flow like the river
This commit is contained in:
commit
013fe673f3
42435 changed files with 5764238 additions and 0 deletions
10
VISUALIZACION/node_modules/ngraph.forcelayout/test/createBody.js
generated
vendored
Executable file
10
VISUALIZACION/node_modules/ngraph.forcelayout/test/createBody.js
generated
vendored
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
var test = require('tap').test;
|
||||
var dimensions = 2;
|
||||
|
||||
test('can debug setters', function (t) {
|
||||
var Body = require('../lib/codeGenerators/generateCreateBody')(dimensions, true);
|
||||
let b = new Body();
|
||||
t.throws(() => b.pos.x = 'foo', /Cannot set non-numbers to x/);
|
||||
t.end();
|
||||
});
|
||||
21
VISUALIZACION/node_modules/ngraph.forcelayout/test/dragForce.js
generated
vendored
Executable file
21
VISUALIZACION/node_modules/ngraph.forcelayout/test/dragForce.js
generated
vendored
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
var test = require('tap').test;
|
||||
var dimensions = 2;
|
||||
var createDragForce = require('../lib/codeGenerators/generateCreateDragForce')(dimensions);
|
||||
var Body = require('../lib/codeGenerators/generateCreateBody')(dimensions);
|
||||
|
||||
test('reduces force value', function (t) {
|
||||
var body = new Body();
|
||||
body.force.x = 1; body.force.y = 1;
|
||||
body.velocity.x = 1; body.velocity.y = 1;
|
||||
|
||||
var dragForce = createDragForce({ dragCoefficient: 0.1 });
|
||||
dragForce.update(body);
|
||||
|
||||
t.ok(body.force.x < 1 && body.force.y < 1, 'Force value is reduced');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Initialized with default value', function (t) {
|
||||
t.throws(() => createDragForce());
|
||||
t.end();
|
||||
});
|
||||
68
VISUALIZACION/node_modules/ngraph.forcelayout/test/eulerIntegrator.js
generated
vendored
Executable file
68
VISUALIZACION/node_modules/ngraph.forcelayout/test/eulerIntegrator.js
generated
vendored
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
var test = require('tap').test;
|
||||
var dimensions = 2;
|
||||
var Body = require('../lib/codeGenerators/generateCreateBody')(dimensions);
|
||||
var integrate = require('../lib/codeGenerators/generateIntegrator')(dimensions);
|
||||
|
||||
test('Body preserves velocity without forces', function (t) {
|
||||
var body = new Body();
|
||||
var timeStep = 1;
|
||||
body.mass = 1; body.velocity.x = 1;
|
||||
|
||||
integrate([body], timeStep);
|
||||
t.equal(body.pos.x, 1, 'Should move by 1 pixel on first iteration');
|
||||
|
||||
timeStep = 2; // let's increase time step:
|
||||
integrate([body], timeStep);
|
||||
t.equal(body.pos.x, 3, 'Should move by 2 pixel on second iteration');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Body gains velocity under force', function (t) {
|
||||
var body = new Body();
|
||||
var timeStep = 1;
|
||||
body.mass = 1; body.force.x = 0.1;
|
||||
|
||||
// F = m * a;
|
||||
// since mass = 1 => F = a = y';
|
||||
integrate([body], timeStep);
|
||||
t.equal(body.velocity.x, 0.1, 'Should increase velocity');
|
||||
|
||||
integrate([body], timeStep);
|
||||
t.equal(body.velocity.x, 0.2, 'Should increase velocity');
|
||||
// floating point math:
|
||||
t.ok(0.29 < body.pos.x && body.pos.x < 0.31, 'Position should be at 0.3 now');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('No bodies yield 0 movement', function (t) {
|
||||
var movement = integrate([], 2);
|
||||
t.equal(movement, 0, 'Nothing has moved');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Body does not move faster than 1px', function (t) {
|
||||
var body = new Body();
|
||||
var timeStep = 1;
|
||||
body.mass = 1; body.force.x = 2;
|
||||
|
||||
integrate([body], timeStep);
|
||||
t.ok(body.velocity.x <= 1, 'Velocity should be within speed limit');
|
||||
|
||||
integrate([body], timeStep);
|
||||
t.ok(body.velocity.x <= 1, 'Velocity should be within speed limit');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Can get total system movement', function (t) {
|
||||
var body = new Body();
|
||||
var timeStep = 1;
|
||||
body.mass = 1; body.velocity.x = 0.2;
|
||||
|
||||
var movement = integrate([body], timeStep);
|
||||
// to improve performance, integrator does not take square root, thus
|
||||
// total movement is .2 * .2 = 0.04;
|
||||
t.ok(0.04 <= movement && movement <= 0.041, 'System should travel by 0.2 pixels');
|
||||
t.end();
|
||||
});
|
||||
78
VISUALIZACION/node_modules/ngraph.forcelayout/test/insert.js
generated
vendored
Executable file
78
VISUALIZACION/node_modules/ngraph.forcelayout/test/insert.js
generated
vendored
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
var test = require('tap').test;
|
||||
|
||||
var dimensions = 2;
|
||||
var createQuadTree = require('../lib/codeGenerators/generateQuadTree')(dimensions);
|
||||
var Body = require('../lib/codeGenerators/generateCreateBody')(dimensions);
|
||||
var random = require('ngraph.random').random(42);
|
||||
|
||||
test('insert and update update forces', function (t) {
|
||||
var tree = createQuadTree({}, random);
|
||||
var body = new Body();
|
||||
var clone = JSON.parse(JSON.stringify(body));
|
||||
|
||||
tree.insertBodies([body]);
|
||||
tree.updateBodyForce(body);
|
||||
t.same(body, clone, 'The body should not be changed - there are no forces acting on it');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can get root', function (t) {
|
||||
var tree = createQuadTree({}, random);
|
||||
var body = new Body();
|
||||
|
||||
tree.insertBodies([body]);
|
||||
var root = tree.getRoot();
|
||||
t.ok(root, 'Root is present');
|
||||
t.equal(root.body, body, 'Body is initialized');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Two bodies repel each other', function (t) {
|
||||
var tree = createQuadTree({}, random);
|
||||
var bodyA = new Body(); bodyA.pos.x = 1; bodyA.pos.y = 0;
|
||||
var bodyB = new Body(); bodyB.pos.x = 2; bodyB.pos.y = 0;
|
||||
|
||||
tree.insertBodies([bodyA, bodyB]);
|
||||
tree.updateBodyForce(bodyA);
|
||||
tree.updateBodyForce(bodyB);
|
||||
// based on our physical model construction forces should be equivalent, with
|
||||
// opposite sign:
|
||||
t.ok(bodyA.force.x + bodyB.force.x === 0, 'Forces should be same, with opposite sign');
|
||||
t.ok(bodyA.force.x !== 0, 'X-force for body A should not be zero');
|
||||
t.ok(bodyB.force.x !== 0, 'X-force for body B should not be zero');
|
||||
// On the other hand, our bodies should not move by Y axis:
|
||||
t.ok(bodyA.force.y === 0, 'Y-force for body A should be zero');
|
||||
t.ok(bodyB.force.y === 0, 'Y-force for body B should be zero');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Can handle two bodies at the same location', function (t) {
|
||||
var tree = createQuadTree({}, random);
|
||||
var bodyA = new Body();
|
||||
var bodyB = new Body();
|
||||
|
||||
tree.insertBodies([bodyA, bodyB]);
|
||||
tree.updateBodyForce(bodyA);
|
||||
tree.updateBodyForce(bodyB);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it does not stuck', function(t) {
|
||||
var count = 60000;
|
||||
var bodies = [];
|
||||
|
||||
for (var i = 0; i < count; ++i) {
|
||||
bodies.push(new Body(Math.random(), Math.random()));
|
||||
}
|
||||
|
||||
var quadTree = createQuadTree({}, random);
|
||||
quadTree.insertBodies(bodies);
|
||||
|
||||
bodies.forEach(function(body) {
|
||||
quadTree.updateBodyForce(body);
|
||||
});
|
||||
t.ok(1);
|
||||
t.end();
|
||||
});
|
||||
463
VISUALIZACION/node_modules/ngraph.forcelayout/test/layout.js
generated
vendored
Executable file
463
VISUALIZACION/node_modules/ngraph.forcelayout/test/layout.js
generated
vendored
Executable file
|
|
@ -0,0 +1,463 @@
|
|||
/* eslint-disable no-shadow */
|
||||
var test = require('tap').test,
|
||||
createGraph = require('ngraph.graph'),
|
||||
createLayout = require('..');
|
||||
|
||||
test('it exposes simulator', function(t) {
|
||||
t.ok(typeof createLayout.simulator === 'function', 'Simulator is exposed');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it returns spring', function(t) {
|
||||
var g = createGraph();
|
||||
var layout = createLayout(g);
|
||||
|
||||
var link = g.addLink(1, 2);
|
||||
|
||||
var springForLink = layout.getSpring(link);
|
||||
var springForLinkId = layout.getSpring(link.id);
|
||||
var springForFromTo = layout.getSpring(1, 2);
|
||||
|
||||
t.ok(springForLink, 'spring is here');
|
||||
t.ok(springForLinkId === springForLink, 'Spring is the same');
|
||||
t.ok(springForFromTo === springForLink, 'Spring is the same');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it returns same position', function(t) {
|
||||
var g = createGraph();
|
||||
var layout = createLayout(g);
|
||||
|
||||
g.addLink(1, 2);
|
||||
|
||||
var firstNodePos = layout.getNodePosition(1);
|
||||
layout.step();
|
||||
t.ok(firstNodePos === layout.getNodePosition(1), 'Position is the same object');
|
||||
layout.step();
|
||||
t.ok(firstNodePos === layout.getNodePosition(1), 'Position is the same object after multiple steps');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it returns body', function(t) {
|
||||
var g = createGraph();
|
||||
var layout = createLayout(g);
|
||||
|
||||
g.addLink(1, 2);
|
||||
|
||||
t.ok(layout.getBody(1), 'node 1 has body');
|
||||
t.ok(layout.getBody(2), 'node 2 has body');
|
||||
t.notOk(layout.getBody(4), 'there is no node 4');
|
||||
|
||||
var body = layout.getBody(1);
|
||||
t.ok(body.pos.x && body.pos.y, 'Body has a position');
|
||||
t.ok(body.mass, 'Body has a mass');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can set node mass', function(t) {
|
||||
var g = createGraph();
|
||||
g.addNode('anvaka');
|
||||
|
||||
var layout = createLayout(g, {
|
||||
nodeMass: function (nodeId) {
|
||||
t.equal(nodeId, 'anvaka', 'correct node is called');
|
||||
return 84; // my mass in kilograms :P
|
||||
}
|
||||
});
|
||||
|
||||
var body = layout.getBody('anvaka');
|
||||
t.equal(body.mass, 84, 'Mass is okay');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('does not tolerate bad input', function (t) {
|
||||
t.throws(missingGraph);
|
||||
t.throws(invalidNodeId);
|
||||
t.end();
|
||||
|
||||
function missingGraph() {
|
||||
// graph is missing:
|
||||
createLayout();
|
||||
}
|
||||
|
||||
function invalidNodeId() {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
|
||||
// we don't have nodes in the graph. This should throw:
|
||||
layout.getNodePosition(1);
|
||||
}
|
||||
});
|
||||
|
||||
test('it fires stable on empty graph', function(t) {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
layout.on('stable', endTest);
|
||||
layout.step();
|
||||
|
||||
function endTest() {
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
test('can add bodies which are standard prototype names', function (t) {
|
||||
var graph = createGraph();
|
||||
graph.addLink('constructor', 'watch');
|
||||
|
||||
var layout = createLayout(graph);
|
||||
layout.step();
|
||||
|
||||
graph.forEachNode(function (node) {
|
||||
var pos = layout.getNodePosition(node.id);
|
||||
t.ok(pos && typeof pos.x === 'number' &&
|
||||
typeof pos.y === 'number', 'Position is defined');
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can step when no links present', function (t) {
|
||||
var graph = createGraph();
|
||||
graph.addNode('constructor');
|
||||
graph.addNode('watch');
|
||||
|
||||
var layout = createLayout(graph);
|
||||
layout.step();
|
||||
|
||||
graph.forEachNode(function (node) {
|
||||
var pos = layout.getNodePosition(node.id);
|
||||
t.ok(pos && typeof pos.x === 'number' &&
|
||||
typeof pos.y === 'number', 'Position is defined');
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('layout initializes nodes positions', function (t) {
|
||||
var graph = createGraph();
|
||||
graph.addLink(1, 2);
|
||||
|
||||
var layout = createLayout(graph);
|
||||
|
||||
// perform one iteration of layout:
|
||||
layout.step();
|
||||
|
||||
graph.forEachNode(function (node) {
|
||||
var pos = layout.getNodePosition(node.id);
|
||||
t.ok(pos && typeof pos.x === 'number' &&
|
||||
typeof pos.y === 'number', 'Position is defined');
|
||||
});
|
||||
|
||||
graph.forEachLink(function (link) {
|
||||
var linkPos = layout.getLinkPosition(link.id);
|
||||
t.ok(linkPos && linkPos.from && linkPos.to, 'Link position is defined');
|
||||
var fromPos = layout.getNodePosition(link.fromId);
|
||||
t.ok(linkPos.from === fromPos, '"From" should be identical to getNodePosition');
|
||||
var toPos = layout.getNodePosition(link.toId);
|
||||
t.ok(linkPos.to === toPos, '"To" should be identical to getNodePosition');
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Layout can set node position', function (t) {
|
||||
var graph = createGraph();
|
||||
graph.addLink(1, 2);
|
||||
|
||||
var layout = createLayout(graph);
|
||||
|
||||
layout.pinNode(graph.getNode(1), true);
|
||||
layout.setNodePosition(1, 42, 42);
|
||||
|
||||
// perform one iteration of layout:
|
||||
layout.step();
|
||||
|
||||
// and make sure node 1 was not moved:
|
||||
var actualPosition = layout.getNodePosition(1);
|
||||
t.equal(actualPosition.x, 42, 'X has not changed');
|
||||
t.equal(actualPosition.y, 42, 'Y has not changed');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Layout updates bounding box when it sets node position', function (t) {
|
||||
var graph = createGraph();
|
||||
graph.addLink(1, 2);
|
||||
|
||||
var layout = createLayout(graph);
|
||||
layout.setNodePosition(1, 42, 42);
|
||||
layout.setNodePosition(2, 40, 40);
|
||||
var rect = layout.getGraphRect();
|
||||
t.ok(rect.max_x <= 42); t.ok(rect.max_y <= 42);
|
||||
t.ok(rect.min_x >= 40); t.ok(rect.min_y >= 40);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('layout initializes links', function (t) {
|
||||
var graph = createGraph();
|
||||
var node1 = graph.addNode(1); node1.position = {x : -1000, y: 0};
|
||||
var node2 = graph.addNode(2); node2.position = {x : 1000, y: 0};
|
||||
|
||||
graph.addLink(1, 2);
|
||||
|
||||
var layout = createLayout(graph);
|
||||
|
||||
// perform one iteration of layout:
|
||||
layout.step();
|
||||
|
||||
// since both nodes are connected by spring and distance is too large between
|
||||
// them, they should start attracting each other
|
||||
var pos1 = layout.getNodePosition(1);
|
||||
var pos2 = layout.getNodePosition(2);
|
||||
|
||||
t.ok(pos1.x > -1000, 'Node 1 moves towards node 2');
|
||||
t.ok(pos2.x < 1000, 'Node 1 moves towards node 2');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('layout respects proposed original position', function (t) {
|
||||
var graph = createGraph();
|
||||
var node = graph.addNode(1);
|
||||
|
||||
var initialPosition = {x: 100, y: 100};
|
||||
node.position = copy(initialPosition);
|
||||
|
||||
var layout = createLayout(graph);
|
||||
layout.step();
|
||||
|
||||
t.same(layout.getNodePosition(node.id), initialPosition, 'original position preserved');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('layout has defined graph rectangle', function (t) {
|
||||
t.test('empty graph', function (t) {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
|
||||
var rect = layout.getGraphRect();
|
||||
var expectedProperties = ['min_x', 'min_y', 'max_x', 'max_y'];
|
||||
t.ok(rect && expectedProperties.reduce(hasProperties, true), 'Values are present before step()');
|
||||
|
||||
layout.step();
|
||||
|
||||
t.ok(rect && expectedProperties.reduce(hasProperties, true), 'Values are present after step()');
|
||||
t.end();
|
||||
|
||||
function hasProperties(result, key) {
|
||||
return result && typeof rect[key] === 'number';
|
||||
}
|
||||
});
|
||||
|
||||
t.test('two nodes', function (t) {
|
||||
var graph = createGraph();
|
||||
graph.addLink(1, 2);
|
||||
var layout = createLayout(graph);
|
||||
layout.step();
|
||||
|
||||
var rect = layout.getGraphRect();
|
||||
t.ok(!rectangleIsEmpty(rect), 'Graph rectangle is not empty');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it does not move pinned nodes', function (t) {
|
||||
t.test('respects original data.isPinned attribute', function (t) {
|
||||
var graph = createGraph();
|
||||
var testNode = graph.addNode(1, { isPinned: true });
|
||||
var layout = createLayout(graph);
|
||||
t.ok(layout.isNodePinned(testNode), 'Node is pinned');
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('respects node.isPinned attribute', function (t) {
|
||||
var graph = createGraph();
|
||||
var testNode = graph.addNode(1);
|
||||
|
||||
// this was possible in vivagraph. Port it over to ngraph:
|
||||
testNode.isPinned = true;
|
||||
var layout = createLayout(graph);
|
||||
t.ok(layout.isNodePinned(testNode), 'Node is pinned');
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('can pin nodes after graph is initialized', function (t) {
|
||||
var graph = createGraph();
|
||||
graph.addLink(1, 2);
|
||||
|
||||
var layout = createLayout(graph);
|
||||
layout.pinNode(graph.getNode(1), true);
|
||||
layout.step();
|
||||
var pos1 = copy(layout.getNodePosition(1));
|
||||
var pos2 = copy(layout.getNodePosition(2));
|
||||
|
||||
// make one more step and make sure node 1 did not move:
|
||||
layout.step();
|
||||
|
||||
t.ok(!positionChanged(pos1, layout.getNodePosition(1)), 'Node 1 was not moved');
|
||||
t.ok(positionChanged(pos2, layout.getNodePosition(2)), 'Node 2 has moved');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it listens to graph events', function (t) {
|
||||
// we first initialize with empty graph:
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
|
||||
// and only then add nodes:
|
||||
graph.addLink(1, 2);
|
||||
|
||||
// make two iterations
|
||||
layout.step();
|
||||
var pos1 = copy(layout.getNodePosition(1));
|
||||
var pos2 = copy(layout.getNodePosition(2));
|
||||
|
||||
layout.step();
|
||||
|
||||
t.ok(positionChanged(pos1, layout.getNodePosition(1)), 'Node 1 has moved');
|
||||
t.ok(positionChanged(pos2, layout.getNodePosition(2)), 'Node 2 has moved');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('can stop listen to events', function (t) {
|
||||
// we first initialize with empty graph:
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
layout.dispose();
|
||||
|
||||
graph.addLink(1, 2);
|
||||
layout.step();
|
||||
t.ok(layout.simulator.bodies.length === 0, 'No bodies in the simulator');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('physics simulator', function (t) {
|
||||
t.test('has default simulator', function (t) {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
|
||||
t.ok(layout.simulator, 'physics simulator is present');
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('can override default settings', function (t) {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph, {
|
||||
theta: 1.5
|
||||
});
|
||||
t.equal(layout.simulator.theta(), 1.5, 'Simulator settings are overridden');
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it removes removed nodes', function (t) {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
graph.addLink(1, 2);
|
||||
|
||||
layout.step();
|
||||
graph.clear();
|
||||
|
||||
// since we removed everything from graph rect should be empty:
|
||||
var rect = layout.getGraphRect();
|
||||
|
||||
t.ok(rectangleIsEmpty(rect), 'Graph rect is empty');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can iterate over bodies', function(t) {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
graph.addLink(1, 2);
|
||||
var calledCount = 0;
|
||||
|
||||
layout.forEachBody(function(body, bodyId) {
|
||||
t.ok(body.pos, bodyId + ' has position');
|
||||
t.ok(graph.getNode(bodyId), bodyId + ' matches a graph node');
|
||||
calledCount += 1;
|
||||
});
|
||||
|
||||
t.equal(calledCount, 2, 'Both bodies are visited');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it handles large graphs', function (t) {
|
||||
var graph = createGraph();
|
||||
var layout = createLayout(graph);
|
||||
|
||||
var count = 60000;
|
||||
|
||||
var i = count;
|
||||
while (i--) {
|
||||
graph.addNode(i);
|
||||
}
|
||||
|
||||
// link each node to 2 other random nodes
|
||||
i = count;
|
||||
while (i--) {
|
||||
graph.addLink(i, Math.ceil(Math.random() * count));
|
||||
graph.addLink(i, Math.ceil(Math.random() * count));
|
||||
}
|
||||
|
||||
layout.step();
|
||||
|
||||
t.ok(layout.simulator.bodies.length !== 0, 'Bodies in the simulator');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can create high dimensional layout', function(t) {
|
||||
var graph = createGraph();
|
||||
graph.addLink(1, 2);
|
||||
var layout = createLayout(graph, {dimensions: 6});
|
||||
layout.step();
|
||||
|
||||
var pos = layout.getNodePosition(1);
|
||||
t.ok(pos.x !== undefined, 'Position has x');
|
||||
t.ok(pos.y !== undefined, 'Position has y');
|
||||
t.ok(pos.z !== undefined, 'Position has z');
|
||||
t.ok(pos.c4 !== undefined, 'Position has c4');
|
||||
t.ok(pos.c5 !== undefined, 'Position has c5');
|
||||
t.ok(pos.c6 !== undefined, 'Position has c6');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can layout two graphs independently', function(t) {
|
||||
var graph1 = createGraph();
|
||||
var graph2 = createGraph();
|
||||
var layout1 = createLayout(graph1);
|
||||
var layout2 = createLayout(graph2);
|
||||
graph1.addLink(1, 2);
|
||||
graph2.addLink(1, 2);
|
||||
layout1.step();
|
||||
layout2.step();
|
||||
layout2.step();
|
||||
t.ok(layout1.getNodePosition(1).x !== layout2.getNodePosition(1).x, 'Positions are different');
|
||||
t.end();
|
||||
});
|
||||
|
||||
function positionChanged(pos1, pos2) {
|
||||
return (pos1.x !== pos2.x) || (pos1.y !== pos2.y);
|
||||
}
|
||||
|
||||
function copy(obj) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
function rectangleIsEmpty(rect) {
|
||||
return rect.min_x === 0 && rect.min_y === 0 && rect.max_x === 0 && rect.max_y === 0;
|
||||
}
|
||||
100
VISUALIZACION/node_modules/ngraph.forcelayout/test/primitives.js
generated
vendored
Executable file
100
VISUALIZACION/node_modules/ngraph.forcelayout/test/primitives.js
generated
vendored
Executable file
|
|
@ -0,0 +1,100 @@
|
|||
var test = require('tap').test;
|
||||
var {generateCreateBodyFunctionBody} = require('../lib/codeGenerators/generateCreateBody');
|
||||
|
||||
function primitive(dimension) {
|
||||
let res = (new Function(generateCreateBodyFunctionBody(dimension)))();
|
||||
return res;
|
||||
}
|
||||
|
||||
test('Body has properties force, pos and mass', function(t) {
|
||||
debugger;
|
||||
var body = new (primitive(2).Body)();
|
||||
t.ok(body.force, 'Force attribute is missing on body');
|
||||
t.ok(body.pos, 'Pos attribute is missing on body');
|
||||
t.ok(body.velocity, 'Velocity attribute is missing on body');
|
||||
t.ok(typeof body.mass === 'number' && body.mass !== 0, 'Body should have a mass');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Vector has x and y', function(t) {
|
||||
var vector = new (primitive(2).Vector)();
|
||||
t.ok(typeof vector.x === 'number', 'Vector has x coordinates');
|
||||
t.ok(typeof vector.y === 'number', 'Vector has y coordinates');
|
||||
|
||||
var initialized = new (primitive(2).Vector)(1, 2);
|
||||
t.equal(initialized.x, 1, 'Vector initialized properly');
|
||||
t.equal(initialized.y, 2, 'Vector initialized properly');
|
||||
|
||||
var badInput = new (primitive(2).Vector)('hello world');
|
||||
t.equal(badInput.x, 0, 'Vector should be resilient to bed input');
|
||||
t.equal(badInput.y, 0, 'Vector should be resilient to bed input');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Body3d has properties force, pos and mass', function(t) {
|
||||
var body = new (primitive(3).Body)();
|
||||
t.ok(body.force, 'Force attribute is missing on body');
|
||||
t.ok(body.pos, 'Pos attribute is missing on body');
|
||||
t.ok(body.velocity, 'Velocity attribute is missing on body');
|
||||
t.ok(typeof body.mass === 'number' && body.mass !== 0, 'Body should have a mass');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Vector3d has x and y and z', function(t) {
|
||||
var vector = new (primitive(3).Vector)();
|
||||
t.ok(typeof vector.x === 'number', 'Vector has x coordinates');
|
||||
t.ok(typeof vector.y === 'number', 'Vector has y coordinates');
|
||||
t.ok(typeof vector.z === 'number', 'Vector has z coordinates');
|
||||
|
||||
var initialized = new (primitive(3).Vector)(1, 2, 3);
|
||||
t.equal(initialized.x, 1, 'Vector initialized properly');
|
||||
t.equal(initialized.y, 2, 'Vector initialized properly');
|
||||
t.equal(initialized.z, 3, 'Vector initialized properly');
|
||||
|
||||
var badInput = new (primitive(3).Vector)('hello world');
|
||||
t.equal(badInput.x, 0, 'Vector should be resilient to bed input');
|
||||
t.equal(badInput.y, 0, 'Vector should be resilient to bed input');
|
||||
t.equal(badInput.z, 0, 'Vector should be resilient to bed input');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('reset vector', function(t) {
|
||||
var v3 = new (primitive(3).Vector)(1, 2, 3);
|
||||
v3.reset();
|
||||
t.equal(v3.x, 0, 'Reset to 0');
|
||||
t.equal(v3.y, 0, 'Reset to 0');
|
||||
t.equal(v3.z, 0, 'Reset to 0');
|
||||
var v2 = new (primitive(2).Vector)(1, 2);
|
||||
v2.reset();
|
||||
t.equal(v2.x, 0, 'Reset to 0');
|
||||
t.equal(v2.y, 0, 'Reset to 0');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('vector can use copy constructor', function(t) {
|
||||
var a = new (primitive(3).Vector)(1, 2, 3);
|
||||
var b = new (primitive(3).Vector)(a);
|
||||
t.equal(b.x, a.x, 'Value copied');
|
||||
t.equal(b.y, a.y, 'Value copied');
|
||||
t.equal(b.z, a.z, 'Value copied');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Body3d can set position', function(t) {
|
||||
var body = new (primitive(3).Body)();
|
||||
body.setPosition(10, 11, 12);
|
||||
t.equal(body.pos.x, 10, 'x is correct');
|
||||
t.equal(body.pos.y, 11, 'y is correct');
|
||||
t.equal(body.pos.z, 12, 'z is correct');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Body can set position', function(t) {
|
||||
var body = new (primitive(2).Body)();
|
||||
body.setPosition(10, 11);
|
||||
t.equal(body.pos.x, 10, 'x is correct');
|
||||
t.equal(body.pos.y, 11, 'y is correct');
|
||||
|
||||
t.end();
|
||||
});
|
||||
336
VISUALIZACION/node_modules/ngraph.forcelayout/test/simulator.js
generated
vendored
Executable file
336
VISUALIZACION/node_modules/ngraph.forcelayout/test/simulator.js
generated
vendored
Executable file
|
|
@ -0,0 +1,336 @@
|
|||
/* eslint-disable no-shadow */
|
||||
var test = require('tap').test;
|
||||
var dimensions = 2;
|
||||
var Body = require('../lib/codeGenerators/generateCreateBody')(dimensions);
|
||||
var createSimulator = require('../lib/createPhysicsSimulator');
|
||||
|
||||
test('Can step without bodies', function (t) {
|
||||
var simulator = createSimulator();
|
||||
t.equal(simulator.bodies.length, 0, 'There should be no bodies');
|
||||
t.equal(simulator.springs.length, 0, 'There should be no springs');
|
||||
simulator.step();
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it has settings exposed', function(t) {
|
||||
var mySettings = { };
|
||||
var simulator = createSimulator(mySettings);
|
||||
t.ok(mySettings === simulator.settings, 'settings are exposed');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it gives amount of total movement', function(t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(-10, 0);
|
||||
var body2 = new Body(10, 0);
|
||||
simulator.addBody(body1);
|
||||
simulator.addBody(body2);
|
||||
simulator.step();
|
||||
|
||||
var totalMoved = simulator.getTotalMovement();
|
||||
t.ok(!isNaN(totalMoved), 'Amount of total movement is returned');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can add a body at given position', function(t) {
|
||||
var simulator = createSimulator();
|
||||
var pos1 = {x: -10, y: 0};
|
||||
var pos2 = {x: 10, y: 0};
|
||||
simulator.addBodyAt(pos1);
|
||||
simulator.addBodyAt(pos2);
|
||||
|
||||
t.equal(simulator.bodies.length, 2, 'All bodies are added');
|
||||
var body1 = simulator.bodies[0];
|
||||
|
||||
t.equal(body1.pos.x, -10, 'X is there');
|
||||
t.equal(body1.pos.y, 0, 'Y is there');
|
||||
|
||||
var body2 = simulator.bodies[1];
|
||||
t.equal(body2.pos.x, 10, 'X is there');
|
||||
t.equal(body2.pos.y, 0, 'Y is there');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Does not update position of one body', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body = new Body(0, 0);
|
||||
simulator.addBody(body);
|
||||
|
||||
simulator.step(1);
|
||||
t.equal(simulator.bodies.length, 1, 'Number of bodies is 1');
|
||||
t.equal(simulator.springs.length, 0, 'Number of springs is 0');
|
||||
t.equal(simulator.bodies[0], body, 'Body points to actual object');
|
||||
t.equal(body.pos.x, 0, 'X is not changed');
|
||||
t.equal(body.pos.y, 0, 'Y is not changed');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('throws on no body or no pos', t => {
|
||||
var simulator = createSimulator();
|
||||
t.throws(() => simulator.addBody(), /Body is required/);
|
||||
t.throws(() => simulator.addBodyAt(), /Body position is required/);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('throws on no spring', t => {
|
||||
var simulator = createSimulator();
|
||||
t.throws(() => simulator.addSpring(), /Cannot add null spring to force simulator/);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Can add and remove forces', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var testForce = function () {};
|
||||
simulator.addForce('foo', testForce);
|
||||
t.equal(simulator.getForces().get('foo'), testForce);
|
||||
|
||||
simulator.removeForce('foo');
|
||||
t.equal(simulator.getForces().get('foo'), undefined);
|
||||
|
||||
simulator.removeForce('foo');
|
||||
// should still be good
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Can configure forces', function (t) {
|
||||
t.test('Gravity', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(0, 0);
|
||||
var body2 = new Body(1, 0);
|
||||
|
||||
simulator.addBody(body1);
|
||||
simulator.addBody(body2);
|
||||
|
||||
simulator.step();
|
||||
// by default gravity is negative, bodies should repel each other:
|
||||
var x1 = body1.pos.x;
|
||||
var x2 = body2.pos.x;
|
||||
t.ok(x1 < 0, 'Body 1 moves away from body 2');
|
||||
t.ok(x2 > 1, 'Body 2 moves away from body 1');
|
||||
|
||||
// now reverse gravity, and bodies should attract each other:
|
||||
simulator.gravity(100);
|
||||
simulator.step();
|
||||
t.ok(body1.pos.x > x1, 'Body 1 moved towards body 2');
|
||||
t.ok(body2.pos.x < x2, 'Body 2 moved towards body 1');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('Drag', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(0, 0);
|
||||
body1.velocity.x = -1; // give it small impulse
|
||||
simulator.addBody(body1);
|
||||
|
||||
simulator.step();
|
||||
|
||||
var x1 = body1.velocity.x;
|
||||
// by default drag force will slow down entire system:
|
||||
t.ok(x1 > -1, 'Body 1 moves at reduced speed');
|
||||
|
||||
// Restore original velocity, but now set drag force to 0
|
||||
body1.velocity.x = -1;
|
||||
simulator.dragCoefficient(0);
|
||||
simulator.step();
|
||||
t.ok(body1.velocity.x === -1, 'Velocity should remain unchanged');
|
||||
t.end();
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Can remove bodies', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body = new Body(0, 0);
|
||||
simulator.addBody(body);
|
||||
t.equal(simulator.bodies.length, 1, 'Number of bodies is 1');
|
||||
var result = simulator.removeBody(body);
|
||||
t.equal(result, true, 'body successfully removed');
|
||||
t.equal(simulator.bodies.length, 0, 'Number of bodies is 0');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Updates position for two bodies', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(-1, 0);
|
||||
var body2 = new Body(1, 0);
|
||||
simulator.addBody(body1);
|
||||
simulator.addBody(body2);
|
||||
|
||||
simulator.step();
|
||||
t.equal(simulator.bodies.length, 2, 'Number of bodies is 2');
|
||||
t.ok(body1.pos.x !== 0, 'Body1.X has changed');
|
||||
t.ok(body2.pos.x !== 0, 'Body2.X has changed');
|
||||
|
||||
t.equal(body1.pos.y, 0, 'Body1.Y has not changed');
|
||||
t.equal(body2.pos.y, 0, 'Body2.Y has not changed');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('add spring should not add bodies', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(-1, 0);
|
||||
var body2 = new Body(1, 0);
|
||||
|
||||
simulator.addSpring(body1, body2, 10);
|
||||
|
||||
t.equal(simulator.bodies.length, 0, 'Should not add two bodies');
|
||||
t.equal(simulator.bodies.length, 0, 'Should not add two bodies');
|
||||
t.equal(simulator.springs.length, 1, 'Should have a spring');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Spring affects bodies positions', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(-10, 0);
|
||||
var body2 = new Body(10, 0);
|
||||
simulator.addBody(body1);
|
||||
simulator.addBody(body2);
|
||||
// If you take this out, bodies will repel each other:
|
||||
simulator.addSpring(body1, body2, 1);
|
||||
|
||||
simulator.step();
|
||||
|
||||
t.ok(body1.pos.x > -10, 'Body 1 should move towards body 2');
|
||||
t.ok(body2.pos.x < 10, 'Body 2 should move towards body 1');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Can remove springs', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(-10, 0);
|
||||
var body2 = new Body(10, 0);
|
||||
simulator.addBody(body1);
|
||||
simulator.addBody(body2);
|
||||
var spring = simulator.addSpring(body1, body2, 1);
|
||||
simulator.removeSpring(spring);
|
||||
|
||||
simulator.step();
|
||||
|
||||
t.ok(body1.pos.x < -10, 'Body 1 should move away from body 2');
|
||||
t.ok(body2.pos.x > 10, 'Body 2 should move away from body 1');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Get bounding box', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(0, 0);
|
||||
var body2 = new Body(10, 10);
|
||||
simulator.addBody(body1);
|
||||
simulator.addBody(body2);
|
||||
simulator.step(); // this will move bodies farther away
|
||||
var bbox = simulator.getBBox();
|
||||
t.ok(bbox.min_x <= 0, 'Left is 0');
|
||||
t.ok(bbox.min_y <= 0, 'Top is 0');
|
||||
t.ok(bbox.max_x >= 10, 'right is 10');
|
||||
t.ok(bbox.max_y >= 10, 'bottom is 10');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it updates bounding box', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var body1 = new Body(0, 0);
|
||||
var body2 = new Body(10, 10);
|
||||
simulator.addBody(body1);
|
||||
simulator.addBody(body2);
|
||||
var bbox = simulator.getBBox();
|
||||
|
||||
t.ok(bbox.min_x === 0, 'Left is 0');
|
||||
t.ok(bbox.min_y === 0, 'Top is 0');
|
||||
t.ok(bbox.max_x === 10, 'right is 10');
|
||||
t.ok(bbox.max_y === 10, 'bottom is 10');
|
||||
|
||||
body1.setPosition(15, 15);
|
||||
simulator.invalidateBBox();
|
||||
bbox = simulator.getBBox();
|
||||
|
||||
t.ok(bbox.min_x === 10, 'Left is 10');
|
||||
t.ok(bbox.min_y === 10, 'Top is 10');
|
||||
t.ok(bbox.max_x === 15, 'right is 15');
|
||||
t.ok(bbox.max_y === 15, 'bottom is 15');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Get best position', function (t) {
|
||||
t.test('can get with empty simulator', function (t) {
|
||||
var simulator = createSimulator();
|
||||
var empty = simulator.getBestNewBodyPosition([]);
|
||||
t.ok(typeof empty.x === 'number', 'Has X');
|
||||
t.ok(typeof empty.y === 'number', 'Has Y');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can change settings', function(t) {
|
||||
var simulator = createSimulator();
|
||||
|
||||
var currentTheta = simulator.theta();
|
||||
t.ok(typeof currentTheta === 'number', 'theta is here');
|
||||
simulator.theta(1.2);
|
||||
t.equal(simulator.theta(), 1.2, 'theta is changed');
|
||||
|
||||
var currentSpringCoefficient = simulator.springCoefficient();
|
||||
t.ok(typeof currentSpringCoefficient === 'number', 'springCoefficient is here');
|
||||
simulator.springCoefficient(0.8);
|
||||
t.equal(simulator.springCoefficient(), 0.8, 'springCoefficient is changed');
|
||||
|
||||
var gravity = simulator.gravity();
|
||||
t.ok(typeof gravity === 'number', 'gravity is here');
|
||||
simulator.gravity(-0.8);
|
||||
t.equal(simulator.gravity(), -0.8, 'gravity is changed');
|
||||
|
||||
var springLength = simulator.springLength();
|
||||
t.ok(typeof springLength === 'number', 'springLength is here');
|
||||
simulator.springLength(80);
|
||||
t.equal(simulator.springLength(), 80, 'springLength is changed');
|
||||
|
||||
var dragCoefficient = simulator.dragCoefficient();
|
||||
t.ok(typeof dragCoefficient === 'number', 'dragCoefficient is here');
|
||||
simulator.dragCoefficient(0.8);
|
||||
t.equal(simulator.dragCoefficient(), 0.8, 'dragCoefficient is changed');
|
||||
|
||||
var timeStep = simulator.timeStep();
|
||||
t.ok(typeof timeStep === 'number', 'timeStep is here');
|
||||
simulator.timeStep(8);
|
||||
t.equal(simulator.timeStep(), 8, 'timeStep is changed');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can augment string setter values', function (t) {
|
||||
var simulator = createSimulator({
|
||||
name: 'John'
|
||||
});
|
||||
|
||||
simulator.name('Alisa');
|
||||
t.equal(simulator.name(), 'Alisa', 'name is Alisa');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it ignores body that does not exist', function(t) {
|
||||
var simulator = createSimulator();
|
||||
var body = new Body(0, 0);
|
||||
simulator.addBody(body);
|
||||
simulator.removeBody({});
|
||||
t.equal(simulator.bodies.length, 1, 'Should ignore body that does not exist');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it throws on springCoeff', function (t) {
|
||||
t.throws(function () {
|
||||
createSimulator({springCoeff: 1});
|
||||
}, 'springCoeff was renamed to springCoefficient');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it throws on dragCoeff', function (t) {
|
||||
t.throws(function () {
|
||||
createSimulator({dragCoeff: 1});
|
||||
}, 'dragCoeff was renamed to dragCoefficient');
|
||||
t.end();
|
||||
});
|
||||
63
VISUALIZACION/node_modules/ngraph.forcelayout/test/springForce.js
generated
vendored
Executable file
63
VISUALIZACION/node_modules/ngraph.forcelayout/test/springForce.js
generated
vendored
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
/* eslint-disable no-shadow */
|
||||
var test = require('tap').test;
|
||||
|
||||
var dimensions = 2;
|
||||
var createSpringForce = require('../lib/codeGenerators/generateCreateSpringForce')(dimensions);
|
||||
var Body = require('../lib/codeGenerators/generateCreateBody')(dimensions);
|
||||
var Spring = require('../lib/spring');
|
||||
var random = require('ngraph.random')(42);
|
||||
|
||||
test('Initialized with default value', function (t) {
|
||||
t.throws(() => createSpringForce());
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
||||
test('Should bump bodies at same position', function (t) {
|
||||
var body1 = new Body(0, 0);
|
||||
var body2 = new Body(0, 0);
|
||||
// length between two bodies is 2, while ideal length is 1. Each body
|
||||
// should start moving towards each other after force update
|
||||
var idealLength = 1;
|
||||
var spring = new Spring(body1, body2, idealLength);
|
||||
var springForce = createSpringForce({springCoefficient: 0.1, springLength: 1}, random);
|
||||
springForce.update(spring);
|
||||
|
||||
t.ok(body1.force.x > 0, 'Body 1 should go right');
|
||||
t.ok(body2.force.x < 0, 'Body 2 should go left');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Check spring force direction', function (t) {
|
||||
var springForce = createSpringForce({springCoefficient: 0.1, springLength: 1});
|
||||
|
||||
t.test('Should contract two bodies when ideal length is smaller than actual', function (t) {
|
||||
var body1 = new Body(-1, 0);
|
||||
var body2 = new Body(+1, 0);
|
||||
// length between two bodies is 2, while ideal length is 1. Each body
|
||||
// should start moving towards each other after force update
|
||||
var idealLength = 1;
|
||||
var spring = new Spring(body1, body2, idealLength);
|
||||
springForce.update(spring);
|
||||
|
||||
t.ok(body1.force.x > 0, 'Body 1 should go right');
|
||||
t.ok(body2.force.x < 0, 'Body 2 should go left');
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('Should repel two bodies when ideal length is larger than actual', function (t) {
|
||||
var body1 = new Body(-1, 0);
|
||||
var body2 = new Body(+1, 0);
|
||||
// length between two bodies is 2, while ideal length is 1. Each body
|
||||
// should start moving towards each other after force update
|
||||
var idealLength = 3;
|
||||
var spring = new Spring(body1, body2, idealLength);
|
||||
springForce.update(spring);
|
||||
|
||||
t.ok(body1.force.x < 0, 'Body 1 should go left');
|
||||
t.ok(body2.force.x > 0, 'Body 2 should go right');
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue