newton
Version:
A playful, particle-based physics engine designed from the ground up for JavaScript.
522 lines (411 loc) • 12.8 kB
JavaScript
var assert = require('chai').assert;
var Vector = require('../lib/vector.js');
describe('Vector', function() {
describe('constructor', function() {
it('should force instantiation', function() {
var v = Vector();
assert.instanceOf(v, Vector);
});
it('should assume 0, 0 as defaults', function() {
var v = Vector();
assert.equal(v.x, 0);
assert.equal(v.y, 0);
});
it('should accept a coord', function() {
var v = Vector(1, 2);
assert.equal(v.x, 1);
assert.equal(v.y, 2);
});
});
describe('pooling', function() {
it('should be able to acquire and release', function() {
assert.equal(Vector.pool(), 0);
var v = Vector.claim();
assert.instanceOf(v, Vector);
assert.equal(Vector.pool(), 0);
v.free();
assert.equal(Vector.pool(), 1);
});
it('should provide different vectors', function() {
var v1 = Vector.claim();
var v2 = Vector.claim();
assert.notEqual(v1, v2);
v1.free();
v2.free();
});
it('should reuse objects', function() {
var v1 = Vector.claim();
v1.free();
var v2 = Vector.claim();
assert.strictEqual(v1, v2);
v2.free();
});
it('should automatically expand when pool is empty', function() {
Vector.pool(1);
var v1 = Vector.claim();
var v2 = Vector.claim();
assert.instanceOf(v1, Vector);
assert.instanceOf(v2, Vector);
v1.free();
v2.free();
});
it('should claim and copy with pool()', function() {
Vector.pool(0);
assert.equal(Vector.pool(), 0, 'pool should start empty');
var v1 = Vector(3, 4);
var v2 = v1.pool();
assert.notEqual(v1, v2, 'pool() instance should be separate');
assert.equal(v2.x, v1.x, 'pool()d values should be copied');
assert.equal(Vector.pool(), 0, 'pool should be empty');
v2.free();
assert.equal(Vector.pool(), 1, 'free() should add one to pool');
});
});
/*
describe('scratch', function() {
it('should be a single instance', function() {
assert.instanceOf(Vector.scratch, Vector);
});
});
*/
describe('clone()', function() {
var v1 = Vector(2, 3);
var v2 = v1.clone();
it('should return a Vector', function() {
assert.instanceOf(v2, Vector);
});
it('should copy the data from the cloned Vector', function() {
assert.equal(v1.x, v2.x);
assert.equal(v1.y, v2.y);
});
it('should not share an object reference', function() {
assert.notEqual(v1, v2);
});
});
describe('copy()', function() {
var v1 = Vector(3, 4);
var v2 = Vector().copy(v1);
it('should return a Vector', function() {
assert.instanceOf(v2, Vector);
});
it('should copy the coordinates', function() {
assert.equal(v1.x, v2.x);
assert.equal(v1.y, v2.y);
});
it('should not share an object reference', function() {
assert.notEqual(v1, v2);
});
});
describe('equals()', function() {
before(function() {
this.a = Vector(1, 2);
this.b = Vector(1, 3);
this.c = Vector(4, 2);
this.d = Vector(1, 2);
});
it('should fail with different y values', function() {
assert.ok(!this.a.equals(this.b));
});
it('should fail with different x values', function() {
assert.ok(!this.a.equals(this.c));
});
it('should succeed with matching x and y', function() {
assert.ok(this.a.equals(this.d));
});
});
describe('zero()', function() {
it('should zero out a vector', function() {
var v = Vector().zero();
assert.equal(v.x, 0);
assert.equal(v.y, 0);
});
});
/*
describe('set()', function() {
it('should set x and y', function() {
var v = Vector().set(1, 2);
assert.equal(v.x, 1);
assert.equal(v.y, 2);
});
});
*/
describe('add()', function() {
var v = Vector(1, 2);
var v1 = v.add(Vector(3, 4));
it('should add components', function() {
assert.equal(v1.x, 4);
assert.equal(v1.y, 6);
});
it('should add in-place', function() {
assert.equal(v1, v);
});
});
/*
describe('addXY()', function() {
var v = Vector(1, 2);
var v1 = v.addXY(3, 4);
it('should add components', function() {
assert.equal(v1.x, 4);
assert.equal(v1.y, 6);
});
it('should add in-place', function() {
assert.equal(v1, v);
});
});
*/
describe('sub()', function() {
var v = Vector(1, 2);
var v1 = v.sub(Vector(3, 4));
it('should subtract components', function() {
assert.equal(v1.x, -2);
assert.equal(v1.y, -2);
});
it('should subtract in-place', function() {
assert.equal(v1, v);
});
it('should be able to subtract zero', function() {
var pivot = Vector(5, -5);
var v = Vector(0, 0).sub(pivot);
assert.equal(v.x, -5);
assert.equal(v.y, 5);
});
});
/*
describe('subXY()', function() {
var v = Vector(1, 2);
var v1 = v.subXY(3, 4);
it('should subtract components in-place', function() {
assert.equal(v1.x, -2);
assert.equal(v1.y, -2);
assert.equal(v1, v);
});
it('should subtract in-place', function() {
assert.equal(v1, v);
});
});
describe('merge()', function() {
var pos3 = Vector(3, 3);
var neg3 = Vector(-3, -3);
var mixed3 = Vector(3, -3);
it('should accept only larger positive values', function() {
var v1 = Vector(1, 5).merge(pos3);
var v2 = Vector(-1, 5).merge(mixed3);
assert.equal(v1.x, 3, 'v1.x');
assert.equal(v1.y, 5, 'v1.y');
assert.equal(v2.x, -1, 'v2.x');
assert.equal(v2.y, 5, 'v2.y');
});
it('should accept only smaller negative values', function() {
var v1 = Vector(-1, -5).merge(neg3);
var v2 = Vector(1, -5).merge(mixed3)
assert.equal(v1.x, -3);
assert.equal(v1.y, -5);
assert.equal(v2.x, 3);
assert.equal(v2.y, -5);
});
it('should accept any values on zero', function() {
var v1 = Vector(0, 0).merge(pos3);
var v2 = Vector(0, 0).merge(neg3);
assert.equal(v1.x, 3, 'v1.x');
assert.equal(v1.y, 3, 'v1.y');
assert.equal(v2.x, -3, 'v2.x');
assert.equal(v2.y, -3, 'v2.y');
});
});
describe('mult()', function() {
var v = Vector(1, 2);
var v1 = v.mult(Vector(2, 3));
it('should multiply components', function() {
assert.equal(v1.x, 2);
assert.equal(v1.y, 6);
});
it('should multiply in-place', function() {
assert.equal(v1, v);
});
});
*/
describe('scale()', function() {
var v = Vector(1, 2);
var v1 = v.scale(3);
it('should scale components', function() {
assert.equal(v1.x, 3);
assert.equal(v1.y, 6);
});
it('should scale in-place', function() {
assert.equal(v1, v);
});
});
/*
describe('div()', function() {
var v = Vector(1, 2);
var v1 = v.div(Vector(2, 8));
it('should divide components', function() {
assert.equal(v1.x, 0.5);
assert.equal(v1.y, 0.25);
});
it('should divide in-place', function() {
assert.equal(v1, v);
});
});
describe('reverse()', function() {
var v = Vector(1, 2);
var v1 = v.reverse();
it('should reverse components', function() {
assert.equal(v1.x, -1);
assert.equal(v1.y, -2);
});
it('should reverse in-place', function() {
assert.equal(v1, v);
});
});
describe('unit()', function() {
var v = Vector(3, 4);
var v1 = v.unit();
it('should convert to a unit vector', function() {
assert.closeTo(v1.x, 0.6, 0.001);
assert.closeTo(v1.y, 0.8, 0.001);
});
it('should modify in-place', function() {
assert.equal(v1, v);
});
});
describe('turnRight()', function() {
var v = Vector(1, 2);
var v1 = v.turnRight();
it('should turn right', function() {
assert.equal(v1.x, -2);
assert.equal(v1.y, 1);
});
it('should modify in-place', function() {
assert.equal(v1, v);
});
});
describe('turnLeft()', function() {
var v = Vector(1, 2);
var v1 = v.turnLeft();
it('should turn left', function() {
assert.equal(v1.x, 2);
assert.equal(v1.y, -1);
});
it('should modify in-place', function() {
assert.equal(v1, v);
});
});
*/
describe('rotate()', function() {
it('should return the same values with a zero rotation', function() {
var v = Vector(1, 2).rotate(0);
assert.equal(v.x, 1);
assert.equal(v.y, 2);
});
it('should be able to rotate counter-clockwise', function() {
var v = Vector(0, 10).rotate(Math.PI * 0.25);
assert.closeTo(v.x, 7.071067811865475, 0.0001, 'x');
assert.closeTo(v.y, 7.071067811865475, 0.0001, 'y');
});
it('should be able to rotate across the 0-boundary', function() {
var v = Vector(10, -1).rotate(-Math.PI * 0.25);
assert.closeTo(v.x, 7.778174593052023, 0.0001);
assert.closeTo(v.y, 6.363961030678927, 0.0001);
});
it('should modify in-place', function() {
var v1 = Vector(1, 2);
var v2 = v1.rotate(Math.PI);
assert.equal(v1, v2);
});
it('should go from -5,5 to 5,5 with a positive rotation', function() {
var v = Vector(-5, 5).rotate(Math.PI * 0.5);
assert.equal(v.x, 5, 'x should equal 5');
assert.equal(v.y, 5, 'y should equal 5');
});
});
/*
describe('rotateAbout()', function() {
it('should be able to rotate about the origin', function() {
var pivot = Vector(0, 0);
var v = Vector(10, 7).rotateAbout(pivot, Math.PI);
assert.closeTo(v.x, -10, 0.0001);
assert.closeTo(v.y, -7, 0.0001);
});
it('should be able to rotate about an offset pivot', function() {
var pivot = Vector(5, -5);
var v = Vector(0, 0).rotateAbout(pivot, Math.PI * 0.5);
assert.closeTo(v.x, 10, 0.0001);
assert.closeTo(v.y, 0, 0.0001);
});
});
describe('getDot()', function() {
it('should return the dot product', function() {
var v1 = Vector(-6, 8);
var v2 = Vector(5, 12);
assert.equal(v1.getDot(v2), 66);
});
});
describe('getCross()', function() {
it('should return the cross product', function() {
var v1 = Vector(1, 2);
var v2 = Vector(3, 4);
assert.equal(v1.getCross(v2), 10);
});
});
*/
describe('getLength()', function() {
it('should give total length', function() {
var len = Vector(3, 4).getLength();
assert.equal(len, 5);
});
});
/*
describe('getLength2()', function() {
it('should give squared length', function() {
var len = Vector(3, 4).getLength2();
assert.equal(len, 25);
});
});
describe('getAngle()', function() {
it('should be zero for 10, 0', function() {
assert.equal(Vector(10, 0).getAngle(), 0);
});
it ('should be 45 degrees for 10, -10', function() {
assert.equal(Vector(10, -10).getAngle(), Math.PI * 0.25);
});
it('should be 90 degrees for 0, -10', function() {
assert.equal(Vector(0, -10).getAngle(), Math.PI * 0.5);
});
it('should be 135 degrees for -10, -10', function() {
assert.equal(Vector(-10, -10).getAngle(), Math.PI * 0.75);
});
it('should be 180 degrees for -10, 0', function() {
// Weird
assert.equal(Vector(-10, 0).getAngle(), -Math.PI);
assert.equal(Vector(-10, -0).getAngle(), Math.PI);
});
it('should be -45 degrees for 10, 10', function() {
assert.equal(Vector(10, 10).getAngle(), Math.PI * -0.25);
});
it('should be -90 degrees for 0, 10', function() {
assert.equal(Vector(0, 10).getAngle(), Math.PI * -0.5);
});
it('should be -135 degrees for -10, 10', function() {
assert.equal(Vector(-10, 10).getAngle(), Math.PI * -0.75);
});
});
describe('getAngleTo()', function() {
it('should compute angles between two vectors (0,0 = axis)', function() {
var v1 = Vector(10, 0);
var v2 = Vector(10, -10);
assert.equal(v1.getAngleTo(Vector(10, -10)), Math.PI * 0.25,
'10, 0 should be 45 degrees to 10, -10');
assert.equal(v1.getAngleTo(Vector(0, -10)), Math.PI * 0.5,
'10, 0 should be 90 degrees to 0, -10');
assert.equal(v1.getAngleTo(Vector(10, 10)), Math.PI * -0.25,
'10, 0 should be -45 degrees to 10, 10');
// Weird that it has to be negative
assert.equal(v1.getAngleTo(Vector(-10, 0)), -Math.PI,
'10, 0 should be 180 degrees to -10, 0');
assert.equal(v2.getAngleTo(Vector(0, 10)), -Math.PI * 0.75,
'10, -10 should be -135 degrees to 0, 10');
});
});
*/
});