phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
1,291 lines (1,154 loc) • 38.7 kB
JavaScript
var Vector3 = require('../../src/math/Vector3');
describe('Vector3', function ()
{
describe('constructor', function ()
{
it('should create a vector with default values of zero', function ()
{
var v = new Vector3();
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should create a vector with given x, y, z values', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.x).toBe(1);
expect(v.y).toBe(2);
expect(v.z).toBe(3);
});
it('should create a vector from an object with x, y, z properties', function ()
{
var v = new Vector3({ x: 4, y: 5, z: 6 });
expect(v.x).toBe(4);
expect(v.y).toBe(5);
expect(v.z).toBe(6);
});
it('should default missing object properties to zero', function ()
{
var v = new Vector3({ x: 1 });
expect(v.x).toBe(1);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should handle negative values', function ()
{
var v = new Vector3(-1, -2, -3);
expect(v.x).toBe(-1);
expect(v.y).toBe(-2);
expect(v.z).toBe(-3);
});
it('should handle floating point values', function ()
{
var v = new Vector3(1.5, 2.7, 3.14);
expect(v.x).toBe(1.5);
expect(v.y).toBe(2.7);
expect(v.z).toBe(3.14);
});
});
describe('static constants', function ()
{
it('should have ZERO constant at (0, 0, 0)', function ()
{
expect(Vector3.ZERO.x).toBe(0);
expect(Vector3.ZERO.y).toBe(0);
expect(Vector3.ZERO.z).toBe(0);
});
it('should have RIGHT constant at (1, 0, 0)', function ()
{
expect(Vector3.RIGHT.x).toBe(1);
expect(Vector3.RIGHT.y).toBe(0);
expect(Vector3.RIGHT.z).toBe(0);
});
it('should have LEFT constant at (-1, 0, 0)', function ()
{
expect(Vector3.LEFT.x).toBe(-1);
expect(Vector3.LEFT.y).toBe(0);
expect(Vector3.LEFT.z).toBe(0);
});
it('should have UP constant at (0, -1, 0)', function ()
{
expect(Vector3.UP.x).toBe(0);
expect(Vector3.UP.y).toBe(-1);
expect(Vector3.UP.z).toBe(0);
});
it('should have DOWN constant at (0, 1, 0)', function ()
{
expect(Vector3.DOWN.x).toBe(0);
expect(Vector3.DOWN.y).toBe(1);
expect(Vector3.DOWN.z).toBe(0);
});
it('should have FORWARD constant at (0, 0, 1)', function ()
{
expect(Vector3.FORWARD.x).toBe(0);
expect(Vector3.FORWARD.y).toBe(0);
expect(Vector3.FORWARD.z).toBe(1);
});
it('should have BACK constant at (0, 0, -1)', function ()
{
expect(Vector3.BACK.x).toBe(0);
expect(Vector3.BACK.y).toBe(0);
expect(Vector3.BACK.z).toBe(-1);
});
it('should have ONE constant at (1, 1, 1)', function ()
{
expect(Vector3.ONE.x).toBe(1);
expect(Vector3.ONE.y).toBe(1);
expect(Vector3.ONE.z).toBe(1);
});
});
describe('up', function ()
{
it('should set vector to (0, 1, 0)', function ()
{
var v = new Vector3(5, 5, 5);
v.up();
expect(v.x).toBe(0);
expect(v.y).toBe(1);
expect(v.z).toBe(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3();
expect(v.up()).toBe(v);
});
});
describe('min', function ()
{
it('should set components to minimum of this and given vector', function ()
{
var v = new Vector3(5, 3, 8);
v.min({ x: 3, y: 6, z: 2 });
expect(v.x).toBe(3);
expect(v.y).toBe(3);
expect(v.z).toBe(2);
});
it('should not change components already at minimum', function ()
{
var v = new Vector3(1, 2, 3);
v.min({ x: 5, y: 5, z: 5 });
expect(v.x).toBe(1);
expect(v.y).toBe(2);
expect(v.z).toBe(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.min({ x: 0, y: 0, z: 0 })).toBe(v);
});
});
describe('max', function ()
{
it('should set components to maximum of this and given vector', function ()
{
var v = new Vector3(5, 3, 8);
v.max({ x: 3, y: 6, z: 2 });
expect(v.x).toBe(5);
expect(v.y).toBe(6);
expect(v.z).toBe(8);
});
it('should not change components already at maximum', function ()
{
var v = new Vector3(5, 5, 5);
v.max({ x: 1, y: 2, z: 3 });
expect(v.x).toBe(5);
expect(v.y).toBe(5);
expect(v.z).toBe(5);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.max({ x: 5, y: 5, z: 5 })).toBe(v);
});
});
describe('clone', function ()
{
it('should return a new Vector3 with the same values', function ()
{
var v = new Vector3(1, 2, 3);
var clone = v.clone();
expect(clone.x).toBe(1);
expect(clone.y).toBe(2);
expect(clone.z).toBe(3);
});
it('should return a different object instance', function ()
{
var v = new Vector3(1, 2, 3);
var clone = v.clone();
expect(clone).not.toBe(v);
});
it('should not be affected by changes to the original', function ()
{
var v = new Vector3(1, 2, 3);
var clone = v.clone();
v.x = 99;
expect(clone.x).toBe(1);
});
});
describe('addVectors', function ()
{
it('should set this vector to the sum of two vectors', function ()
{
var v = new Vector3();
v.addVectors({ x: 1, y: 2, z: 3 }, { x: 4, y: 5, z: 6 });
expect(v.x).toBe(5);
expect(v.y).toBe(7);
expect(v.z).toBe(9);
});
it('should work with negative values', function ()
{
var v = new Vector3();
v.addVectors({ x: -1, y: -2, z: -3 }, { x: 1, y: 2, z: 3 });
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3();
expect(v.addVectors({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 })).toBe(v);
});
});
describe('subVectors', function ()
{
it('should set this vector to the difference of two vectors', function ()
{
var v = new Vector3();
v.subVectors({ x: 5, y: 7, z: 9 }, { x: 1, y: 2, z: 3 });
expect(v.x).toBe(4);
expect(v.y).toBe(5);
expect(v.z).toBe(6);
});
it('should work when result is negative', function ()
{
var v = new Vector3();
v.subVectors({ x: 1, y: 2, z: 3 }, { x: 5, y: 7, z: 9 });
expect(v.x).toBe(-4);
expect(v.y).toBe(-5);
expect(v.z).toBe(-6);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3();
expect(v.subVectors({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 })).toBe(v);
});
});
describe('crossVectors', function ()
{
it('should compute the cross product of two vectors', function ()
{
var v = new Vector3();
v.crossVectors({ x: 1, y: 0, z: 0 }, { x: 0, y: 1, z: 0 });
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(1);
});
it('should return zero vector for parallel vectors', function ()
{
var v = new Vector3();
v.crossVectors({ x: 1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 });
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should be anti-commutative', function ()
{
var v1 = new Vector3();
var v2 = new Vector3();
var a = { x: 1, y: 2, z: 3 };
var b = { x: 4, y: 5, z: 6 };
v1.crossVectors(a, b);
v2.crossVectors(b, a);
expect(v1.x).toBeCloseTo(-v2.x);
expect(v1.y).toBeCloseTo(-v2.y);
expect(v1.z).toBeCloseTo(-v2.z);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3();
expect(v.crossVectors({ x: 1, y: 0, z: 0 }, { x: 0, y: 1, z: 0 })).toBe(v);
});
});
describe('equals', function ()
{
it('should return true for equal vectors', function ()
{
var v1 = new Vector3(1, 2, 3);
var v2 = new Vector3(1, 2, 3);
expect(v1.equals(v2)).toBe(true);
});
it('should return false when x differs', function ()
{
var v1 = new Vector3(1, 2, 3);
expect(v1.equals({ x: 2, y: 2, z: 3 })).toBe(false);
});
it('should return false when y differs', function ()
{
var v1 = new Vector3(1, 2, 3);
expect(v1.equals({ x: 1, y: 3, z: 3 })).toBe(false);
});
it('should return false when z differs', function ()
{
var v1 = new Vector3(1, 2, 3);
expect(v1.equals({ x: 1, y: 2, z: 4 })).toBe(false);
});
it('should return true when compared to itself', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.equals(v)).toBe(true);
});
});
describe('copy', function ()
{
it('should copy x, y, z from source vector', function ()
{
var v = new Vector3();
v.copy({ x: 4, y: 5, z: 6 });
expect(v.x).toBe(4);
expect(v.y).toBe(5);
expect(v.z).toBe(6);
});
it('should default z to 0 when source has no z', function ()
{
var v = new Vector3(1, 2, 3);
v.copy({ x: 4, y: 5 });
expect(v.z).toBe(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3();
expect(v.copy({ x: 1, y: 1, z: 1 })).toBe(v);
});
});
describe('set', function ()
{
it('should set x, y, z from numeric arguments', function ()
{
var v = new Vector3();
v.set(1, 2, 3);
expect(v.x).toBe(1);
expect(v.y).toBe(2);
expect(v.z).toBe(3);
});
it('should set x, y, z from an object', function ()
{
var v = new Vector3();
v.set({ x: 4, y: 5, z: 6 });
expect(v.x).toBe(4);
expect(v.y).toBe(5);
expect(v.z).toBe(6);
});
it('should default missing object properties to 0', function ()
{
var v = new Vector3(9, 9, 9);
v.set({ x: 1 });
expect(v.x).toBe(1);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3();
expect(v.set(1, 2, 3)).toBe(v);
});
});
describe('setFromMatrixPosition', function ()
{
it('should extract position (column 3) from a Matrix4', function ()
{
var mat = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
7, 8, 9, 1
])
};
var v = new Vector3();
v.setFromMatrixPosition(mat);
expect(v.x).toBe(7);
expect(v.y).toBe(8);
expect(v.z).toBe(9);
});
it('should return this vector for chaining', function ()
{
var mat = { val: new Float32Array(16) };
var v = new Vector3();
expect(v.setFromMatrixPosition(mat)).toBe(v);
});
});
describe('setFromMatrixColumn', function ()
{
it('should extract column 0 from a Matrix4', function ()
{
var mat = {
val: new Float32Array([
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
])
};
var v = new Vector3();
v.setFromMatrixColumn(mat, 0);
expect(v.x).toBe(1);
expect(v.y).toBe(2);
expect(v.z).toBe(3);
});
it('should extract column 1 from a Matrix4', function ()
{
var mat = {
val: new Float32Array([
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
])
};
var v = new Vector3();
v.setFromMatrixColumn(mat, 1);
expect(v.x).toBe(5);
expect(v.y).toBe(6);
expect(v.z).toBe(7);
});
it('should return this vector for chaining', function ()
{
var mat = { val: new Float32Array(16) };
var v = new Vector3();
expect(v.setFromMatrixColumn(mat, 0)).toBe(v);
});
});
describe('fromArray', function ()
{
it('should set components from array at offset 0 by default', function ()
{
var v = new Vector3();
v.fromArray([10, 20, 30]);
expect(v.x).toBe(10);
expect(v.y).toBe(20);
expect(v.z).toBe(30);
});
it('should set components from array at given offset', function ()
{
var v = new Vector3();
v.fromArray([0, 0, 10, 20, 30], 2);
expect(v.x).toBe(10);
expect(v.y).toBe(20);
expect(v.z).toBe(30);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3();
expect(v.fromArray([1, 2, 3])).toBe(v);
});
});
describe('add', function ()
{
it('should add another vector to this vector', function ()
{
var v = new Vector3(1, 2, 3);
v.add({ x: 4, y: 5, z: 6 });
expect(v.x).toBe(5);
expect(v.y).toBe(7);
expect(v.z).toBe(9);
});
it('should treat missing z as 0', function ()
{
var v = new Vector3(1, 2, 3);
v.add({ x: 1, y: 1 });
expect(v.z).toBe(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.add({ x: 0, y: 0, z: 0 })).toBe(v);
});
});
describe('addScalar', function ()
{
it('should add a scalar to all components', function ()
{
var v = new Vector3(1, 2, 3);
v.addScalar(5);
expect(v.x).toBe(6);
expect(v.y).toBe(7);
expect(v.z).toBe(8);
});
it('should work with negative scalars', function ()
{
var v = new Vector3(5, 5, 5);
v.addScalar(-3);
expect(v.x).toBe(2);
expect(v.y).toBe(2);
expect(v.z).toBe(2);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.addScalar(1)).toBe(v);
});
});
describe('addScale', function ()
{
it('should add a scaled vector to this vector', function ()
{
var v = new Vector3(1, 2, 3);
v.addScale({ x: 1, y: 1, z: 1 }, 2);
expect(v.x).toBe(3);
expect(v.y).toBe(4);
expect(v.z).toBe(5);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.addScale({ x: 1, y: 1, z: 1 }, 1)).toBe(v);
});
});
describe('subtract', function ()
{
it('should subtract another vector from this vector', function ()
{
var v = new Vector3(5, 7, 9);
v.subtract({ x: 1, y: 2, z: 3 });
expect(v.x).toBe(4);
expect(v.y).toBe(5);
expect(v.z).toBe(6);
});
it('should treat missing z as 0', function ()
{
var v = new Vector3(1, 2, 3);
v.subtract({ x: 1, y: 1 });
expect(v.z).toBe(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(5, 7, 9);
expect(v.subtract({ x: 1, y: 2, z: 3 })).toBe(v);
});
});
describe('multiply', function ()
{
it('should multiply components by another vector', function ()
{
var v = new Vector3(2, 3, 4);
v.multiply({ x: 2, y: 3, z: 4 });
expect(v.x).toBe(4);
expect(v.y).toBe(9);
expect(v.z).toBe(16);
});
it('should treat missing z as 1', function ()
{
var v = new Vector3(2, 3, 4);
v.multiply({ x: 2, y: 3 });
expect(v.z).toBe(4);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.multiply({ x: 1, y: 1, z: 1 })).toBe(v);
});
});
describe('scale', function ()
{
it('should scale all components by the given value', function ()
{
var v = new Vector3(2, 3, 4);
v.scale(3);
expect(v.x).toBe(6);
expect(v.y).toBe(9);
expect(v.z).toBe(12);
});
it('should zero all components when given Infinity', function ()
{
var v = new Vector3(2, 3, 4);
v.scale(Infinity);
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should zero all components when given NaN', function ()
{
var v = new Vector3(2, 3, 4);
v.scale(NaN);
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should work with zero scale', function ()
{
var v = new Vector3(2, 3, 4);
v.scale(0);
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.scale(2)).toBe(v);
});
});
describe('divide', function ()
{
it('should divide components by another vector', function ()
{
var v = new Vector3(4, 9, 16);
v.divide({ x: 2, y: 3, z: 4 });
expect(v.x).toBe(2);
expect(v.y).toBe(3);
expect(v.z).toBe(4);
});
it('should treat missing z as 1', function ()
{
var v = new Vector3(4, 9, 16);
v.divide({ x: 2, y: 3 });
expect(v.z).toBe(16);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(4, 9, 16);
expect(v.divide({ x: 2, y: 3, z: 4 })).toBe(v);
});
});
describe('negate', function ()
{
it('should negate all components', function ()
{
var v = new Vector3(1, 2, 3);
v.negate();
expect(v.x).toBe(-1);
expect(v.y).toBe(-2);
expect(v.z).toBe(-3);
});
it('should negate negative values back to positive', function ()
{
var v = new Vector3(-1, -2, -3);
v.negate();
expect(v.x).toBe(1);
expect(v.y).toBe(2);
expect(v.z).toBe(3);
});
it('should leave zero unchanged', function ()
{
var v = new Vector3(0, 0, 0);
v.negate();
expect(v.x).toBe(-0);
expect(v.y).toBe(-0);
expect(v.z).toBe(-0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.negate()).toBe(v);
});
});
describe('distance', function ()
{
it('should return the distance between two vectors', function ()
{
var v = new Vector3(0, 0, 0);
var dist = v.distance({ x: 3, y: 4, z: 0 });
expect(dist).toBe(5);
});
it('should return 0 for identical vectors', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.distance({ x: 1, y: 2, z: 3 })).toBe(0);
});
it('should handle 3D distance', function ()
{
var v = new Vector3(1, 2, 3);
var dist = v.distance({ x: 4, y: 6, z: 3 });
expect(dist).toBe(5);
});
it('should return a positive value regardless of direction', function ()
{
var v = new Vector3(3, 4, 0);
expect(v.distance({ x: 0, y: 0, z: 0 })).toBe(5);
});
});
describe('distanceSq', function ()
{
it('should return the squared distance between two vectors', function ()
{
var v = new Vector3(0, 0, 0);
expect(v.distanceSq({ x: 3, y: 4, z: 0 })).toBe(25);
});
it('should return 0 for identical vectors', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.distanceSq({ x: 1, y: 2, z: 3 })).toBe(0);
});
it('should equal distance squared', function ()
{
var v = new Vector3(1, 2, 3);
var target = { x: 4, y: 6, z: 3 };
var d = v.distance(target);
expect(v.distanceSq(target)).toBeCloseTo(d * d);
});
});
describe('length', function ()
{
it('should return the length of the vector', function ()
{
var v = new Vector3(3, 4, 0);
expect(v.length()).toBe(5);
});
it('should return 0 for a zero vector', function ()
{
var v = new Vector3(0, 0, 0);
expect(v.length()).toBe(0);
});
it('should return 1 for a unit vector', function ()
{
var v = new Vector3(1, 0, 0);
expect(v.length()).toBe(1);
});
it('should work in 3D', function ()
{
var v = new Vector3(1, 2, 2);
expect(v.length()).toBe(3);
});
});
describe('lengthSq', function ()
{
it('should return the squared length of the vector', function ()
{
var v = new Vector3(3, 4, 0);
expect(v.lengthSq()).toBe(25);
});
it('should return 0 for a zero vector', function ()
{
var v = new Vector3(0, 0, 0);
expect(v.lengthSq()).toBe(0);
});
it('should equal length squared', function ()
{
var v = new Vector3(1, 2, 3);
var l = v.length();
expect(v.lengthSq()).toBeCloseTo(l * l);
});
});
describe('normalize', function ()
{
it('should produce a unit vector', function ()
{
var v = new Vector3(3, 4, 0);
v.normalize();
expect(v.length()).toBeCloseTo(1);
});
it('should not modify a zero vector', function ()
{
var v = new Vector3(0, 0, 0);
v.normalize();
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should preserve direction', function ()
{
var v = new Vector3(2, 0, 0);
v.normalize();
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(0);
expect(v.z).toBeCloseTo(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.normalize()).toBe(v);
});
});
describe('dot', function ()
{
it('should return the dot product of two vectors', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.dot({ x: 4, y: 5, z: 6 })).toBe(32);
});
it('should return 0 for perpendicular vectors', function ()
{
var v = new Vector3(1, 0, 0);
expect(v.dot({ x: 0, y: 1, z: 0 })).toBe(0);
});
it('should return length squared when dotted with itself', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.dot(v)).toBeCloseTo(v.lengthSq());
});
});
describe('cross', function ()
{
it('should compute the cross product', function ()
{
var v = new Vector3(1, 0, 0);
v.cross({ x: 0, y: 1, z: 0 });
expect(v.x).toBeCloseTo(0);
expect(v.y).toBeCloseTo(0);
expect(v.z).toBeCloseTo(1);
});
it('should return zero vector for parallel vectors', function ()
{
var v = new Vector3(1, 0, 0);
v.cross({ x: 2, y: 0, z: 0 });
expect(v.x).toBeCloseTo(0);
expect(v.y).toBeCloseTo(0);
expect(v.z).toBeCloseTo(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 0, 0);
expect(v.cross({ x: 0, y: 1, z: 0 })).toBe(v);
});
});
describe('lerp', function ()
{
it('should return start vector when t=0', function ()
{
var v = new Vector3(0, 0, 0);
v.lerp({ x: 10, y: 10, z: 10 }, 0);
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should return end vector when t=1', function ()
{
var v = new Vector3(0, 0, 0);
v.lerp({ x: 10, y: 10, z: 10 }, 1);
expect(v.x).toBe(10);
expect(v.y).toBe(10);
expect(v.z).toBe(10);
});
it('should return midpoint when t=0.5', function ()
{
var v = new Vector3(0, 0, 0);
v.lerp({ x: 10, y: 20, z: 30 }, 0.5);
expect(v.x).toBeCloseTo(5);
expect(v.y).toBeCloseTo(10);
expect(v.z).toBeCloseTo(15);
});
it('should default t to 0 when not provided', function ()
{
var v = new Vector3(1, 2, 3);
v.lerp({ x: 10, y: 10, z: 10 });
expect(v.x).toBe(1);
expect(v.y).toBe(2);
expect(v.z).toBe(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(0, 0, 0);
expect(v.lerp({ x: 1, y: 1, z: 1 }, 0.5)).toBe(v);
});
});
describe('applyMatrix3', function ()
{
it('should transform vector by a 3x3 identity matrix', function ()
{
var v = new Vector3(1, 2, 3);
var mat3 = {
val: new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1
])
};
v.applyMatrix3(mat3);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should correctly transform by a scale matrix', function ()
{
var v = new Vector3(1, 2, 3);
var mat3 = {
val: new Float32Array([
2, 0, 0,
0, 2, 0,
0, 0, 2
])
};
v.applyMatrix3(mat3);
expect(v.x).toBeCloseTo(2);
expect(v.y).toBeCloseTo(4);
expect(v.z).toBeCloseTo(6);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var mat3 = { val: new Float32Array([1,0,0, 0,1,0, 0,0,1]) };
expect(v.applyMatrix3(mat3)).toBe(v);
});
});
describe('applyMatrix4', function ()
{
it('should transform vector by a 4x4 identity matrix', function ()
{
var v = new Vector3(1, 2, 3);
var mat4 = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
};
v.applyMatrix4(mat4);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should apply translation from matrix', function ()
{
var v = new Vector3(0, 0, 0);
var mat4 = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
5, 6, 7, 1
])
};
v.applyMatrix4(mat4);
expect(v.x).toBeCloseTo(5);
expect(v.y).toBeCloseTo(6);
expect(v.z).toBeCloseTo(7);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var mat4 = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
expect(v.applyMatrix4(mat4)).toBe(v);
});
});
describe('transformMat3', function ()
{
it('should transform vector by identity matrix leaving it unchanged', function ()
{
var v = new Vector3(1, 2, 3);
var mat = {
val: new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1
])
};
v.transformMat3(mat);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var mat = { val: new Float32Array([1,0,0, 0,1,0, 0,0,1]) };
expect(v.transformMat3(mat)).toBe(v);
});
});
describe('transformMat4', function ()
{
it('should transform vector by identity matrix leaving it unchanged', function ()
{
var v = new Vector3(1, 2, 3);
var mat = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
};
v.transformMat4(mat);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should apply translation', function ()
{
var v = new Vector3(1, 2, 3);
var mat = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
10, 20, 30, 1
])
};
v.transformMat4(mat);
expect(v.x).toBeCloseTo(11);
expect(v.y).toBeCloseTo(22);
expect(v.z).toBeCloseTo(33);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var mat = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
expect(v.transformMat4(mat)).toBe(v);
});
});
describe('transformCoordinates', function ()
{
it('should transform vector by identity matrix leaving it unchanged', function ()
{
var v = new Vector3(1, 2, 3);
var mat = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
};
v.transformCoordinates(mat);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var mat = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
expect(v.transformCoordinates(mat)).toBe(v);
});
});
describe('transformQuat', function ()
{
it('should not change vector when transformed by identity quaternion', function ()
{
var v = new Vector3(1, 0, 0);
v.transformQuat({ x: 0, y: 0, z: 0, w: 1 });
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(0);
expect(v.z).toBeCloseTo(0);
});
it('should rotate x-axis to y-axis with 90 degree rotation around z', function ()
{
var v = new Vector3(1, 0, 0);
// 90 degree rotation around z-axis
var sin90 = Math.sin(Math.PI / 4);
var cos90 = Math.cos(Math.PI / 4);
v.transformQuat({ x: 0, y: 0, z: sin90, w: cos90 });
expect(v.x).toBeCloseTo(0);
expect(v.y).toBeCloseTo(1);
expect(v.z).toBeCloseTo(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 0, 0);
expect(v.transformQuat({ x: 0, y: 0, z: 0, w: 1 })).toBe(v);
});
});
describe('project', function ()
{
it('should project vector by identity matrix leaving it unchanged', function ()
{
var v = new Vector3(1, 2, 3);
var mat = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
};
v.project(mat);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var mat = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
expect(v.project(mat)).toBe(v);
});
});
describe('projectViewMatrix', function ()
{
it('should apply view then projection matrix', function ()
{
var v = new Vector3(1, 2, 3);
var identity = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
};
v.projectViewMatrix(identity, identity);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var identity = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
expect(v.projectViewMatrix(identity, identity)).toBe(v);
});
});
describe('unprojectViewMatrix', function ()
{
it('should apply projection then world matrix', function ()
{
var v = new Vector3(1, 2, 3);
var identity = {
val: new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
};
v.unprojectViewMatrix(identity, identity);
expect(v.x).toBeCloseTo(1);
expect(v.y).toBeCloseTo(2);
expect(v.z).toBeCloseTo(3);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
var identity = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
expect(v.unprojectViewMatrix(identity, identity)).toBe(v);
});
});
describe('unproject', function ()
{
it('should return this vector for chaining', function ()
{
var v = new Vector3(400, 300, 0);
var viewport = { x: 0, y: 0, z: 800, w: 600 };
var identity = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
expect(v.unproject(viewport, identity)).toBe(v);
});
it('should normalize screen coordinates before projecting', function ()
{
var v = new Vector3(400, 300, 0.5);
var viewport = { x: 0, y: 0, z: 800, w: 600 };
var identity = { val: new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) };
v.unproject(viewport, identity);
// With identity matrix, result goes through project which divides by w=1
// Just verify it ran without error and returned a finite result
expect(isFinite(v.x)).toBe(true);
expect(isFinite(v.y)).toBe(true);
expect(isFinite(v.z)).toBe(true);
});
});
describe('reset', function ()
{
it('should set all components to zero', function ()
{
var v = new Vector3(1, 2, 3);
v.reset();
expect(v.x).toBe(0);
expect(v.y).toBe(0);
expect(v.z).toBe(0);
});
it('should return this vector for chaining', function ()
{
var v = new Vector3(1, 2, 3);
expect(v.reset()).toBe(v);
});
});
});