import { assert } from 'chai'; import { DOUBLE_EPSILON } from '../../../../lib/math/float'; import { radians } from '../../../../lib/math/units'; import { Vector2D } from '../../../../lib/graphics/Vector2D'; import { Vector2DArray } from '../../../../lib/graphics/Vector2DArray'; import { Matrix } from '../../../../lib/graphics/Matrix'; import { Shape } from '../../../../lib/graphics/shapes/Shape'; import { Point } from '../../../../lib/graphics/shapes/Point'; import { Line } from '../../../../lib/graphics/shapes/Line'; import { Circle } from '../../../../lib/graphics/shapes/Circle'; import { Rectangle } from '../../../../lib/graphics/shapes/Rectangle'; import { Polygon, FillRule } from '../../../../lib/graphics/shapes/Polygon'; import { Polyline } from '../../../../lib/graphics/shapes/Polyline'; import { canvasRenderingContext2DSpy } from '../mock/CanvasRenderingContext2D'; const matrix = Matrix.create; const vector2d = Vector2D.create; const fuzzyDeepEqual = Vector2DArray.fuzzyDeepEqual; const point = Point.create; const line = Line.create; const circle = Circle.create; const rectangle = Rectangle.create; const polygon = Polygon.create; const polyline = Polyline.create; describe('graphics.shapes.Polygon', () => { describe('constructor', () => { it('default constructor', () => { const p = new Polygon(); assert.strictEqual(p.points.length, 0); }); it('one point constructor', () => { const p = new Polygon([new Vector2D(1, 2)]); assert.strictEqual(p.points.length, 1); assert.strictEqual(p.points[0].x, 1); assert.strictEqual(p.points[0].y, 2); }); it('two points constructor', () => { const p = new Polygon([new Vector2D(1, 2), new Vector2D(3, 4)]); assert.strictEqual(p.points.length, 2); assert.strictEqual(p.points[0].x, 1); assert.strictEqual(p.points[0].y, 2); assert.strictEqual(p.points[1].x, 3); assert.strictEqual(p.points[1].y, 4); }); it('instanceof', () => { const p = new Polygon(); assert.isTrue(p instanceof Shape); assert.isTrue(p instanceof Polygon); }); }); describe('clone', function () { it('clone', function () { const p1 = polygon([vector2d(1, 2), vector2d(3, 4)]); const p2 = p1.clone(); p1.points[0].x = 5; p1.points[0].y = 6; p1.points.push(vector2d(7, 8)); assert.isTrue(p2 instanceof Polygon); assert.isTrue(p2.equals(polygon([vector2d(1, 2), vector2d(3, 4)]))); }); }); describe('getters/setters', () => { it('getters/setters', () => { const poly = polygon([vector2d(1, 2), vector2d(3, 4), vector2d(1, 4)]); assert.strictEqual(poly.size, 3); poly.size = 0; assert.strictEqual(poly.size, 0); assert.deepEqual(poly.points, []); }); }); describe('isEmpty', () => { test.each([ [polygon(), true], [polygon([]), true], [polygon([vector2d()]), false], ])('isEmpty#%#', (polygon: Polygon, result: boolean) => { assert.isTrue(polygon.isEmpty() === result); }); }); describe('first', () => { it('empty', () => { assert.isUndefined(polygon().first()); }); it('non empty', () => { assert.isTrue(polygon([vector2d(1, 2), vector2d(3, 4), vector2d(5, 6)]).first().equals(vector2d(1, 2))); }); }); describe('last', () => { it('empty', () => { assert.isUndefined(polygon().last()); }); it('non empty', () => { assert.isTrue(polygon([vector2d(1, 2), vector2d(3, 4), vector2d(5, 6)]).last().equals(vector2d(5, 6))); }); }); describe('isNull', () => { test.each([ [polygon(), true], [polygon([vector2d(1, 1)]), true], [polygon([vector2d(1, 1), vector2d(1, 1)]), true], [polygon([vector2d(1, 1), vector2d(2, 2)]), false], ])('isNull#%#', (polygon: Polygon, result: boolean) => { assert.isTrue(polygon.isNull() === result); }); }); describe('fuzzyIsNull', () => { test.each([ [polygon(), true, undefined], [polygon([vector2d(1, 1)]), true, undefined], [polygon([vector2d(1, 1), vector2d(1, 1)]), true, undefined], [polygon([vector2d(1, 1), vector2d(1.000001, 1.000001)]), true, undefined], [polygon([vector2d(1, 1), vector2d(1.000001, 1.000001)]), false, DOUBLE_EPSILON], [polygon([vector2d(1, 1), vector2d(2, 2)]), false, undefined], ])('isNull#%#', (polygon: Polygon, result: boolean, epsilon: number | undefined) => { assert.isTrue(polygon.fuzzyIsNull(epsilon) === result); }); }); describe('equals', () => { test.each([ [polygon(), polygon(), true], [polygon(), polygon([vector2d()]), false], [polygon([vector2d()]), polygon(), false], [polygon([vector2d()]), polygon([vector2d()]), true], [polygon([vector2d(1, 1)]), polygon([vector2d()]), false], ])('equals#%#', (poly1: Polygon, poly2: Polygon, result: boolean) => { assert.isTrue(poly1.equals(poly2) === result); }); }); describe('fuzzyEquals', () => { test.each([ [polygon(), polygon(), true, undefined], [polygon(), polygon([vector2d()]), false, undefined], [polygon([vector2d()]), polygon(), false, undefined], [polygon([vector2d()]), polygon([vector2d()]), true, undefined], [polygon([vector2d(1, 1)]), polygon([vector2d()]), false, undefined], [polygon([vector2d(1, 1)]), polygon([vector2d(1.000001, 1.000001)]), true, undefined], [polygon([vector2d(1, 1)]), polygon([vector2d(1.000001, 1.000001)]), false, DOUBLE_EPSILON], ])('equals#%#', (poly1: Polygon, poly2: Polygon, result: boolean, epsilon: number | undefined) => { assert.isTrue(poly1.fuzzyEquals(poly2, epsilon) === result); }); }); describe('boundingRectangle', () => { test.each([ [polygon(), rectangle()], [polygon([vector2d(5, 2), vector2d(5, 6), vector2d(2, 6)]), rectangle(vector2d(2, 2), vector2d(3, 4))], [polygon([vector2d(2, 6), vector2d(5, 2), vector2d(5, 6)]), rectangle(vector2d(2, 2), vector2d(3, 4))], [polygon([vector2d(5, 6), vector2d(2, 6), vector2d(5, 2)]), rectangle(vector2d(2, 2), vector2d(3, 4))], [polygon([vector2d(2, 6), vector2d(5, 6)]), rectangle(vector2d(2, 6), vector2d(3, 0))], [polygon([vector2d(5, 2), vector2d(5, 6)]), rectangle(vector2d(5, 2), vector2d(0, 4))], ])('boundingRectangle#%#', (polygon: Polygon, result: Rectangle) => { assert.isTrue(polygon.boundingRectangle().equals(result)); }); }); describe('translate', () => { test.each([ [polygon(), vector2d(1, 1), polygon()], [polygon([vector2d(2, 2), vector2d(2, 6), vector2d(5, 6)]), vector2d(), polygon([vector2d(2, 2), vector2d(2, 6), vector2d(5, 6)])], [polygon([vector2d(2, 2), vector2d(2, 6), vector2d(5, 6)]), vector2d(1, 1), polygon([vector2d(3, 3), vector2d(3, 7), vector2d(6, 7)])], ])('translate#%#', (polygon: Polygon, offset: Vector2D, result: Polygon) => { assert.isTrue(polygon.translate(offset.x, offset.y) === polygon); assert.isTrue(polygon.equals(result)); }); }); describe('translated', () => { test.each([ [polygon(), vector2d(1, 1), polygon()], [polygon([vector2d(2, 2), vector2d(2, 6), vector2d(5, 6)]), vector2d(), polygon([vector2d(2, 2), vector2d(2, 6), vector2d(5, 6)])], [polygon([vector2d(2, 2), vector2d(2, 6), vector2d(5, 6)]), vector2d(1, 1), polygon([vector2d(3, 3), vector2d(3, 7), vector2d(6, 7)])], ])('translated#%#', (polygon: Polygon, offset: Vector2D, result: Polygon) => { assert.isTrue(polygon.translated(offset.x, offset.y).equals(result)); }); }); describe('transform', () => { it('transform', () => { const p1 = polygon([vector2d(2, 2), vector2d(5, 2), vector2d(5, 0)]); const m = matrix().translate(2, 2).scale(2, 2).rotate(radians(90)); assert.isTrue(p1.transform(m) === p1); assert.isTrue(p1.fuzzyEquals(polygon([vector2d(-2, 6), vector2d(-2, 12), vector2d(2, 12)]))); }); }); describe('transformed', () => { it('transformed', () => { const p1 = polygon([vector2d(2, 2), vector2d(5, 2), vector2d(5, 0)]); const m = matrix().translate(2, 2).scale(2, 2).rotate(radians(90)); const p2 = p1.transformed(m); assert.isTrue(p2 instanceof Polygon); assert.isTrue(p2.fuzzyEquals(polygon([vector2d(-2, 6), vector2d(-2, 12), vector2d(2, 12)]))); }); }); describe('map', () => { it('map', () => { const pts = [vector2d(2.3, 3.6), vector2d(-1.1, 0.5), vector2d(4.2, -1.1)]; const poly = polygon(pts); const bind2nd = (fn: (arg1: T1, arg2: T2) => R, boundArg: T2) => (arg: T1) => fn(arg, boundArg); assert.isTrue(poly.map(p => p.map(Math.ceil)).equals(polygon(pts.map(p => p.map(Math.ceil))))); assert.isTrue(poly.map(p => p.map(bind2nd(Math.pow, 2))).equals(polygon(pts.map(p => p.map(bind2nd(Math.pow, 2)))))); }); }); describe('get', () => { it('get', () => { const poly = polygon([vector2d(1, 1), vector2d(2, 2), vector2d(1, 2)]); assert.isTrue(poly.get(0).equals(vector2d(1, 1))); assert.isTrue(poly.get(1).equals(vector2d(2, 2))); assert.isTrue(poly.get(2).equals(vector2d(1, 2))); assert.isUndefined(poly.get(3)); }); }); describe('set', () => { it('set', () => { const poly = polygon([vector2d(1, 1), vector2d(2, 2), vector2d(1, 2)]); poly.set(0, vector2d(-1, -1)); poly.set(2, vector2d(-1, -2)); assert.isTrue(poly.get(0).equals(vector2d(-1, -1))); assert.isTrue(poly.get(1).equals(vector2d(2, 2))); assert.isTrue(poly.get(2).equals(vector2d(-1, -2))); }); }); describe('forEach', () => { it('empty', () => { let count = 0; polygon().forEach(() => { count++; }); assert.strictEqual(count, 0); }); it('non empty', () => { const pts = [vector2d(1, 1), vector2d(2, 2), vector2d(1, 2)]; const poly = polygon(pts); let count = 0; poly.forEach((point, index, polygon) => { assert.isTrue(point.equals(pts[index])); assert.isTrue(poly === polygon); count++; }); assert.strictEqual(count, poly.size); }); }); describe('raycast', () => { const tests = (fillRule?: FillRule) => [ [polygon(), vector2d(), fillRule, false], [polygon([vector2d()]), vector2d(), fillRule, false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), vector2d(2, 2), fillRule, true], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), vector2d(1, 2), fillRule, false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), vector2d(4, 2), fillRule, false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), vector2d(2, 1), fillRule, false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), vector2d(1, 3), fillRule, false], [polygon([vector2d(9, 1), vector2d(9, 3)]), vector2d(9, 2), fillRule, false], [polygon([vector2d(9, 1), vector2d(9, 3)]), vector2d(9, 0), fillRule, false], [polygon([vector2d(8, 2), vector2d(10, 2)]), vector2d(9, 2), fillRule, false], [polygon([vector2d(8, 2), vector2d(10, 2)]), vector2d(7, 2), fillRule, false], [polygon([vector2d(4, 6), vector2d(5, 3), vector2d(6, 5), vector2d(7, 3), vector2d(8, 6)]), vector2d(5, 4), fillRule, true], [polygon([vector2d(4, 6), vector2d(5, 3), vector2d(6, 5), vector2d(7, 3), vector2d(8, 6)]), vector2d(6, 4), fillRule, false], ] test.each([ ...tests(FillRule.OddEven), ...tests(FillRule.Winding), ...tests(), ])('raycast#%#', (polygon: Polygon, point: Vector2D, fillRule: FillRule, result: boolean) => { assert.isTrue(polygon.raycast(point, fillRule) === result); }); }); describe('containsPoint', () => { test.each([ [polygon(), point(), false], [polygon([vector2d()]), point(), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(2, 2), true], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(1, 2), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(4, 2), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(2, 1), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(1, 3), false], [polygon([vector2d(9, 1), vector2d(9, 3)]), point(9, 2), false], [polygon([vector2d(9, 1), vector2d(9, 3)]), point(9, 0), false], [polygon([vector2d(8, 2), vector2d(10, 2)]), point(9, 2), false], [polygon([vector2d(8, 2), vector2d(10, 2)]), point(7, 2), false], [polygon([vector2d(4, 6), vector2d(5, 3), vector2d(6, 5), vector2d(7, 3), vector2d(8, 6)]), point(5, 4), true], [polygon([vector2d(4, 6), vector2d(5, 3), vector2d(6, 5), vector2d(7, 3), vector2d(8, 6)]), point(6, 4), false], ])('containsPoint#%#', (polygon: Polygon, point: Point, result: boolean) => { assert.isTrue(polygon.containsPoint(point) === result); }); }); describe('containsLine', () => { test.each([ [polygon(), line(), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(5, 5), vector2d(7, 5)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), line(vector2d(5, 5), vector2d(7, 5)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(5, 5), vector2d(10, 5)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(6, 4), vector2d(6, 6)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(6, 4), vector2d(6, 7)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(2, 2), vector2d(4, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(1, 1), vector2d(3, 3)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(1, 1), vector2d(3, 3)), false], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), line(vector2d(3, 4), vector2d(5, 4)), true], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), line(vector2d(3, 4), vector2d(9, 4)), false], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), line(vector2d(3, 4), vector2d(1, 4)), false], ])('containsLine#%#', (polygon: Polygon, line: Line, result: boolean) => { assert.isTrue(polygon.containsLine(line) === result); }); }); describe('containsCircle', () => { test.each([ [polygon(), circle(), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(5, 5), 1), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), circle(vector2d(5, 5), 1), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(5, 5), 2), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(3, 9), 1), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(6, 6), 1), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(6, 5), 6), false], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), circle(vector2d(6, 2), 1), false], ])('containsCircle#%#', (polygon: Polygon, circle: Circle, result: boolean) => { assert.isTrue(polygon.containsCircle(circle) === result); }); }); describe('containsRectangle', () => { test.each([ [polygon(), rectangle(), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(2, 2)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), rectangle(vector2d(5, 4), vector2d(2, 2)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(2, 3)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(4, 4), vector2d(2, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(1, 1), vector2d(2, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(4, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(1, 0), vector2d(10, 10)), false], ])('containsRectangle#%#', (polygon: Polygon, rectangle: Rectangle, result: boolean) => { assert.isTrue(polygon.containsRectangle(rectangle) === result); }); }); describe('containsPolygon', () => { test.each([ [polygon(), polygon(), false], [polygon([vector2d()]), polygon(), false], [polygon(), polygon([vector2d()]), false], [polygon([vector2d()]), polygon([vector2d()]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6)]), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6), vector2d(6, 4)]), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(3, 8)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 0), vector2d(7, 6), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(11, 6), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(8, 4), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(1, 8), vector2d(6, 0), vector2d(11, 8)]), false], ])('containsPolygon#%#', (polygon1: Polygon, polygon2: Polygon, result: boolean) => { assert.isTrue(polygon1.containsPolygon(polygon2) === result); }); }); describe('containsPolyline', () => { test.each([ [polygon(), polyline(), false], [polygon([vector2d()]), polyline(), false], [polygon(), polyline([vector2d()]), false], [polygon([vector2d()]), polyline([vector2d()]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polyline([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6)]), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polyline([vector2d(6, 4), vector2d(7, 6), vector2d(3, 8)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polyline([vector2d(6, 0), vector2d(7, 6), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(11, 6), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polyline([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polyline([vector2d(6, 4), vector2d(8, 4), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polyline([vector2d(1, 8), vector2d(6, 0), vector2d(11, 8)]), false], ])('containsPolyline#%#', (polygon: Polyline, polyline: Polyline, result: boolean) => { assert.isTrue(polygon.containsPolyline(polyline) === result); }); }); describe('contains', () => { test.each([ [polygon(), point(), false], [polygon([vector2d()]), point(), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(2, 2), true], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(1, 2), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(4, 2), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(2, 1), false], [polygon([vector2d(2, 1), vector2d(3, 3), vector2d(1, 3)]), point(1, 3), false], [polygon([vector2d(9, 1), vector2d(9, 3)]), point(9, 2), false], [polygon([vector2d(9, 1), vector2d(9, 3)]), point(9, 0), false], [polygon([vector2d(8, 2), vector2d(10, 2)]), point(9, 2), false], [polygon([vector2d(8, 2), vector2d(10, 2)]), point(7, 2), false], [polygon([vector2d(4, 6), vector2d(5, 3), vector2d(6, 5), vector2d(7, 3), vector2d(8, 6)]), point(5, 4), true], [polygon([vector2d(4, 6), vector2d(5, 3), vector2d(6, 5), vector2d(7, 3), vector2d(8, 6)]), point(6, 4), false], [polygon(), line(), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(5, 5), vector2d(7, 5)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(5, 5), vector2d(10, 5)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(6, 4), vector2d(6, 6)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(6, 4), vector2d(6, 7)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(2, 2), vector2d(4, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(1, 1), vector2d(3, 3)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(1, 1), vector2d(3, 3)), false], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), line(vector2d(3, 4), vector2d(5, 4)), true], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), line(vector2d(3, 4), vector2d(9, 4)), false], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), line(vector2d(3, 4), vector2d(1, 4)), false], [polygon(), circle(), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(5, 5), 1), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(5, 5), 2), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(3, 9), 1), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(6, 6), 1), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), circle(vector2d(6, 5), 6), false], [polygon([vector2d(4, 1), vector2d(6, 5), vector2d(8, 1), vector2d(11, 7), vector2d(1, 7)]), circle(vector2d(6, 2), 1), false], [polygon(), rectangle(), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(2, 2)), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(2, 3)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(4, 4), vector2d(2, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(1, 1), vector2d(2, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(4, 2)), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(1, 0), vector2d(10, 10)), false], [polygon(), polygon(), false], [polygon([vector2d()]), polygon(), false], [polygon(), polygon([vector2d()]), false], [polygon([vector2d()]), polygon([vector2d()]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6)]), true], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(3, 8)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 0), vector2d(7, 6), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(11, 6), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(8, 4), vector2d(5, 6)]), false], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(1, 8), vector2d(6, 0), vector2d(11, 8)]), false], ])('contains#%#', (shape1: Shape, shape2: Shape, result: boolean) => { assert.isTrue(shape2.contains(shape1) === result); }); }); describe('intersectsPoint', () => { test.each([ [polygon(), point(), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(4, 4), true, [vector2d(4, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(6, 7), true, [vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(5, 5), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), point(5, 5), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(6, 1), true, [vector2d(6, 1), vector2d(6, 1)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(2, 7), true, [vector2d(2, 7), vector2d(2, 7)]], ])('intersectsPoint#%#', (polygon: Polygon, point: Point, result: boolean, points: Vector2D[] | undefined) => { assert.isTrue(polygon.intersectsPoint(point) === result); const intersection: any = {}; polygon.intersectsPoint(point, function (this: any, points, thisShape, otherShape) { assert.isTrue(polygon === thisShape); assert.isTrue(point === otherShape); this.points = this.points === undefined ? points : this.points.concat(points); return false; }, intersection); assert.isTrue(fuzzyDeepEqual(intersection.points, points), `${intersection.points} !== ${points}`); }); }); describe('intersectsLine', () => { test.each([ [polygon(), line(), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(3, 4), vector2d(9, 4)), true, [vector2d(4, 4), vector2d(8, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(6, 5), vector2d(6, 8)), true, [vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(4, 1), vector2d(8, 1)), true, [vector2d(6, 1), vector2d(6, 1)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(5, 6), vector2d(7, 6)), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), line(vector2d(5, 6), vector2d(7, 6)), false, undefined], ])('intersectsLine#%#', (polygon: Polygon, line: Line, result: boolean, points: Vector2D[] | undefined) => { assert.isTrue(polygon.intersectsLine(line) === result); const intersection: any = {}; polygon.intersectsLine(line, function (this: any, points, thisShape, otherShape) { assert.isTrue(polygon === thisShape); assert.isTrue(line === otherShape); this.points = this.points === undefined ? points : this.points.concat(points); return false; }, intersection); assert.isTrue(fuzzyDeepEqual(intersection.points, points), `${intersection.points} !== ${points}`); }); }); describe('intersectsCircle', () => { test.each([ [polygon(), circle(), false, undefined], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(6, 6), 1), true, [vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(9, 4), 1), true, [vector2d(10, 4)]], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(8, 5), 1), false, undefined], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7), vector2d(2, 7)]), circle(vector2d(8, 5), 1), false, undefined], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(0, 7), 2), true, [vector2d(2, 7), vector2d(2, 7)]], ])('intersectsCircle#%#', (polygon: Polygon, circle: Circle, result: boolean, points: Vector2D[] | undefined) => { assert.isTrue(polygon.intersectsCircle(circle) === result); const intersection: any = {}; polygon.intersectsCircle(circle, function (this: any, points, thisShape, otherShape) { assert.isTrue(polygon === thisShape); assert.isTrue(circle === otherShape); this.points = this.points === undefined ? points : this.points.concat(points); return false; }, intersection); assert.isTrue(fuzzyDeepEqual(intersection.points, points), `${intersection.points} !== ${points}`); }); }); describe('intersectsRectangle', () => { test.each([ [polygon(), rectangle(), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(4, 4), vector2d(2, 2)), true, [vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 5), vector2d(2, 2)), true, [vector2d(7, 7), vector2d(7, 7), vector2d(5, 7), vector2d(5, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(2, 2)), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), rectangle(vector2d(5, 4), vector2d(2, 2)), false, undefined], ])('intersectsRectangle#%#', (polygon: Polygon, rectangle: Rectangle, result: boolean, points: Vector2D[] | undefined) => { assert.isTrue(polygon.intersectsRectangle(rectangle) === result); const intersection: any = {}; polygon.intersectsRectangle(rectangle, function (this: any, points, thisShape, otherShape) { assert.isTrue(polygon === thisShape); assert.isTrue(rectangle === otherShape); this.points = this.points === undefined ? points : this.points.concat(points); return false; }, intersection); assert.isTrue(fuzzyDeepEqual(intersection.points, points), `${intersection.points} !== ${points}`); }); }); describe('intersectsPolygon', () => { test.each([ [polygon(), polygon(), false, undefined], [polygon([vector2d()]), polygon([vector2d()]), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(8, 4), vector2d(6, 7), vector2d(4, 4)]), true, [vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7)]], [polygon([vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), polygon([vector2d(8, 4), vector2d(6, 7), vector2d(4, 4)]), true, [vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(10, 7), vector2d(2, 7), vector2d(6, 1)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4)]], [polygon([vector2d(10, 7), vector2d(2, 7), vector2d(6, 1)]), polygon([vector2d(8, 4), vector2d(6, 7), vector2d(4, 4)]), true, [vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4)]], [polygon([vector2d(10, 7), vector2d(2, 7), vector2d(6, 1)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6)]), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6)]), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6), vector2d(6, 4)]), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(5, 5), vector2d(7, 5), vector2d(6, 7)]), true, [vector2d(6, 7), vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(8, 3), vector2d(12, 8), vector2d(8, 8)]), true, [vector2d(8, 4), vector2d(8, 7)]], ])('intersectsPolygon#%#', (polygon1: Polygon, polygon2: Polygon, result: boolean, points: Vector2D[] | undefined) => { assert.isTrue(polygon1.intersectsPolygon(polygon2) === result); const intersection: any = {}; polygon1.intersectsPolygon(polygon2, function (this: any, points, thisShape, otherShape) { assert.isTrue(polygon1 === thisShape); assert.isTrue(polygon2 === otherShape); this.points = this.points === undefined ? points : this.points.concat(points); return false; }, intersection); assert.isTrue(fuzzyDeepEqual(intersection.points, points), `${intersection.points} !== ${points}`); }); }); describe('intersects', () => { test.each([ [polygon(), point(), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(4, 4), true, [vector2d(4, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(6, 7), true, [vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(5, 5), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(6, 1), true, [vector2d(6, 1), vector2d(6, 1)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), point(2, 7), true, [vector2d(2, 7), vector2d(2, 7)]], [polygon(), line(), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(3, 4), vector2d(9, 4)), true, [vector2d(4, 4), vector2d(8, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(6, 5), vector2d(6, 8)), true, [vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(4, 1), vector2d(8, 1)), true, [vector2d(6, 1), vector2d(6, 1)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), line(vector2d(5, 6), vector2d(7, 6)), false, undefined], [polygon(), circle(), false, undefined], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(6, 6), 1), true, [vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(9, 4), 1), true, [vector2d(10, 4)]], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(8, 5), 1), false, undefined], [polygon([vector2d(2, 7), vector2d(10, 1), vector2d(10, 7)]), circle(vector2d(0, 7), 2), true, [vector2d(2, 7), vector2d(2, 7)]], [polygon(), rectangle(), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(4, 4), vector2d(2, 2)), true, [vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 5), vector2d(2, 2)), true, [vector2d(7, 7), vector2d(7, 7), vector2d(5, 7), vector2d(5, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), rectangle(vector2d(5, 4), vector2d(2, 2)), false, undefined], [polygon(), polygon(), false, undefined], [polygon([vector2d()]), polygon([vector2d()]), false, undefined], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(8, 4), vector2d(6, 7), vector2d(4, 4)]), true, [vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7)]], [polygon([vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), polygon([vector2d(8, 4), vector2d(6, 7), vector2d(4, 4)]), true, [vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(6, 1), vector2d(10, 7), vector2d(2, 7)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(8, 4), vector2d(8, 4), vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(10, 7), vector2d(2, 7), vector2d(6, 1)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4)]], [polygon([vector2d(10, 7), vector2d(2, 7), vector2d(6, 1)]), polygon([vector2d(8, 4), vector2d(6, 7), vector2d(4, 4)]), true, [vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4)]], [polygon([vector2d(10, 7), vector2d(2, 7), vector2d(6, 1)]), polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), true, [vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4), vector2d(8, 4), vector2d(8, 4)]], [polygon([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6)]), false, undefined], [polygon([vector2d(4, 4), vector2d(8, 4), vector2d(6, 7)]), polyline([vector2d(10, 7), vector2d(2, 7), vector2d(6, 1)]), true, [vector2d(6, 7), vector2d(6, 7), vector2d(4, 4), vector2d(4, 4)]], [polygon([vector2d(6, 4), vector2d(7, 6), vector2d(5, 6)]), polyline([vector2d(2, 7), vector2d(6, 1), vector2d(10, 7)]), false, undefined], ])('intersects#%#', (s1: Shape, s2: Shape, result: boolean, points: Vector2D[] | undefined) => { assert.isTrue(s2.intersects(s1) === result); const intersection: any = {}; s2.intersects(s1, function (this: any, points, thisShape, otherShape) { assert.isTrue(intersection === this); assert.isTrue(s1 === thisShape); assert.isTrue(s2 === otherShape); this.points = this.points === undefined ? points : this.points.concat(points); return false; }, intersection); assert.isTrue(fuzzyDeepEqual(intersection.points, points), `${intersection.points} !== ${points}`); }); }); describe('intersectsSelf', () => { test.each([ [polygon(), false, undefined], [polygon([vector2d(2, 2)]), false, undefined], [polygon([vector2d(2, 2), vector2d(8, 6)]), false, undefined], [polygon([vector2d(2, 2), vector2d(8, 6), vector2d(2, 6)]), false, undefined], [polygon([vector2d(2, 2), vector2d(8, 6), vector2d(8, 2), vector2d(2, 6)]), true, [vector2d(5, 4)]], [polygon([vector2d(2, 6), vector2d(2, 2), vector2d(8, 6), vector2d(8, 2)]), true, [vector2d(5, 4)]], [polygon([vector2d(8, 2), vector2d(2, 6), vector2d(2, 2), vector2d(8, 6)]), true, [vector2d(5, 4)]], [polygon([vector2d(8, 6), vector2d(8, 2), vector2d(2, 6), vector2d(2, 2)]), true, [vector2d(5, 4)]], [polygon([vector2d(2, 2), vector2d(4, 6), vector2d(6, 2), vector2d(8, 6), vector2d(10, 2), vector2d(11, 4), vector2d(1, 4)]), true, [vector2d(3, 4), vector2d(5, 4), vector2d(7, 4), vector2d(9, 4)]], [polygon([vector2d(2, 2), vector2d(5, 5), vector2d(5, 4), vector2d(4, 4), vector2d(3, 3), vector2d(3, 2)]), true, [vector2d(4, 4), vector2d(3, 3), vector2d(4, 4), vector2d(3, 3)]], ])('intersectsSelf#%#', (polygon: Polygon, result: boolean, points: Vector2D[] | undefined) => { assert.isTrue(polygon.intersectsSelf() === result); const intersection: any = {}; polygon.intersectsSelf(function (this: any, points, thisShape, otherShape) { assert.isTrue(polygon === thisShape); assert.isTrue(polygon === otherShape); this.points = this.points === undefined ? points : this.points.concat(points); return false; }, intersection); assert.isTrue(fuzzyDeepEqual(intersection.points, points), `${intersection.points} !== ${points}`); }); it('intersectsSelf#callbackReturnsTrue', () => { assert.isTrue(polygon([vector2d(2, 2), vector2d(8, 6), vector2d(8, 2), vector2d(2, 6)]).intersectsSelf(function () { return true; })); assert.isTrue(polygon([vector2d(2, 2), vector2d(4, 4), vector2d(6, 0), vector2d(8, 2)]).intersectsSelf(function () { return true; })); assert.isFalse(polygon([vector2d(2, 2), vector2d(8, 6), vector2d(2, 6)]).intersectsSelf(function () { return true; })); }); }); describe('render', () => { const begin = [ { apply: 'beginPath', args: [] } ]; const mid = [ { apply: 'closePath', args: [] } ]; const end = [ { set: 'strokeStyle', value: undefined, }, { set: 'fillStyle', value: undefined, } ]; test.each([ [ polygon(), undefined, undefined, [ ...end ] ], [ polygon([vector2d(1, 1)]), undefined, undefined, [ ...end ] ], [ polygon([vector2d(1, 1), vector2d(5, 3)]), undefined, undefined, [ ...begin, { apply: 'moveTo', args: [1, 1] }, { apply: 'lineTo', args: [5, 3] }, ...mid, { apply: 'stroke', args: [] }, ...end ] ], [ polygon([vector2d(1, 1), vector2d(5, 3), vector2d(4, -1)]), undefined, undefined, [ ...begin, { apply: 'moveTo', args: [1, 1] }, { apply: 'lineTo', args: [5, 3] }, { apply: 'lineTo', args: [4, -1] }, ...mid, { apply: 'stroke', args: [] }, ...end ] ], [ polygon([vector2d(1, 1), vector2d(5, 3), vector2d(4, -1)]), 'yellow', undefined, [ { set: 'strokeStyle', value: 'yellow' }, ...begin, { apply: 'moveTo', args: [1, 1] }, { apply: 'lineTo', args: [5, 3] }, { apply: 'lineTo', args: [4, -1] }, ...mid, { apply: 'stroke', args: [] }, ...end ] ], [ polygon([vector2d(1, 1), vector2d(5, 3), vector2d(4, -1)]), undefined, 'yellow', [ { set: 'fillStyle', value: 'yellow' }, ...begin, { apply: 'moveTo', args: [1, 1] }, { apply: 'lineTo', args: [5, 3] }, { apply: 'lineTo', args: [4, -1] }, ...mid, { apply: 'fill', args: [] }, ...end ] ], [ polygon([vector2d(1, 1), vector2d(5, 3), vector2d(4, -1)]), 'yellow', 'black', [ { set: 'strokeStyle', value: 'yellow' }, { set: 'fillStyle', value: 'black' }, ...begin, { apply: 'moveTo', args: [1, 1] }, { apply: 'lineTo', args: [5, 3] }, { apply: 'lineTo', args: [4, -1] }, ...mid, { apply: 'fill', args: [] }, { apply: 'stroke', args: [] }, ...end ] ], ])('render#%#', (p: Polygon, strokeStyle: string | undefined, fillStyle: string | undefined, result: any[]) => { const interceptions: any[] = []; const context = canvasRenderingContext2DSpy(interceptions); p.render(context, strokeStyle, fillStyle); assert.deepEqual(interceptions, result); }); }); describe('Polygon.fromRectangle', () => { test.each([ [rectangle(), polygon([vector2d(), vector2d(), vector2d(), vector2d()])], [rectangle(vector2d(1, 2), vector2d(3, 4)), polygon([vector2d(1, 2), vector2d(4, 2), vector2d(4, 6), vector2d(1, 6)])], ])('Polygon.fromRectangle#%#', (rect: Rectangle, expected: Polygon) => { const actual = Polygon.fromRectangle(rect); assert.isTrue(actual.equals(expected), `${actual} !== ${expected}`); }); }); describe('Polygon.create', () => { it('default constructor', () => { const p = Polygon.create(); assert.strictEqual(p.points.length, 0); }); it('one point constructor', () => { const p = Polygon.create([new Vector2D(1, 2)]); assert.strictEqual(p.points.length, 1); assert.strictEqual(p.points[0].x, 1); assert.strictEqual(p.points[0].y, 2); }); it('two points constructor', () => { const p = Polygon.create([new Vector2D(1, 2), new Vector2D(3, 4)]); assert.strictEqual(p.points.length, 2); assert.strictEqual(p.points[0].x, 1); assert.strictEqual(p.points[0].y, 2); assert.strictEqual(p.points[1].x, 3); assert.strictEqual(p.points[1].y, 4); }); it('instanceof', () => { const p = Polygon.create(); assert.isTrue(p instanceof Shape); assert.isTrue(p instanceof Polygon); }); }); });