import { assert } from 'chai'; import { Vector2D } from '../../../lib/graphics/Vector2D'; import { Matrix } from '../../../lib/graphics/Matrix'; import { DOUBLE_EPSILON } from '../../../lib/math/float'; const vector2d = Vector2D.create; const matrix = Matrix.create; function mutable(op: Op, v: Vector2D, ...args: any[]) { const clone = v.clone(); assert.ok((v[op])(...args) === v); assert.ok(!v.fuzzyEquals(clone)); } function immutable(op: Op, v: Vector2D, ...args: any[]) { const clone = v.clone(); assert.ok((v[op])(...args) !== v); assert.ok(v.fuzzyEquals(clone)); } describe('graphics.Vector2D', () => { it('constructor', () => { const a = vector2d(); const b = vector2d(1.5); const c = vector2d(-2, 10); assert.strictEqual(a.x, 0); assert.strictEqual(a.y, 0); assert.strictEqual(b.x, 1.5); assert.strictEqual(b.y, 0); assert.strictEqual(c.x, -2); assert.strictEqual(c.y, 10); }); it('clone', () => { const v1 = vector2d(1, 2); const v2 = v1.clone(); assert.ok(v2 instanceof Vector2D); assert.ok(v2.equals(v1)); v1.x = 3; v1.y = 4; assert.ok(v2.equals(vector2d(1, 2))); }); it('isNull', () => { assert.ok(vector2d().isNull()); assert.ok(vector2d(0, -0.0).isNull()); assert.ok(!vector2d(-1, 0).isNull()); assert.ok(!vector2d(0.00001, -0.00001).isNull()); }); it('fuzzyIsNull', () => { assert.ok(vector2d().fuzzyIsNull()); assert.ok(vector2d(0.00001, -0.00001).fuzzyIsNull(0.00001)); assert.ok(!vector2d(0.0001, -0.0001).fuzzyIsNull()); }); it('equals', () => { assert.ok(vector2d().equals(vector2d())); assert.ok(vector2d(0, -0.0).equals(vector2d(-0, 0.0))); assert.ok(vector2d(6, 2).equals(vector2d(6, 2))); assert.ok(vector2d(-0.5).equals(vector2d(-0.5))); assert.ok(!vector2d(-1, 0).equals(vector2d(0, -1))); }); it('fuzzyEquals', () => { assert.ok(vector2d().fuzzyEquals(vector2d())); assert.ok(vector2d(0, -0.0).fuzzyEquals(vector2d(-0, 0.0))); assert.ok(vector2d(-0.50001).fuzzyEquals(vector2d(-0.5), 0.00001)); assert.ok(!vector2d(-0.5001).fuzzyEquals(vector2d(-0.5))); }); it('length', () => { assert.strictEqual(vector2d(6, 8).length(), 10); assert.strictEqual(vector2d(0, 0).length(), 0); assert.strictEqual(vector2d(-4, 3).length(), 5); assert.strictEqual(vector2d(-3, -3).length(), 4.242640687119285); assert.strictEqual(vector2d(1, 1).length(), 1.4142135623730951); assert.strictEqual(vector2d(1, 2).length(), 2.23606797749979); }); it('lengthSquared', () => { assert.strictEqual(vector2d(6, 8).lengthSquared(), 100); assert.strictEqual(vector2d(0, 0).lengthSquared(), 0); assert.strictEqual(vector2d(-4, 3).lengthSquared(), 25); assert.strictEqual(vector2d(-3, -3).lengthSquared(), 18); assert.strictEqual(vector2d(1, 1).lengthSquared(), 2); }); it('manhattanLength', () => { assert.strictEqual(vector2d(6, 8).manhattanLength(), 14); assert.strictEqual(vector2d(0, 0).manhattanLength(), 0); assert.strictEqual(vector2d(-4, 3).manhattanLength(), 7); assert.strictEqual(vector2d(-3, -3).manhattanLength(), 6); assert.strictEqual(vector2d(1, 1).manhattanLength(), 2); }); it('plus', () => { assert.ok(vector2d(6, -2).plus(vector2d(-4, 4)).equals(vector2d(2, 2))); assert.ok(vector2d(1, 2).plus(vector2d(3, 4)).equals(vector2d(4, 6))); immutable('plus', vector2d(2, 4), vector2d(1, 2)); }); it('minus', () => { assert.ok(vector2d(2, 3).minus(vector2d(-4, -2)).equals(vector2d(6, 5))); assert.ok(vector2d(-4, -2).minus(vector2d(2, 3)).equals(vector2d(-6, -5))); assert.ok(vector2d(1, 2).minus(vector2d(3, 4)).equals(vector2d(-2, -2))); immutable('minus', vector2d(2, 4), vector2d(1, 2)); }); it('mul', () => { assert.ok(vector2d(2, 4).mul(2).equals(vector2d(4, 8))); assert.ok(vector2d(2, 1).mul(-1).equals(vector2d(-2, -1))); assert.ok(vector2d(2, 1).mul(-2).equals(vector2d(-4, -2))); assert.ok(vector2d(2, 1).mul(3).equals(vector2d(6, 3))); assert.ok(vector2d(2, 1).mul(-1).equals(vector2d(-2, -1))); assert.ok(vector2d(2, 1).mul(-2).equals(vector2d(-4, -2))); assert.ok(vector2d(1, 2).mul(4.48).equals(vector2d(4.48, 8.96))); assert.ok(vector2d(1, 2).mul(vector2d(4, 5)).equals(vector2d(4, 10))); assert.ok(vector2d(1, 0).mul(vector2d(2, 0)).equals(vector2d(2, 0))); assert.ok(vector2d(1, 2).mul(matrix().translate(2, 2).scale(2).rotate(Math.PI / 2)).equals(vector2d(-2, 4))); assert.ok(vector2d(1, 2).mul(matrix().rotate(Math.PI / 2).scale(2).translate(2, 2)).equals(vector2d(-8, 6))); immutable('mul', vector2d(2, 4), 2); immutable('mul', vector2d(2, 4), vector2d(2, 3)); immutable('mul', vector2d(2, 4), matrix(1, 2, 3, 4, 5, 6)); assert.ok(vector2d(1, 2).mul({}).equals(vector2d())); }); it('div', () => { assert.ok(vector2d(2, 4).div(2).equals(vector2d(1, 2))); assert.ok(vector2d(2, 1).div(-1).equals(vector2d(-2, -1))); assert.ok(vector2d(2, 1).div(-2).equals(vector2d(-1, -0.5))); assert.ok(vector2d(2, 4).div(vector2d(2, 2)).equals(vector2d(1, 2))); assert.ok(vector2d(2, 4).div(vector2d(2, 4)).equals(vector2d(1, 1))); assert.ok(vector2d(1, 2).div({}).equals(vector2d())); immutable('div', vector2d(2, 4), 2); immutable('div', vector2d(2, 4), vector2d(2, 4)); }); it('map', () => { const p = vector2d(2.3, 3.6); const plus = (a: number, b: number) => a + b; const bind2nd = (fn: (arg1: T1, arg2: T2) => R, boundArg: T2) => (arg: T1) => fn(arg, boundArg); assert.ok(p.map(Math.ceil).equals(vector2d(Math.ceil(p.x), Math.ceil(p.y)))); assert.ok(p.map(Math.floor).equals(vector2d(Math.floor(p.x), Math.floor(p.y)))); assert.ok(p.map(Math.round).equals(vector2d(Math.round(p.x), Math.round(p.y)))); assert.ok(p.map(bind2nd(Math.pow, 2)).equals(vector2d(Math.pow(p.x, 2), Math.pow(p.y, 2)))); assert.ok(p.map(bind2nd(plus, 2)).equals(vector2d(plus(p.x, 2), plus(p.y, 2)))); }); it('distanceToPoint', () => { assert.strictEqual(vector2d(3, 1).distanceToPoint(vector2d(2, 2)), vector2d(1, 1).length()); assert.strictEqual(vector2d(3, 1).distanceToPoint(vector2d(5, 3)), vector2d(1, 1).mul(2).length()); assert.strictEqual(vector2d(3, 1).distanceToPoint(vector2d(6, 4)), vector2d(1, 1).mul(3).length()); }); it('dotProduct', () => { assert.strictEqual(vector2d(1, 2).dotProduct(vector2d(3, 4)), 11); assert.strictEqual(vector2d(2, 5).dotProduct(vector2d(7, 1)), 19); immutable('dotProduct', vector2d(1, 2), vector2d(3, 4)); }); it('crossProduct', () => { assert.strictEqual(vector2d(1, 2).crossProduct(vector2d(3, 4)), -2); assert.strictEqual(vector2d(2, 5).crossProduct(vector2d(7, 1)), -33); assert.strictEqual(vector2d(7, 1).crossProduct(vector2d(2, 5)), 33); immutable('crossProduct', vector2d(1, 2), vector2d(3, 4)); }); it('normalized', () => { assert.ok(vector2d(0, 0).normalized().equals(vector2d(0, 0))); assert.ok(vector2d(0, 1).normalized().equals(vector2d(0, 1))); assert.ok(vector2d(1, 0).normalized().equals(vector2d(1, 0))); assert.ok(vector2d(1, 1).normalized().fuzzyEquals(vector2d(Math.cos(Math.PI / 4), Math.sin(Math.PI / 4)), DOUBLE_EPSILON)); }); it('distanceToLine', () => { assert.strictEqual(vector2d(0.0, 0.0).distanceToLine(vector2d(0.0, 0.0), vector2d(0.0, 0.1)), 0.0); assert.strictEqual(vector2d(0.0, 5.0).distanceToLine(vector2d(0.0, 0.0), vector2d(0.0, 1.0)), 0.0); assert.strictEqual(vector2d(1.0, 0.0).distanceToLine(vector2d(0.0, 0.0), vector2d(0.0, 1.0)), 1.0); assert.strictEqual(vector2d(-2.0, 0.0).distanceToLine(vector2d(0.0, 0.0), vector2d(0.0, 1.0)), 2.0); assert.strictEqual(vector2d(0.0, 5.0).distanceToLine(vector2d(0.0, 0.0), vector2d(0.0, 0.0)), 5.0); }); it('projected', () => { assert.ok(vector2d(2, 1).projected(vector2d(4, 2)).equals(vector2d(2, 1))); }); it('rejected', () => { assert.ok(vector2d(2, 1).rejected(vector2d(4, 2)).equals(vector2d(0, 0))); }); it('lerp', () => { assert.ok(vector2d(1, 1).interpolated(vector2d(5, 5), 0).equals(vector2d(1, 1))); assert.ok(vector2d(1, 1).interpolated(vector2d(5, 5), .5).equals(vector2d(3, 3))); assert.ok(vector2d(1, 1).interpolated(vector2d(5, 5), 1).equals(vector2d(5, 5))); }); it('invert', () => { assert.ok(vector2d(0, 0).invert().equals(vector2d(0, 0))); assert.ok(vector2d(1, 2).invert().equals(vector2d(-1, -2))); assert.ok(vector2d(-1, -2).invert().equals(vector2d(1, 2))); mutable('invert', vector2d(1, 2)); }); it('inverted', () => { assert.ok(vector2d(0, 0).inverted().equals(vector2d(0, 0))); assert.ok(vector2d(1, 2).inverted().equals(vector2d(-1, -2))); assert.ok(vector2d(-1, -2).inverted().equals(vector2d(1, 2))); immutable('inverted', vector2d(1, 2)); }); it('translate', () => { assert.ok(vector2d(0, 0).translate(0, 0).equals(vector2d(0, 0))); assert.ok(vector2d(2, 2).translate(1, 1).equals(vector2d(3, 3))); assert.ok(vector2d(2, 2).translate(-1, -1).equals(vector2d(1, 1))); mutable('translate', vector2d(1, 2), 2, 2); }); it('translated', () => { assert.ok(vector2d(0, 0).translated(0, 0).equals(vector2d(0, 0))); assert.ok(vector2d(2, 2).translated(1, 1).equals(vector2d(3, 3))); assert.ok(vector2d(2, 2).translated(-1, -1).equals(vector2d(1, 1))); immutable('translated', vector2d(1, 2), 2, 2); }); it('scale', () => { assert.ok(vector2d(1, 2).scale(2).equals(vector2d(2, 4))); assert.ok(vector2d(1, 2).scale(2, 3).equals(vector2d(2, 6))); assert.ok(vector2d(1, 2).scale(0).equals(vector2d(0, 0))); mutable('scale', vector2d(1, 2), 2); }); it('scaled', () => { assert.ok(vector2d(1, 2).scaled(2).equals(vector2d(2, 4))); assert.ok(vector2d(1, 2).scaled(2, 3).equals(vector2d(2, 6))); assert.ok(vector2d(1, 2).scaled(0).equals(vector2d(0, 0))); immutable('scaled', vector2d(1, 2), 2); }); it('rotate', () => { assert.ok(vector2d(1, 2).rotate(0).equals(vector2d(1, 2))); assert.ok(vector2d(2, 0).rotate(Math.PI / 2).fuzzyEquals(vector2d(0, 2), DOUBLE_EPSILON)); mutable('rotate', vector2d(1, 2), Math.PI / 2); }); it('rotated', () => { assert.ok(vector2d(1, 2).rotated(0).equals(vector2d(1, 2))); assert.ok(vector2d(2, 0).rotated(Math.PI / 2).fuzzyEquals(vector2d(0, 2), DOUBLE_EPSILON)); immutable('rotated', vector2d(1, 2), Math.PI / 2); }); it('transform', () => { assert.ok(vector2d(1, 2).transform(matrix().translate(2, 2).scale(2).rotate(Math.PI / 2)).equals(vector2d(-2, 4))); mutable('transform', vector2d(1, 2), matrix(1, 2, 3, 4, 5, 6)); }); it('transformed', () => { assert.ok(vector2d(1, 2).transformed(matrix().translate(2, 2).scale(2).rotate(Math.PI / 2)).equals(vector2d(-2, 4))); assert.ok(vector2d(1, 2).transformed(matrix().rotate(Math.PI / 2).scale(2).translate(2, 2)).equals(vector2d(-8, 6))); immutable('transformed', vector2d(1, 2), matrix(1, 2, 3, 4, 5, 6)); }); it('Vector2D.compare', () => { assert.isTrue(Vector2D.compare(vector2d(), vector2d()) === 0); assert.isTrue(Vector2D.compare(vector2d(1, 2), vector2d(1, 2)) === 0); assert.isTrue(Vector2D.compare(vector2d(2, 2), vector2d(1, 2)) > 0); assert.isTrue(Vector2D.compare(vector2d(1, 2), vector2d(2, 2)) < 0); assert.isTrue(Vector2D.compare(vector2d(1, 3), vector2d(1, 2)) > 0); assert.isTrue(Vector2D.compare(vector2d(1, 1), vector2d(1, 2)) < 0); }); it('Vector2D.equal', () => { assert.ok(Vector2D.equal(vector2d(), vector2d())); assert.ok(Vector2D.equal(vector2d(0, -0.0), vector2d(-0, 0.0))); assert.ok(Vector2D.equal(vector2d(6, 2), vector2d(6, 2))); assert.ok(Vector2D.equal(vector2d(-0.5), vector2d(-0.5))); assert.ok(!Vector2D.equal(vector2d(-1, 0), vector2d(0, -1))); }); it('Vector2D.fuzzyEqual', () => { assert.ok(Vector2D.fuzzyEqual(vector2d(), vector2d())); assert.ok(Vector2D.fuzzyEqual(vector2d(0, -0.0), vector2d(-0, 0.0))); assert.ok(Vector2D.fuzzyEqual(vector2d(-0.50001), vector2d(-0.5), 0.00001)); assert.ok(!Vector2D.fuzzyEqual(vector2d(-0.5001), vector2d(-0.5))); }); it('Vector2D.lerp', () => { assert.ok(Vector2D.interpolate(vector2d(1, 1), vector2d(5, 5), 0).equals(vector2d(1, 1))); assert.ok(Vector2D.interpolate(vector2d(1, 1), vector2d(5, 5), .5).equals(vector2d(3, 3))); assert.ok(Vector2D.interpolate(vector2d(1, 1), vector2d(5, 5), 1).equals(vector2d(5, 5))); }); });