From e392c71cc39ce06fd0bfabfc3b46ea71fa995f5a Mon Sep 17 00:00:00 2001 From: hornta Date: Mon, 15 Jul 2024 15:17:44 +0200 Subject: [PATCH 1/2] refactor: moved much code to typescript --- eslint.config.mjs | 3 + package.json | 4 +- .../src/examples/isometricRpg/play.ts | 16 +- packages/melonjs/src/camera/camera2d.js | 26 +- .../src/geometries/{earcut.js => earcut.ts} | 504 +- packages/melonjs/src/geometries/ellipse.js | 19 +- packages/melonjs/src/geometries/line.js | 8 +- packages/melonjs/src/geometries/path2d.js | 39 +- packages/melonjs/src/geometries/point.js | 76 - packages/melonjs/src/geometries/point.ts | 81 + packages/melonjs/src/geometries/poly.js | 27 +- packages/melonjs/src/geometries/rectangle.js | 11 +- .../melonjs/src/geometries/toarccanvas.js | 104 - .../melonjs/src/geometries/toarccanvas.ts | 150 + packages/melonjs/src/index.js | 41 +- packages/melonjs/src/input/pointer.js | 4 +- packages/melonjs/src/input/pointerevent.js | 6 +- packages/melonjs/src/level/level.js | 2 +- packages/melonjs/src/level/tiled/TMXLayer.js | 6 +- packages/melonjs/src/level/tiled/TMXObject.js | 16 +- packages/melonjs/src/level/tiled/TMXTile.js | 4 +- .../melonjs/src/level/tiled/TMXTileMap.js | 19 +- .../melonjs/src/level/tiled/TMXTileset.js | 2 +- .../tiled/renderer/TMXHexagonalRenderer.js | 37 +- .../tiled/renderer/TMXIsometricRenderer.js | 29 +- .../tiled/renderer/TMXOrthogonalRenderer.js | 11 +- .../src/level/tiled/renderer/TMXRenderer.js | 6 +- .../tiled/renderer/TMXStaggeredRenderer.js | 13 +- packages/melonjs/src/math/matrix2.js | 509 -- packages/melonjs/src/math/matrix2d.ts | 476 ++ .../src/math/{matrix3.js => matrix3d.ts} | 384 +- .../melonjs/src/math/observableVector2d.ts | 200 + .../melonjs/src/math/observableVector3d.ts | 226 + .../melonjs/src/math/observable_vector2.js | 425 -- .../melonjs/src/math/observable_vector3.js | 513 -- packages/melonjs/src/math/vector2.js | 424 -- packages/melonjs/src/math/vector2d.ts | 433 ++ packages/melonjs/src/math/vector3.js | 503 -- packages/melonjs/src/math/vector3d.ts | 478 ++ packages/melonjs/src/particles/particle.js | 4 +- packages/melonjs/src/physics/body.js | 33 +- packages/melonjs/src/physics/bounds.js | 437 -- packages/melonjs/src/physics/bounds.ts | 435 ++ packages/melonjs/src/physics/detector.js | 4 +- packages/melonjs/src/physics/quadtree.js | 4 +- packages/melonjs/src/physics/response.js | 2 +- packages/melonjs/src/physics/sat.js | 2 +- packages/melonjs/src/physics/world.js | 2 +- packages/melonjs/src/pool.ts | 21 + .../melonjs/src/renderable/collectable.js | 7 +- packages/melonjs/src/renderable/container.js | 14 +- packages/melonjs/src/renderable/draggable.js | 2 +- .../melonjs/src/renderable/entity/entity.js | 11 +- packages/melonjs/src/renderable/imagelayer.js | 8 +- packages/melonjs/src/renderable/renderable.js | 94 +- packages/melonjs/src/renderable/sprite.js | 10 +- .../melonjs/src/renderable/text/bitmaptext.js | 5 +- .../src/renderable/text/textmetrics.js | 2 +- packages/melonjs/src/renderable/trigger.js | 7 +- .../src/renderable/ui/uibaseelement.js | 8 +- packages/melonjs/src/system/event.ts | 2 +- packages/melonjs/src/system/pool.test.ts | 53 +- packages/melonjs/src/system/pool.ts | 128 +- packages/melonjs/src/utils/utils.ts | 1 - .../src/video/canvas/canvas_renderer.js | 2 +- packages/melonjs/src/video/renderer.js | 6 +- packages/melonjs/src/video/texture/atlas.js | 2 +- .../src/video/texture/parser/aseprite.js | 2 +- .../src/video/texture/parser/spritesheet.js | 8 +- .../src/video/texture/parser/texturepacker.js | 2 +- .../src/video/webgl/compositors/compositor.js | 2 +- .../webgl/compositors/primitive_compositor.js | 2 +- .../webgl/compositors/quad_compositor.js | 2 +- .../melonjs/src/video/webgl/webgl_renderer.js | 8 +- packages/melonjs/tests/earcut/expected.json | 63 + .../tests/earcut/fixtures/bad-diagonals.json | 15 + .../tests/earcut/fixtures/bad-hole.json | 52 + .../melonjs/tests/earcut/fixtures/boxy.json | 63 + .../tests/earcut/fixtures/building.json | 19 + .../earcut/fixtures/collinear-diagonal.json | 28 + .../tests/earcut/fixtures/degenerate.json | 1 + .../melonjs/tests/earcut/fixtures/dude.json | 107 + .../tests/earcut/fixtures/eberly-3.json | 78 + .../tests/earcut/fixtures/eberly-6.json | 1453 +++++ .../tests/earcut/fixtures/empty-square.json | 4 + .../earcut/fixtures/filtered-bridge-jhl.json | 14 + .../tests/earcut/fixtures/hilbert.json | 1031 ++++ .../earcut/fixtures/hole-touching-outer.json | 87 + .../tests/earcut/fixtures/hourglass.json | 1 + .../earcut/fixtures/infinite-loop-jhl.json | 4 + .../tests/earcut/fixtures/issue107.json | 20 + .../tests/earcut/fixtures/issue111.json | 21 + .../tests/earcut/fixtures/issue119.json | 7 + .../tests/earcut/fixtures/issue131.json | 12 + .../tests/earcut/fixtures/issue142.json | 20 + .../tests/earcut/fixtures/issue149.json | 17 + .../tests/earcut/fixtures/issue16.json | 18 + .../tests/earcut/fixtures/issue17.json | 17 + .../tests/earcut/fixtures/issue29.json | 46 + .../tests/earcut/fixtures/issue34.json | 124 + .../tests/earcut/fixtures/issue35.json | 776 +++ .../tests/earcut/fixtures/issue45.json | 5 + .../tests/earcut/fixtures/issue52.json | 106 + .../tests/earcut/fixtures/issue83.json | 198 + .../tests/earcut/fixtures/outside-ring.json | 67 + .../melonjs/tests/earcut/fixtures/rain.json | 2699 ++++++++ .../tests/earcut/fixtures/self-touching.json | 133 + .../tests/earcut/fixtures/shared-points.json | 14 + .../earcut/fixtures/simplified-us-border.json | 126 + .../tests/earcut/fixtures/steiner.json | 7 + .../tests/earcut/fixtures/touching-holes.json | 63 + .../tests/earcut/fixtures/touching2.json | 4 + .../tests/earcut/fixtures/touching3.json | 16 + .../tests/earcut/fixtures/touching4.json | 7 + .../tests/earcut/fixtures/water-huge.json | 5419 +++++++++++++++++ .../tests/earcut/fixtures/water-huge2.json | 4885 +++++++++++++++ .../melonjs/tests/earcut/fixtures/water.json | 2533 ++++++++ .../melonjs/tests/earcut/fixtures/water2.json | 1253 ++++ .../melonjs/tests/earcut/fixtures/water3.json | 220 + .../tests/earcut/fixtures/water3b.json | 34 + .../melonjs/tests/earcut/fixtures/water4.json | 734 +++ packages/melonjs/tests/earcut/test.spec.ts | 59 + packages/melonjs/tests/earcut/utils.ts | 59 + .../tests/{mat2d.spec.js => mat2d.spec.ts} | 16 +- .../tests/{mat3d.spec.js => mat3d.spec.ts} | 43 +- .../melonjs/tests/observableVect2d.spec.js | 227 - .../melonjs/tests/observableVect3d.spec.js | 281 - .../{vect2d.spec.js => vector2d.spec.ts} | 19 +- .../{vect3d.spec.js => vector3d.spec.ts} | 24 +- packages/melonjs/vitest.config.ts | 1 + pnpm-lock.yaml | 145 +- 131 files changed, 26146 insertions(+), 4516 deletions(-) rename packages/melonjs/src/geometries/{earcut.js => earcut.ts} (62%) delete mode 100644 packages/melonjs/src/geometries/point.js create mode 100644 packages/melonjs/src/geometries/point.ts delete mode 100644 packages/melonjs/src/geometries/toarccanvas.js create mode 100644 packages/melonjs/src/geometries/toarccanvas.ts delete mode 100644 packages/melonjs/src/math/matrix2.js create mode 100644 packages/melonjs/src/math/matrix2d.ts rename packages/melonjs/src/math/{matrix3.js => matrix3d.ts} (61%) create mode 100644 packages/melonjs/src/math/observableVector2d.ts create mode 100644 packages/melonjs/src/math/observableVector3d.ts delete mode 100644 packages/melonjs/src/math/observable_vector2.js delete mode 100644 packages/melonjs/src/math/observable_vector3.js delete mode 100644 packages/melonjs/src/math/vector2.js create mode 100644 packages/melonjs/src/math/vector2d.ts delete mode 100644 packages/melonjs/src/math/vector3.js create mode 100644 packages/melonjs/src/math/vector3d.ts delete mode 100644 packages/melonjs/src/physics/bounds.js create mode 100644 packages/melonjs/src/physics/bounds.ts create mode 100644 packages/melonjs/src/pool.ts create mode 100644 packages/melonjs/tests/earcut/expected.json create mode 100644 packages/melonjs/tests/earcut/fixtures/bad-diagonals.json create mode 100644 packages/melonjs/tests/earcut/fixtures/bad-hole.json create mode 100644 packages/melonjs/tests/earcut/fixtures/boxy.json create mode 100644 packages/melonjs/tests/earcut/fixtures/building.json create mode 100644 packages/melonjs/tests/earcut/fixtures/collinear-diagonal.json create mode 100644 packages/melonjs/tests/earcut/fixtures/degenerate.json create mode 100644 packages/melonjs/tests/earcut/fixtures/dude.json create mode 100644 packages/melonjs/tests/earcut/fixtures/eberly-3.json create mode 100644 packages/melonjs/tests/earcut/fixtures/eberly-6.json create mode 100644 packages/melonjs/tests/earcut/fixtures/empty-square.json create mode 100644 packages/melonjs/tests/earcut/fixtures/filtered-bridge-jhl.json create mode 100644 packages/melonjs/tests/earcut/fixtures/hilbert.json create mode 100644 packages/melonjs/tests/earcut/fixtures/hole-touching-outer.json create mode 100644 packages/melonjs/tests/earcut/fixtures/hourglass.json create mode 100644 packages/melonjs/tests/earcut/fixtures/infinite-loop-jhl.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue107.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue111.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue119.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue131.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue142.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue149.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue16.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue17.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue29.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue34.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue35.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue45.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue52.json create mode 100644 packages/melonjs/tests/earcut/fixtures/issue83.json create mode 100644 packages/melonjs/tests/earcut/fixtures/outside-ring.json create mode 100644 packages/melonjs/tests/earcut/fixtures/rain.json create mode 100644 packages/melonjs/tests/earcut/fixtures/self-touching.json create mode 100644 packages/melonjs/tests/earcut/fixtures/shared-points.json create mode 100644 packages/melonjs/tests/earcut/fixtures/simplified-us-border.json create mode 100644 packages/melonjs/tests/earcut/fixtures/steiner.json create mode 100644 packages/melonjs/tests/earcut/fixtures/touching-holes.json create mode 100644 packages/melonjs/tests/earcut/fixtures/touching2.json create mode 100644 packages/melonjs/tests/earcut/fixtures/touching3.json create mode 100644 packages/melonjs/tests/earcut/fixtures/touching4.json create mode 100644 packages/melonjs/tests/earcut/fixtures/water-huge.json create mode 100644 packages/melonjs/tests/earcut/fixtures/water-huge2.json create mode 100644 packages/melonjs/tests/earcut/fixtures/water.json create mode 100644 packages/melonjs/tests/earcut/fixtures/water2.json create mode 100644 packages/melonjs/tests/earcut/fixtures/water3.json create mode 100644 packages/melonjs/tests/earcut/fixtures/water3b.json create mode 100644 packages/melonjs/tests/earcut/fixtures/water4.json create mode 100644 packages/melonjs/tests/earcut/test.spec.ts create mode 100644 packages/melonjs/tests/earcut/utils.ts rename packages/melonjs/tests/{mat2d.spec.js => mat2d.spec.ts} (86%) rename packages/melonjs/tests/{mat3d.spec.js => mat3d.spec.ts} (86%) delete mode 100644 packages/melonjs/tests/observableVect2d.spec.js delete mode 100644 packages/melonjs/tests/observableVect3d.spec.js rename packages/melonjs/tests/{vect2d.spec.js => vector2d.spec.ts} (91%) rename packages/melonjs/tests/{vect3d.spec.js => vector3d.spec.ts} (93%) diff --git a/eslint.config.mjs b/eslint.config.mjs index 787ab33af..ff98c577a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -167,6 +167,9 @@ export default tseslint.config( "@typescript-eslint/no-unsafe-argument": "off", "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unnecessary-condition": "off", + "@typescript-eslint/no-invalid-void-type": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/restrict-template-expressions": [ "error", { allowNumber: true }, diff --git a/package.json b/package.json index f91066667..709b7d2a3 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@eslint/js": "^9.6.0", "@types/eslint__js": "^8.42.3", "@types/node": "^20.14.10", - "@vitest/browser": "^2.0.1", + "@vitest/browser": "^2.0.2", "eslint": "^9.6.0", "eslint-plugin-jsdoc": "^48.5.2", "globals": "^15.8.0", @@ -30,6 +30,6 @@ "tsconfig": "workspace:latest", "typescript": "^5.5.3", "typescript-eslint": "^8.0.0-alpha.41", - "vitest": "^2.0.1" + "vitest": "^2.0.2" } } diff --git a/packages/examples/src/examples/isometricRpg/play.ts b/packages/examples/src/examples/isometricRpg/play.ts index 3e42a38d1..049d111cb 100644 --- a/packages/examples/src/examples/isometricRpg/play.ts +++ b/packages/examples/src/examples/isometricRpg/play.ts @@ -108,13 +108,13 @@ export class PlayScreen extends Stage { game.world.addChild(new Selector()); // register on mouse event - input.registerPointerEvent( - "pointermove", - game.viewport, - (event) => { - event.emit("pointermove", event); - }, - false, - ); + // input.registerPointerEvent( + // "pointermove", + // game.viewport, + // (ev) => { + // event.emit(event.POINTERMOVE, ev); + // }, + // false, + // ); } } diff --git a/packages/melonjs/src/camera/camera2d.js b/packages/melonjs/src/camera/camera2d.js index e4383dc9b..a9f0c12fb 100644 --- a/packages/melonjs/src/camera/camera2d.js +++ b/packages/melonjs/src/camera/camera2d.js @@ -1,9 +1,7 @@ -import Vector2d from "./../math/vector2.js"; -import Vector3d from "./../math/vector3.js"; -import ObservableVector2d from "./../math/observable_vector2.js"; -import ObservableVector3d from "./../math/observable_vector3.js"; -import Matrix2d from "./../math/matrix2.js"; -import Matrix3d from "./../math/matrix3.js"; +import { Vector2d, vector2dPool } from "../math/vector2d.ts"; +import { Vector3d } from "../math/vector3d.ts"; +import { Matrix2d } from "../math/matrix2d.ts"; +import { Matrix3d } from "../math/matrix3d.ts"; import Rect from "./../geometries/rectangle.js"; import { renderer } from "./../video/video.js"; import pool from "./../system/pooling.js"; @@ -17,9 +15,10 @@ import { VIEWPORT_ONCHANGE, VIEWPORT_ONRESIZE, } from "../system/event.ts"; +import { boundsPool } from "./../physics/bounds.ts"; /** - * @import Bounds from "./../physics/bounds.js"; + * @import {Bounds} from "./../physics/bounds.ts"; * @import Color from "./../math/color.js"; * @import Entity from "./../renderable/entity/entity.js"; * @import Sprite from "./../renderable/sprite.js"; @@ -61,7 +60,7 @@ export default class Camera2d extends Renderable { * Camera bounds * @type {Bounds} */ - this.bounds = pool.pull("Bounds"); + this.bounds = boundsPool.get(); /** * enable or disable damping @@ -322,12 +321,7 @@ export default class Camera2d extends Renderable { follow(target, axis, damping) { if (target instanceof Renderable) { this.target = target.pos; - } else if ( - target instanceof Vector2d || - target instanceof Vector3d || - target instanceof ObservableVector2d || - target instanceof ObservableVector3d - ) { + } else if (target instanceof Vector2d || target instanceof Vector3d) { this.target = target; } else { throw new Error("invalid target for me.Camera2d.follow"); @@ -593,7 +587,7 @@ export default class Camera2d extends Renderable { */ localToWorld(x, y, v) { // TODO memoization for one set of coords (multitouch) - v = v || pool.pull("Vector2d"); + v = v || vector2dPool.get(); v.set(x, y).add(this.pos).sub(game.world.pos); if (!this.currentTransform.isIdentity()) { this.invCurrentTransform.apply(v); @@ -610,7 +604,7 @@ export default class Camera2d extends Renderable { */ worldToLocal(x, y, v) { // TODO memoization for one set of coords (multitouch) - v = v || pool.pull("Vector2d"); + v = v || vector2dPool.get(); v.set(x, y); if (!this.currentTransform.isIdentity()) { this.currentTransform.apply(v); diff --git a/packages/melonjs/src/geometries/earcut.js b/packages/melonjs/src/geometries/earcut.ts similarity index 62% rename from packages/melonjs/src/geometries/earcut.js rename to packages/melonjs/src/geometries/earcut.ts index a169140b5..4801d3d8f 100644 --- a/packages/melonjs/src/geometries/earcut.js +++ b/packages/melonjs/src/geometries/earcut.ts @@ -1,47 +1,35 @@ -export function earcut(data, holeIndices, dim) { - dim = dim || 2; - +/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ +/* eslint-disable jsdoc/require-jsdoc */ +export function earcut( + data: number[], + holeIndices?: number[] | null | undefined, + dim: number | undefined = 2, +): number[] { const hasHoles = holeIndices && holeIndices.length; const outerLen = hasHoles ? holeIndices[0] * dim : data.length; let outerNode = linkedList(data, 0, outerLen, dim, true); - const triangles = []; + const triangles: number[] = []; - if (!outerNode || outerNode.next === outerNode.prev) { - return triangles; - } + if (!outerNode || outerNode.next === outerNode.prev) return triangles; - let minX; - let minY; - let maxX; - let maxY; - let x; - let y; - let invSize; + let minX, minY, invSize; - if (hasHoles) { - outerNode = eliminateHoles(data, holeIndices, outerNode, dim); - } + if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox if (data.length > 80 * dim) { - minX = maxX = data[0]; - minY = maxY = data[1]; + minX = Infinity; + minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; for (let i = dim; i < outerLen; i += dim) { - x = data[i]; - y = data[i + 1]; - if (x < minX) { - minX = x; - } - if (y < minY) { - minY = y; - } - if (x > maxX) { - maxX = x; - } - if (y > maxY) { - maxY = y; - } + const x = data[i]; + const y = data[i + 1]; + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; } // minX, minY and invSize are later used to transform coords into integers for z-order calculation @@ -55,17 +43,22 @@ export function earcut(data, holeIndices, dim) { } // create a circular doubly linked list from polygon points in the specified winding order -function linkedList(data, start, end, dim, clockwise) { - let i; - let last; +function linkedList( + data: number[], + start: number, + end: number, + dim: number, + clockwise: boolean, +) { + let last: Node | null = null; if (clockwise === signedArea(data, start, end, dim) > 0) { - for (i = start; i < end; i += dim) { - last = insertNode(i, data[i], data[i + 1], last); + for (let i = start; i < end; i += dim) { + last = insertNode((i / dim) | 0, data[i], data[i + 1], last); } } else { - for (i = end - dim; i >= start; i -= dim) { - last = insertNode(i, data[i], data[i + 1], last); + for (let i = end - dim; i >= start; i -= dim) { + last = insertNode((i / dim) | 0, data[i], data[i + 1], last); } } @@ -74,29 +67,25 @@ function linkedList(data, start, end, dim, clockwise) { last = last.next; } - return last; + return last!; } // eliminate colinear or duplicate points -function filterPoints(start, end) { - if (!start) { - return start; - } - if (!end) { - end = start; - } - - let p = start; - let again; +function filterPoints(start: null, end?: Node | null): null; +function filterPoints(start: Node, end?: Node | null): Node; +function filterPoints(start: Node | null, end?: Node | null) { + if (!start) return start; + if (!end) end = start; + + let p = start, + again; do { again = false; if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) { removeNode(p); p = end = p.prev; - if (p === p.next) { - break; - } + if (p === p.next) break; again = true; } else { p = p.next; @@ -107,30 +96,29 @@ function filterPoints(start, end) { } // main ear slicing loop which triangulates a polygon (given as a linked list) -function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { - if (!ear) { - return; - } +function earcutLinked( + ear: Node, + triangles: number[], + dim: number, + minX: number | undefined, + minY: number | undefined, + invSize: number | undefined, + pass: number, +) { + if (!ear) return; // interlink polygon nodes in z-order - if (!pass && invSize) { - indexCurve(ear, minX, minY, invSize); - } + if (!pass && invSize) indexCurve(ear, minX!, minY!, invSize); let stop = ear; - let prev; - let next; // iterate through ears, slicing them one by one while (ear.prev !== ear.next) { - prev = ear.prev; - next = ear.next; + const prev = ear.prev; + const next = ear.next; - if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) { - // cut off the triangle - triangles.push((prev.i / dim) | 0); - triangles.push((ear.i / dim) | 0); - triangles.push((next.i / dim) | 0); + if (invSize ? isEarHashed(ear, minX!, minY!, invSize) : isEar(ear)) { + triangles.push(prev.i, ear.i, next.i); // cut off the triangle removeNode(ear); @@ -151,7 +139,7 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { // if this didn't work, try curing all small self-intersections locally } else if (pass === 1) { - ear = cureLocalIntersections(filterPoints(ear), triangles, dim); + ear = cureLocalIntersections(filterPoints(ear), triangles); earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); // as a last resort, try splitting the remaining polygon into two @@ -165,28 +153,26 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { } // check whether a polygon node forms a valid ear with adjacent nodes -function isEar(ear) { - const a = ear.prev; - const b = ear; - const c = ear.next; +function isEar(ear: Node) { + const a = ear.prev, + b = ear, + c = ear.next; - if (area(a, b, c) >= 0) { - return false; - } // reflex, can't be an ear + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear // now make sure we don't have other points inside the potential ear - const ax = a.x; - const bx = b.x; - const cx = c.x; - const ay = a.y; - const by = b.y; - const cy = c.y; + const ax = a.x, + bx = b.x, + cx = c.x, + ay = a.y, + by = b.y, + cy = c.y; // triangle bbox; min & max are calculated like this for speed - const x0 = ax < bx ? (ax < cx ? ax : cx) : bx < cx ? bx : cx; - const y0 = ay < by ? (ay < cy ? ay : cy) : by < cy ? by : cy; - const x1 = ax > bx ? (ax > cx ? ax : cx) : bx > cx ? bx : cx; - const y1 = ay > by ? (ay > cy ? ay : cy) : by > cy ? by : cy; + const x0 = ax < bx ? (ax < cx ? ax : cx) : bx < cx ? bx : cx, + y0 = ay < by ? (ay < cy ? ay : cy) : by < cy ? by : cy, + x1 = ax > bx ? (ax > cx ? ax : cx) : bx > cx ? bx : cx, + y1 = ay > by ? (ay > cy ? ay : cy) : by > cy ? by : cy; let p = c.next; while (p !== a) { @@ -197,43 +183,40 @@ function isEar(ear) { p.y <= y1 && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0 - ) { + ) return false; - } p = p.next; } return true; } -function isEarHashed(ear, minX, minY, invSize) { - const a = ear.prev; - const b = ear; - const c = ear.next; +function isEarHashed(ear: Node, minX: number, minY: number, invSize: number) { + const a = ear.prev, + b = ear, + c = ear.next; - if (area(a, b, c) >= 0) { - return false; - } // reflex, can't be an ear + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear - const ax = a.x; - const bx = b.x; - const cx = c.x; - const ay = a.y; - const by = b.y; - const cy = c.y; + const ax = a.x, + bx = b.x, + cx = c.x, + ay = a.y, + by = b.y, + cy = c.y; // triangle bbox; min & max are calculated like this for speed - const x0 = ax < bx ? (ax < cx ? ax : cx) : bx < cx ? bx : cx; - const y0 = ay < by ? (ay < cy ? ay : cy) : by < cy ? by : cy; - const x1 = ax > bx ? (ax > cx ? ax : cx) : bx > cx ? bx : cx; - const y1 = ay > by ? (ay > cy ? ay : cy) : by > cy ? by : cy; + const x0 = ax < bx ? (ax < cx ? ax : cx) : bx < cx ? bx : cx, + y0 = ay < by ? (ay < cy ? ay : cy) : by < cy ? by : cy, + x1 = ax > bx ? (ax > cx ? ax : cx) : bx > cx ? bx : cx, + y1 = ay > by ? (ay > cy ? ay : cy) : by > cy ? by : cy; // z-order range for the current triangle bbox; - const minZ = zOrder(x0, y0, minX, minY, invSize); - const maxZ = zOrder(x1, y1, minX, minY, invSize); + const minZ = zOrder(x0, y0, minX, minY, invSize), + maxZ = zOrder(x1, y1, minX, minY, invSize); - let p = ear.prevZ; - let n = ear.nextZ; + let p = ear.prevZ, + n = ear.nextZ; // look for points inside the triangle in both directions while (p && p.z >= minZ && n && n.z <= maxZ) { @@ -246,9 +229,8 @@ function isEarHashed(ear, minX, minY, invSize) { p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0 - ) { + ) return false; - } p = p.prevZ; if ( @@ -260,9 +242,8 @@ function isEarHashed(ear, minX, minY, invSize) { n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0 - ) { + ) return false; - } n = n.nextZ; } @@ -277,9 +258,8 @@ function isEarHashed(ear, minX, minY, invSize) { p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0 - ) { + ) return false; - } p = p.prevZ; } @@ -294,9 +274,8 @@ function isEarHashed(ear, minX, minY, invSize) { n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0 - ) { + ) return false; - } n = n.nextZ; } @@ -304,11 +283,11 @@ function isEarHashed(ear, minX, minY, invSize) { } // go through all polygon nodes and cure small local self-intersections -function cureLocalIntersections(start, triangles, dim) { +function cureLocalIntersections(start: Node, triangles: number[]) { let p = start; do { - const a = p.prev; - const b = p.next.next; + const a = p.prev, + b = p.next.next; if ( !equals(a, b) && @@ -316,9 +295,7 @@ function cureLocalIntersections(start, triangles, dim) { locallyInside(a, b) && locallyInside(b, a) ) { - triangles.push((a.i / dim) | 0); - triangles.push((p.i / dim) | 0); - triangles.push((b.i / dim) | 0); + triangles.push(a.i, p.i, b.i); // remove two nodes involved removeNode(p); @@ -333,7 +310,14 @@ function cureLocalIntersections(start, triangles, dim) { } // try splitting polygon into two and triangulate them independently -function splitEarcut(start, triangles, dim, minX, minY, invSize) { +function splitEarcut( + start: Node, + triangles: number[], + dim: number, + minX: number | undefined, + minY: number | undefined, + invSize: number | undefined, +) { // look for a valid diagonal that divides the polygon into two let a = start; do { @@ -359,40 +343,38 @@ function splitEarcut(start, triangles, dim, minX, minY, invSize) { } // link every hole into the outer loop, producing a single-ring polygon without holes -function eliminateHoles(data, holeIndices, outerNode, dim) { +function eliminateHoles( + data: number[], + holeIndices: number[], + outerNode: Node, + dim: number, +) { const queue = []; - let i; - let len; - let start; - let end; - let list; - - for (i = 0, len = holeIndices.length; i < len; i++) { - start = holeIndices[i] * dim; - end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; - list = linkedList(data, start, end, dim, false); - if (list === list.next) { - list.steiner = true; - } + + for (let i = 0, len = holeIndices.length; i < len; i++) { + const start = holeIndices[i] * dim; + const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; + const list = linkedList(data, start, end, dim, false); + if (list === list.next) list.steiner = true; queue.push(getLeftmost(list)); } queue.sort(compareX); // process holes from left to right - for (i = 0; i < queue.length; i++) { + for (let i = 0; i < queue.length; i++) { outerNode = eliminateHole(queue[i], outerNode); } return outerNode; } -function compareX(a, b) { +function compareX(a: Node, b: Node) { return a.x - b.x; } // find a bridge between vertices that connects hole with an outer ring and and link it -function eliminateHole(hole, outerNode) { +function eliminateHole(hole: Node, outerNode: Node) { const bridge = findHoleBridge(hole, outerNode); if (!bridge) { return outerNode; @@ -406,7 +388,7 @@ function eliminateHole(hole, outerNode) { } // David Eberly's algorithm for finding a bridge between hole and outer polygon -function findHoleBridge(hole, outerNode) { +function findHoleBridge(hole: Node, outerNode: Node) { let p = outerNode; const hx = hole.x; const hy = hole.y; @@ -421,17 +403,13 @@ function findHoleBridge(hole, outerNode) { if (x <= hx && x > qx) { qx = x; m = p.x < p.next.x ? p : p.next; - if (x === hx) { - return m; - } // hole touches outer segment; pick leftmost endpoint + if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint } } p = p.next; } while (p !== outerNode); - if (!m) { - return null; - } + if (!m) return null; // look for points inside the triangle of hole point, segment intersection and endpoint; // if there are no points found, we have a valid connection; @@ -441,7 +419,6 @@ function findHoleBridge(hole, outerNode) { const mx = m.x; const my = m.y; let tanMin = Infinity; - let tan; p = m; @@ -461,7 +438,7 @@ function findHoleBridge(hole, outerNode) { p.y, ) ) { - tan = Math.abs(hy - p.y) / (hx - p.x); // tangential + const tan = Math.abs(hy - p.y) / (hx - p.x); // tangential if ( locallyInside(p, hole) && @@ -481,23 +458,21 @@ function findHoleBridge(hole, outerNode) { } // whether sector in vertex m contains sector in vertex p in the same coordinates -function sectorContainsSector(m, p) { +function sectorContainsSector(m: Node, p: Node) { return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0; } // interlink polygon nodes in z-order -function indexCurve(start, minX, minY, invSize) { +function indexCurve(start: Node, minX: number, minY: number, invSize: number) { let p = start; do { - if (p.z === 0) { - p.z = zOrder(p.x, p.y, minX, minY, invSize); - } + if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize); p.prevZ = p.prev; p.nextZ = p.next; p = p.next; } while (p !== start); - p.prevZ.nextZ = null; + p.prevZ!.nextZ = null; p.prevZ = null; sortLinked(p); @@ -505,44 +480,38 @@ function indexCurve(start, minX, minY, invSize) { // Simon Tatham's linked list merge sort algorithm // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html -function sortLinked(list) { - let i; - let p; - let q; - let e; - let tail; +function sortLinked(head: Node) { let numMerges; - let pSize; - let qSize; let inSize = 1; + let list: Node | null = head; + do { - p = list; + let p: Node | null = list; + let e: Node; list = null; - tail = null; + let tail = null; numMerges = 0; while (p) { numMerges++; - q = p; - pSize = 0; - for (i = 0; i < inSize; i++) { + let q: Node | null = p; + let pSize = 0; + for (let i = 0; i < inSize; i++) { pSize++; q = q.nextZ; - if (!q) { - break; - } + if (!q) break; } - qSize = inSize; + let qSize = inSize; while (pSize > 0 || (qSize > 0 && q)) { - if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) { - e = p; - p = p.nextZ; + if (pSize !== 0 && (qSize === 0 || !q || p!.z <= q.z)) { + e = p!; + p = p!.nextZ; pSize--; } else { - e = q; - q = q.nextZ; + e = q!; + q = q!.nextZ; qSize--; } @@ -559,7 +528,7 @@ function sortLinked(list) { p = q; } - tail.nextZ = null; + tail!.nextZ = null; inSize *= 2; } while (numMerges > 1); @@ -567,7 +536,13 @@ function sortLinked(list) { } // z-order of a point given coords and inverse of the longer side of data bbox -function zOrder(x, y, minX, minY, invSize) { +function zOrder( + x: number, + y: number, + minX: number, + minY: number, + invSize: number, +) { // coords are transformed into non-negative 15-bit integer range x = ((x - minX) * invSize) | 0; y = ((y - minY) * invSize) | 0; @@ -586,13 +561,12 @@ function zOrder(x, y, minX, minY, invSize) { } // find the leftmost node of a polygon ring -function getLeftmost(start) { - let p = start; - let leftmost = start; +function getLeftmost(start: Node) { + let p = start, + leftmost = start; do { - if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) { + if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p; - } p = p.next; } while (p !== start); @@ -600,7 +574,16 @@ function getLeftmost(start) { } // check if a point lies within a convex triangle -function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) { +function pointInTriangle( + ax: number, + ay: number, + bx: number, + by: number, + cx: number, + cy: number, + px: number, + py: number, +) { return ( (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && @@ -609,7 +592,7 @@ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) { } // check if a diagonal between two polygon nodes is valid (lies in polygon interior) -function isValidDiagonal(a, b) { +function isValidDiagonal(a: Node, b: Node) { return ( a.next.i !== b.i && a.prev.i !== b.i && @@ -625,44 +608,34 @@ function isValidDiagonal(a, b) { } // signed area of a triangle -function area(p, q, r) { +function area(p: Node, q: Node, r: Node) { return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); } // check if two points are equal -function equals(p1, p2) { +function equals(p1: Node, p2: Node) { return p1.x === p2.x && p1.y === p2.y; } // check if two segments intersect -function intersects(p1, q1, p2, q2) { +function intersects(p1: Node, q1: Node, p2: Node, q2: Node) { const o1 = sign(area(p1, q1, p2)); const o2 = sign(area(p1, q1, q2)); const o3 = sign(area(p2, q2, p1)); const o4 = sign(area(p2, q2, q1)); - if (o1 !== o2 && o3 !== o4) { - return true; - } // general case - - if (o1 === 0 && onSegment(p1, p2, q1)) { - return true; - } // p1, q1 and p2 are collinear and p2 lies on p1q1 - if (o2 === 0 && onSegment(p1, q2, q1)) { - return true; - } // p1, q1 and q2 are collinear and q2 lies on p1q1 - if (o3 === 0 && onSegment(p2, p1, q2)) { - return true; - } // p2, q2 and p1 are collinear and p1 lies on p2q2 - if (o4 === 0 && onSegment(p2, q1, q2)) { - return true; - } // p2, q2 and q1 are collinear and q1 lies on p2q2 + if (o1 !== o2 && o3 !== o4) return true; // general case + + if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 return false; } // for collinear points p, q, r, check if point q lies on segment pr -function onSegment(p, q, r) { +function onSegment(p: Node, q: Node, r: Node) { return ( q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && @@ -671,12 +644,12 @@ function onSegment(p, q, r) { ); } -function sign(num) { +function sign(num: number) { return num > 0 ? 1 : num < 0 ? -1 : 0; } // check if a polygon diagonal intersects any polygon segments -function intersectsPolygon(a, b) { +function intersectsPolygon(a: Node, b: Node) { let p = a; do { if ( @@ -685,9 +658,8 @@ function intersectsPolygon(a, b) { p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b) - ) { + ) return true; - } p = p.next; } while (p !== a); @@ -695,14 +667,14 @@ function intersectsPolygon(a, b) { } // check if a polygon diagonal is locally inside the polygon -function locallyInside(a, b) { +function locallyInside(a: Node, b: Node) { return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0; } // check if the middle point of a polygon diagonal is inside the polygon -function middleInside(a, b) { +function middleInside(a: Node, b: Node) { let p = a; let inside = false; const px = (a.x + b.x) / 2; @@ -712,9 +684,8 @@ function middleInside(a, b) { p.y > py !== p.next.y > py && p.next.y !== p.y && px < ((p.next.x - p.x) * (py - p.y)) / (p.next.y - p.y) + p.x - ) { + ) inside = !inside; - } p = p.next; } while (p !== a); @@ -723,30 +694,30 @@ function middleInside(a, b) { // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; // if one belongs to the outer ring and another to a hole, it merges it into a single ring -function splitPolygon(a, b) { - const a2 = new Node(a.i, a.x, a.y); - const b2 = new Node(b.i, b.x, b.y); - const an = a.next; - const bp = b.prev; +function splitPolygon(a: Node, b: Node) { + const a2 = createNode(a.i, a.x, a.y), + b2 = createNode(b.i, b.x, b.y), + an = a.next, + bp = b.prev; a.next = b; b.prev = a; a2.next = an; - an.prev = a2; + an.prev = a2 as Node; - b2.next = a2; - a2.prev = b2; + b2.next = a2 as Node; + a2.prev = b2 as Node; - bp.next = b2; + bp.next = b2 as Node; b2.prev = bp; - return b2; + return b2 as Node; } // create a node and optionally link it with previous one (in a circular doubly linked list) -function insertNode(i, x, y, last) { - const p = new Node(i, x, y); +function insertNode(i: number, x: number, y: number, last: Node | null) { + const p = createNode(i, x, y) as Node; if (!last) { p.prev = p; @@ -760,42 +731,51 @@ function insertNode(i, x, y, last) { return p; } -function removeNode(p) { +function removeNode(p: Node) { p.next.prev = p.prev; p.prev.next = p.next; - if (p.prevZ) { - p.prevZ.nextZ = p.nextZ; - } - if (p.nextZ) { - p.nextZ.prevZ = p.prevZ; - } -} - -function Node(i, x, y) { - // vertex index in coordinates array - this.i = i; - - // vertex coordinates - this.x = x; - this.y = y; - - // previous and next vertex nodes in a polygon ring - this.prev = null; - this.next = null; - - // z-order curve value - this.z = 0; - - // previous and next nodes in z-order - this.prevZ = null; - this.nextZ = null; - - // indicates whether this is a steiner point - this.steiner = false; -} - -function signedArea(data, start, end, dim) { + if (p.prevZ) p.prevZ.nextZ = p.nextZ; + if (p.nextZ) p.nextZ.prevZ = p.prevZ; +} + +interface LooseNode { + i: number; + x: number; + y: number; + prev: Node | null; + next: Node | null; + z: number; + prevZ: Node | null; + nextZ: Node | null; + steiner: boolean; +} + +interface Node extends LooseNode { + prev: Node; + next: Node; +} + +function createNode(i: number, x: number, y: number): LooseNode { + return { + i, // vertex index in coordinates array + x, + y, // vertex coordinates + prev: null, // previous and next vertex nodes in a polygon ring + next: null, + z: 0, // z-order curve value + prevZ: null, // previous and next nodes in z-order + nextZ: null, + steiner: false, // indicates whether this is a steiner point + }; +} + +export function signedArea( + data: number[], + start: number, + end: number, + dim: number, +) { let sum = 0; for (let i = start, j = end - dim; i < end; i += dim) { sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]); diff --git a/packages/melonjs/src/geometries/ellipse.js b/packages/melonjs/src/geometries/ellipse.js index 65efa2687..d64e7b3b0 100644 --- a/packages/melonjs/src/geometries/ellipse.js +++ b/packages/melonjs/src/geometries/ellipse.js @@ -1,10 +1,11 @@ -import pool from "./../system/pooling.js"; +import { vector2dPool } from "../math/vector2d.ts"; +import { boundsPool } from "./../physics/bounds.ts"; /** * additional import for TypeScript - * @import Vector2d from "./../math/vector2.js"; - * @import Matrix2d from "./../math/matrix2.js"; - * @import Bounds from "./../physics/bounds.js"; + * @import {Vector2d} from "../math/vector2d.js"; + * @import {Matrix2d} from "../math/matrix2d.ts"; + * @import {Bounds} from "./../physics/bounds.ts"; */ /** @@ -23,7 +24,7 @@ export default class Ellipse { * @public * @type {Vector2d} */ - this.pos = pool.pull("Vector2d"); + this.pos = vector2dPool.get(); /** * The bounding rectangle for this shape @@ -43,21 +44,21 @@ export default class Ellipse { * @public * @type {Vector2d} */ - this.radiusV = pool.pull("Vector2d"); + this.radiusV = vector2dPool.get(); /** * Radius squared, for pythagorean theorom * @public * @type {Vector2d} */ - this.radiusSq = pool.pull("Vector2d"); + this.radiusSq = vector2dPool.get(); /** * x/y scaling ratio for ellipse * @public * @type {Vector2d} */ - this.ratio = pool.pull("Vector2d"); + this.ratio = vector2dPool.get(); /** * the shape type (used internally) @@ -221,7 +222,7 @@ export default class Ellipse { */ getBounds() { if (typeof this._bounds === "undefined") { - this._bounds = pool.pull("Bounds"); + this._bounds = boundsPool.get(); } return this._bounds; } diff --git a/packages/melonjs/src/geometries/line.js b/packages/melonjs/src/geometries/line.js index ec277ef33..1474905c2 100644 --- a/packages/melonjs/src/geometries/line.js +++ b/packages/melonjs/src/geometries/line.js @@ -1,9 +1,9 @@ -import pool from "./../system/pooling.js"; +import { vector2dPool } from "../math/vector2d.ts"; import Polygon from "./poly.js"; /** * additional import for TypeScript - * @import Vector2d from "./../math/vector2d.js"; + * @import {Vector2d} from "./../math/vector2d.js"; */ /** @@ -74,11 +74,11 @@ export default class Line extends Polygon { // Calculate the edges/normals if (edges[0] === undefined) { - edges[0] = pool.pull("Vector2d"); + edges[0] = vector2dPool.get(); } edges[0].copy(points[1]).sub(points[0]); if (normals[0] === undefined) { - normals[0] = pool.pull("Vector2d"); + normals[0] = vector2dPool.get(); } normals[0].copy(edges[0]).perp().normalize(); diff --git a/packages/melonjs/src/geometries/path2d.js b/packages/melonjs/src/geometries/path2d.js index 6e3e88b76..557607b4f 100644 --- a/packages/melonjs/src/geometries/path2d.js +++ b/packages/melonjs/src/geometries/path2d.js @@ -1,11 +1,11 @@ -import pool from "./../system/pooling.js"; import { TAU } from "./../math/math.ts"; -import { endpointToCenterParameterization } from "./toarccanvas.js"; -import { earcut } from "./earcut.js"; +import { endpointToCenterParameterization } from "./toarccanvas.ts"; +import { earcut } from "./earcut.ts"; +import { pointPool } from "./point.ts"; /** * additional import for TypeScript - * @import Point from "./point.js"; + * @import {Point} from "./point.ts"; */ /** @@ -30,7 +30,7 @@ class Path2D { this.vertices = []; /* @ignore */ - this.startPoint = pool.pull("Point"); + this.startPoint = pointPool.get(); /* @ignore */ this.isDirty = false; @@ -124,7 +124,7 @@ class Path2D { beginPath() { // empty the cache and recycle all vectors this.points.forEach((point) => { - pool.push(point); + pointPool.release(point); }); this.isDirty = true; this.points.length = 0; @@ -165,7 +165,7 @@ class Path2D { // pre-allocate vertices if necessary while (vertices.length < indicesLength) { - vertices.push(pool.pull("Point")); + vertices.push(pointPool.get()); } // calculate all vertices @@ -176,7 +176,7 @@ class Path2D { // recycle overhead from a previous triangulation while (vertices.length > indicesLength) { - pool.push(vertices[vertices.length - 1]); + pointPool.release(vertices[vertices.length - 1]); vertices.length -= 1; } this.isDirty = false; @@ -207,11 +207,11 @@ class Path2D { points.length === 0 ? startPoint : points[points.length - 1]; if (!startPoint.equals(lastPoint)) { - points.push(pool.pull("Point", startPoint.x, startPoint.y)); + points.push(pointPool.get(startPoint.x, startPoint.y)); } else { - points.push(pool.pull("Point", lastPoint.x, lastPoint.y)); + points.push(pointPool.get(lastPoint.x, lastPoint.y)); } - points.push(pool.pull("Point", x, y)); + points.push(pointPool.get(x, y)); startPoint.x = x; startPoint.y = y; @@ -451,8 +451,8 @@ class Path2D { const startPoint = this.startPoint; const lastPoint = points.length === 0 ? startPoint : points[points.length - 1]; - const endPoint = pool.pull("Point").set(x, y); - const controlPoint = pool.pull("Point").set(cpX, cpY); + const endPoint = pointPool.get().set(x, y); + const controlPoint = pointPool.get().set(cpX, cpY); const resolution = this.arcResolution; const t = 1 / resolution; @@ -466,7 +466,8 @@ class Path2D { endPoint.y * Math.pow(t * i, 2), ); } - pool.push(endPoint, controlPoint); + pointPool.release(endPoint); + pointPool.release(controlPoint); this.isDirty = true; } @@ -484,9 +485,9 @@ class Path2D { const startPoint = this.startPoint; const lastPoint = points.length === 0 ? startPoint : points[points.length - 1]; - const endPoint = pool.pull("Point").set(x, y); - const controlPoint1 = pool.pull("Point").set(cp1X, cp1Y); - const controlPoint2 = pool.pull("Point").set(cp2X, cp2Y); + const endPoint = pointPool.get().set(x, y); + const controlPoint1 = pointPool.get().set(cp1X, cp1Y); + const controlPoint2 = pointPool.get().set(cp2X, cp2Y); const resolution = this.arcResolution; const t = 1 / resolution; @@ -503,7 +504,9 @@ class Path2D { ); } - pool.push(endPoint, controlPoint1, controlPoint2); + pointPool.release(endPoint, controlPoint1, controlPoint2); + pointPool.release(controlPoint1); + pointPool.release(controlPoint2); this.isDirty = true; } diff --git a/packages/melonjs/src/geometries/point.js b/packages/melonjs/src/geometries/point.js deleted file mode 100644 index 8ae8f0088..000000000 --- a/packages/melonjs/src/geometries/point.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * additional import for TypeScript - * @import Vector2d from "./../math/vector2.js"; - **/ - -/** - * represents a point in a 2d space - */ -export default class Point { - constructor(x = 0, y = 0) { - /** - * the position of the point on the horizontal axis - * @type {number} - * @default 0 - */ - this.x = x; - - /** - * the position of the point on the vertical axis - * @type {number} - * @default 0 - */ - this.y = y; - - /** - * the shape type (used internally) - * @type {string} - * @default "Point" - */ - this.type = "Point"; - } - - /** @ignore */ - onResetEvent(x = 0, y = 0) { - this.set(x, y); - } - - /** - * set the Point x and y properties to the given values - * @param {number} x - * @param {number} y - * @returns {Point} Reference to this object for method chaining - */ - set(x = 0, y = 0) { - this.x = x; - this.y = y; - return this; - } - - /** - * return true if this point is equal to the given point - * @param {number|Point|Vector2d} x - * @param {number} [y] - * @returns {boolean} - */ - equals(...args) { - let _x; - let _y; - if (args.length === 2) { - // x, y - [_x, _y] = args; - } else { - // point - [_x, _y] = [args[0].x, args[0].y]; - } - return this.x === _x && this.y === _y; - } - - /** - * clone this Point - * @returns {Point} new Point - */ - clone() { - return new Point(this.x, this.y); - } -} diff --git a/packages/melonjs/src/geometries/point.ts b/packages/melonjs/src/geometries/point.ts new file mode 100644 index 000000000..0e58e64a8 --- /dev/null +++ b/packages/melonjs/src/geometries/point.ts @@ -0,0 +1,81 @@ +import { createPool } from "../system/pool"; + +/** + * represents a point in a 2d space + */ +export class Point { + /** + * the position of the point on the horizontal axis + * @default 0 + */ + x: number; + + /** + * the position of the point on the vertical axis + * @default 0 + */ + y: number; + + /** + * the shape type (used internally) + * @default "Point" + */ + type: "Point"; + + constructor(x?: number | undefined, y?: number | undefined) { + this.x = x ?? 0; + this.y = y ?? 0; + this.type = "Point"; + } + + /** + * set the Point x and y properties to the given values + * @param x horizontal coordinate + * @param y vertical coordinate + * @returns Reference to this object for method chaining + */ + set(x = 0, y = 0) { + this.x = x; + this.y = y; + return this; + } + + /** + * return true if this point is equal to the given point + * @param x horizontal coordinate + * @param [y] vertical coordinate + * @param args + * @returns + */ + equals(x: number, y: number): boolean; + equals(point: Point): boolean; + equals(xOrPoint: number | Point, y?: number | undefined) { + if (xOrPoint instanceof Point) { + return this.x === xOrPoint.x && this.y === xOrPoint.y; + } + return this.x === xOrPoint && this.y === y; + } + + /** + * clone this Point + * @returns new Point + */ + clone() { + return new Point(this.x, this.y); + } +} + +export const pointPool = createPool< + Point, + [x?: number | undefined, y?: number | undefined] +>((x, y) => { + const instance = new Point(x, y); + + return { + instance: instance, + reset(x = 0, y = 0) { + instance.x = x; + instance.y = y; + }, + }; +}); diff --git a/packages/melonjs/src/geometries/poly.js b/packages/melonjs/src/geometries/poly.js index 6af8fead0..8e2a7d1ab 100644 --- a/packages/melonjs/src/geometries/poly.js +++ b/packages/melonjs/src/geometries/poly.js @@ -1,11 +1,12 @@ -import pool from "./../system/pooling.js"; -import { earcut } from "./earcut.js"; +import { vector2dPool } from "../math/vector2d.ts"; +import { boundsPool } from "./../physics/bounds.ts"; +import { earcut } from "./earcut.ts"; /** * additional import for TypeScript - * @import Vector2d from "./../math/vector2.js"; - * @import Matrix2d from "./../math/matrix2.js"; - * @import Bounds from "./../physics/bounds.js"; + * @import {Vector2d} from "../math/vector2d.js"; + * @import {Matrix2d} from "../math/matrix2d.ts"; + * @import {Bounds} from "./../physics/bounds.ts"; */ /** @@ -27,7 +28,7 @@ export default class Polygon { * origin point of the Polygon * @type {Vector2d} */ - this.pos = pool.pull("Vector2d"); + this.pos = vector2dPool.get(); /** * Array of points defining the Polygon
@@ -109,7 +110,7 @@ export default class Polygon { // array of {x,y} objects this.points.length = 0; // fix potential memory leak vertices.forEach((vertice) => { - this.points.push(pool.pull("Vector2d", vertice.x, vertice.y)); + this.points.push(vector2dPool.get(vertice.x, vertice.y)); }); } } else { @@ -117,7 +118,7 @@ export default class Polygon { const verticesLength = vertices.length; this.points.length = 0; // fix potential memory leak for (let p = 0; p < verticesLength; p += 2) { - this.points.push(pool.pull("Vector2d", vertices[p], vertices[p + 1])); + this.points.push(vector2dPool.get(vertices[p], vertices[p + 1])); } } @@ -225,21 +226,21 @@ export default class Polygon { for (let i = 0; i < len; i++) { let edge = edges[i]; if (typeof edge === "undefined") { - edge = edges[i] = pool.pull("Vector2d"); + edge = edges[i] = vector2dPool.get(); } edge.copy(points[(i + 1) % len]).sub(points[i]); let normal = normals[i]; if (typeof normal === "undefined") { - normal = normals[i] = pool.pull("Vector2d"); + normal = normals[i] = vector2dPool.get(); } normal.copy(edge).perp().normalize(); } // Release any existing Vector2d objects back to the pool for (let i = len; i < edges.length; i++) { - pool.push(edges[i]); - pool.push(normals[i]); + vector2dPool.release(edges[i]); + vector2dPool.release(normals[i]); } // trunc array @@ -412,7 +413,7 @@ export default class Polygon { */ getBounds() { if (typeof this._bounds === "undefined") { - this._bounds = pool.pull("Bounds"); + this._bounds = boundsPool.get(); } return this._bounds; } diff --git a/packages/melonjs/src/geometries/rectangle.js b/packages/melonjs/src/geometries/rectangle.js index 47ede649f..d73db298a 100644 --- a/packages/melonjs/src/geometries/rectangle.js +++ b/packages/melonjs/src/geometries/rectangle.js @@ -1,9 +1,10 @@ +import { vector2dPool } from "../math/vector2d.ts"; import pool from "./../system/pooling.js"; import Polygon from "./poly.js"; /** * additional import for TypeScript - * @import Vector2d from "./../math/vector2.js"; + * @import {Vector2d} from "../math/vector2d.js"; **/ /** @@ -19,10 +20,10 @@ export default class Rect extends Polygon { constructor(x, y, w, h) { // parent constructor super(x, y, [ - pool.pull("Vector2d", 0, 0), // 0, 0 - pool.pull("Vector2d", w, 0), // 1, 0 - pool.pull("Vector2d", w, h), // 1, 1 - pool.pull("Vector2d", 0, h), // 0, 1 + vector2dPool.get(0, 0), // 0, 0 + vector2dPool.get(w, 0), // 1, 0 + vector2dPool.get(w, h), // 1, 1 + vector2dPool.get(0, h), // 0, 1 ]); /** diff --git a/packages/melonjs/src/geometries/toarccanvas.js b/packages/melonjs/src/geometries/toarccanvas.js deleted file mode 100644 index a75832d28..000000000 --- a/packages/melonjs/src/geometries/toarccanvas.js +++ /dev/null @@ -1,104 +0,0 @@ -import { degToRad, pow } from "./../math/math.ts"; - -function correctRadii(signedRx, signedRy, x1p, y1p) { - const prx = Math.abs(signedRx); - const pry = Math.abs(signedRy); - - const A = pow(x1p) / pow(prx) + pow(y1p) / pow(pry); - - const rx = A > 1 ? Math.sqrt(A) * prx : prx; - const ry = A > 1 ? Math.sqrt(A) * pry : pry; - - return [rx, ry]; -} - -function mat2DotVec2([m00, m01, m10, m11], [vx, vy]) { - return [m00 * vx + m01 * vy, m10 * vx + m11 * vy]; -} - -function vec2Add([ux, uy], [vx, vy]) { - return [ux + vx, uy + vy]; -} - -function vec2Scale([a0, a1], scalar) { - return [a0 * scalar, a1 * scalar]; -} - -function vec2Dot([ux, uy], [vx, vy]) { - return ux * vx + uy * vy; -} - -function vec2Mag([ux, uy]) { - return Math.sqrt(ux ** 2 + uy ** 2); -} - -function vec2Angle(u, v) { - const [ux, uy] = u; - const [vx, vy] = v; - const sign = ux * vy - uy * vx >= 0 ? 1 : -1; - return sign * Math.acos(vec2Dot(u, v) / (vec2Mag(u) * vec2Mag(v))); -} - -// From https://svgwg.org/svg2-draft/implnote.html#ArcConversionEndpointToCenter -export function endpointToCenterParameterization( - x1, - y1, - x2, - y2, - largeArcFlag, - sweepFlag, - srx, - sry, - xAxisRotationDeg, -) { - const xAxisRotation = degToRad(xAxisRotationDeg); - - const cosphi = Math.cos(xAxisRotation); - const sinphi = Math.sin(xAxisRotation); - - const [x1p, y1p] = mat2DotVec2( - [cosphi, sinphi, -sinphi, cosphi], - [(x1 - x2) / 2, (y1 - y2) / 2], - ); - - const [rx, ry] = correctRadii(srx, sry, x1p, y1p); - - const sign = largeArcFlag !== sweepFlag ? 1 : -1; - const n = pow(rx) * pow(ry) - pow(rx) * pow(y1p) - pow(ry) * pow(x1p); - const d = pow(rx) * pow(y1p) + pow(ry) * pow(x1p); - - const [cxp, cyp] = vec2Scale( - [(rx * y1p) / ry, (-ry * x1p) / rx], - sign * Math.sqrt(Math.abs(n / d)), - ); - - const [cx, cy] = vec2Add( - mat2DotVec2([cosphi, -sinphi, sinphi, cosphi], [cxp, cyp]), - [(x1 + x2) / 2, (y1 + y2) / 2], - ); - - const a = [(x1p - cxp) / rx, (y1p - cyp) / ry]; - const b = [(-x1p - cxp) / rx, (-y1p - cyp) / ry]; - const startAngle = vec2Angle([1, 0], a); - const deltaAngle0 = vec2Angle(a, b) % (2 * Math.PI); - - const deltaAngle = - !sweepFlag && deltaAngle0 > 0 - ? deltaAngle0 - 2 * Math.PI - : sweepFlag && deltaAngle0 < 0 - ? deltaAngle0 + 2 * Math.PI - : deltaAngle0; - - const endAngle = startAngle + deltaAngle; - - return { - cx, - cy, - rx, - ry, - startAngle, - endAngle, - xAxisRotation, - anticlockwise: deltaAngle < 0, - }; -} diff --git a/packages/melonjs/src/geometries/toarccanvas.ts b/packages/melonjs/src/geometries/toarccanvas.ts new file mode 100644 index 000000000..af9fb70ba --- /dev/null +++ b/packages/melonjs/src/geometries/toarccanvas.ts @@ -0,0 +1,150 @@ +import { degToRad, pow } from "../math/math.ts"; + +/** + * @ignore + */ +function correctRadii( + signedRx: number, + signedRy: number, + x1p: number, + y1p: number, +) { + const prx = Math.abs(signedRx); + const pry = Math.abs(signedRy); + + const A = pow(x1p) / pow(prx) + pow(y1p) / pow(pry); + + const rx = A > 1 ? Math.sqrt(A) * prx : prx; + const ry = A > 1 ? Math.sqrt(A) * pry : pry; + + return [rx, ry]; +} + +/** + * @ignore + */ +function mat2DotVec2( + [m00, m01, m10, m11]: [number, number, number, number], + [vx, vy]: [number, number], +) { + return [m00 * vx + m01 * vy, m10 * vx + m11 * vy] as [number, number]; +} + +/** + * @ignore + */ +function vec2Add([ux, uy]: [number, number], [vx, vy]: [number, number]) { + return [ux + vx, uy + vy]; +} + +/** + * @ignore + */ +function vec2Scale([a0, a1]: [number, number], scalar: number) { + return [a0 * scalar, a1 * scalar]; +} + +/** + * @ignore + */ +function vec2Dot([ux, uy]: [number, number], [vx, vy]: [number, number]) { + return ux * vx + uy * vy; +} + +/** + * @ignore + */ +function vec2Mag([ux, uy]: [number, number]) { + return Math.sqrt(ux ** 2 + uy ** 2); +} + +/** + * @ignore + */ +function vec2Angle(u: [number, number], v: [number, number]) { + const [ux, uy] = u; + const [vx, vy] = v; + const sign = ux * vy - uy * vx >= 0 ? 1 : -1; + return sign * Math.acos(vec2Dot(u, v) / (vec2Mag(u) * vec2Mag(v))); +} + +// From https://svgwg.org/svg2-draft/implnote.html#ArcConversionEndpointToCenter +/** + * Converts endpoint parameterization of an SVG arc to center parameterization. + * + * This function calculates the center (cx, cy), radii (rx, ry), start angle, + * end angle, x-axis rotation, and sweep flag (anticlockwise) of an SVG arc path + * given its endpoint parameterization. + * @param x1 - The x-coordinate of the start point of the arc. + * @param y1 - The y-coordinate of the start point of the arc. + * @param x2 - The x-coordinate of the end point of the arc. + * @param y2 - The y-coordinate of the end point of the arc. + * @param largeArcFlag - The large arc flag. If true, the arc sweep will be greater than 180 degrees. + * @param sweepFlag - The sweep flag. If true, the arc will be drawn in a "positive-angle" direction. + * @param srx - The x-axis radius of the arc. + * @param sry - The y-axis radius of the arc. + * @param xAxisRotationDeg - The rotation angle in degrees of the x-axis of the ellipse relative to the x-axis of the coordinate system. + * @returns An object containing the center coordinates, radii, start and end angles, x-axis rotation, and sweep direction of an SVG arc given its endpoint parameters. + */ +export function endpointToCenterParameterization( + x1: number, + y1: number, + x2: number, + y2: number, + largeArcFlag: boolean, + sweepFlag: boolean, + srx: number, + sry: number, + xAxisRotationDeg: number, +) { + const xAxisRotation = degToRad(xAxisRotationDeg); + + const cosphi = Math.cos(xAxisRotation); + const sinphi = Math.sin(xAxisRotation); + + const [x1p, y1p] = mat2DotVec2( + [cosphi, sinphi, -sinphi, cosphi], + [(x1 - x2) / 2, (y1 - y2) / 2], + ); + + const [rx, ry] = correctRadii(srx, sry, x1p, y1p); + + const sign = largeArcFlag !== sweepFlag ? 1 : -1; + const n = pow(rx) * pow(ry) - pow(rx) * pow(y1p) - pow(ry) * pow(x1p); + const d = pow(rx) * pow(y1p) + pow(ry) * pow(x1p); + + const [cxp, cyp] = vec2Scale( + [(rx * y1p) / ry, (-ry * x1p) / rx], + sign * Math.sqrt(Math.abs(n / d)), + ); + + const [cx, cy] = vec2Add( + mat2DotVec2([cosphi, -sinphi, sinphi, cosphi], [cxp, cyp]), + [(x1 + x2) / 2, (y1 + y2) / 2], + ); + + const a = [(x1p - cxp) / rx, (y1p - cyp) / ry] satisfies [number, number]; + const b = [(-x1p - cxp) / rx, (-y1p - cyp) / ry] satisfies [number, number]; + const startAngle = vec2Angle([1, 0], a); + const deltaAngle0 = vec2Angle(a, b) % (2 * Math.PI); + + const deltaAngle = + !sweepFlag && deltaAngle0 > 0 + ? deltaAngle0 - 2 * Math.PI + : sweepFlag && deltaAngle0 < 0 + ? deltaAngle0 + 2 * Math.PI + : deltaAngle0; + + const endAngle = startAngle + deltaAngle; + + return { + cx, + cy, + rx, + ry, + startAngle, + endAngle, + xAxisRotation, + anticlockwise: deltaAngle < 0, + }; +} diff --git a/packages/melonjs/src/index.js b/packages/melonjs/src/index.js index ee35bfeac..d12f3bb46 100644 --- a/packages/melonjs/src/index.js +++ b/packages/melonjs/src/index.js @@ -3,21 +3,13 @@ import "./polyfill/index.ts"; // class definition import Color from "./math/color.js"; -import Vector2d from "./math/vector2.js"; -import Vector3d from "./math/vector3.js"; -import ObservableVector2d from "./math/observable_vector2.js"; -import ObservableVector3d from "./math/observable_vector3.js"; -import Matrix2d from "./math/matrix2.js"; -import Matrix3d from "./math/matrix3.js"; import Polygon from "./geometries/poly.js"; import Line from "./geometries/line.js"; import Ellipse from "./geometries/ellipse.js"; -import Point from "./geometries/point.js"; import Rect from "./geometries/rectangle.js"; import RoundRect from "./geometries/roundrect.js"; import QuadTree from "./physics/quadtree.js"; import Body from "./physics/body.js"; -import Bounds from "./physics/bounds.js"; import Tween from "./tweens/tween.ts"; import GLShader from "./video/webgl/glshader.js"; import Compositor from "./video/webgl/compositors/compositor.js"; @@ -95,20 +87,22 @@ export * from "./application/scaleMethods.ts"; export * from "./application/settings.ts"; export * from "./version.ts"; export { plugins, save, timer, pool, state }; +export { Vector2d } from "./math/vector2d.ts"; +export { Vector3d } from "./math/vector3d.ts"; +export { Matrix2d } from "./math/matrix2d.ts"; +export { Matrix3d } from "./math/matrix3d.ts"; +export { Point } from "./geometries/point.ts"; +export { Bounds } from "./physics/bounds.ts"; +export { createObservableVector2d } from "./math/observableVector2d.ts"; +export { createObservableVector3d } from "./math/observableVector3d.ts"; +export { getPool } from "./pool.ts"; // export all class definition export { Color, - Vector2d, - Vector3d, - ObservableVector2d, - ObservableVector3d, - Matrix2d, - Matrix3d, Polygon, Line, Ellipse, - Point, Rect, RoundRect, Tween, @@ -124,7 +118,6 @@ export { TextureAtlas, Renderable, Body, - Bounds, Text, BitmapText, BitmapTextData, @@ -226,19 +219,11 @@ export function boot() { pool.register("me.BitmapTextData", BitmapTextData, true); pool.register("me.ImageLayer", ImageLayer); pool.register("me.ColorLayer", ColorLayer, true); - pool.register("me.Vector2d", Vector2d, true); - pool.register("me.Vector3d", Vector3d, true); - pool.register("me.ObservableVector2d", ObservableVector2d, true); - pool.register("me.ObservableVector3d", ObservableVector3d, true); - pool.register("me.Matrix2d", Matrix2d, true); - pool.register("me.Matrix3d", Matrix3d, true); pool.register("me.Rect", Rect, true); pool.register("me.RoundRect", RoundRect, true); pool.register("me.Polygon", Polygon, true); pool.register("me.Line", Line, true); - pool.register("me.Point", Point, true); pool.register("me.Ellipse", Ellipse, true); - pool.register("me.Bounds", Bounds, true); // duplicate all entries if use with no namespace (e.g. es6) pool.register("Entity", Entity); @@ -256,19 +241,11 @@ export function boot() { pool.register("BitmapTextData", BitmapTextData, true); pool.register("ImageLayer", ImageLayer); pool.register("ColorLayer", ColorLayer, true); - pool.register("Vector2d", Vector2d, true); - pool.register("Vector3d", Vector3d, true); - pool.register("ObservableVector2d", ObservableVector2d, true); - pool.register("ObservableVector3d", ObservableVector3d, true); - pool.register("Matrix2d", Matrix2d, true); - pool.register("Matrix3d", Matrix3d, true); pool.register("Rect", Rect, true); pool.register("RoundRect", RoundRect, true); pool.register("Polygon", Polygon, true); pool.register("Line", Line, true); - pool.register("Point", Point, true); pool.register("Ellipse", Ellipse, true); - pool.register("Bounds", Bounds, true); pool.register("CanvasRenderTarget", CanvasRenderTarget, true); // publish Boot notification diff --git a/packages/melonjs/src/input/pointer.js b/packages/melonjs/src/input/pointer.js index 4cd307d2f..14546ee2f 100644 --- a/packages/melonjs/src/input/pointer.js +++ b/packages/melonjs/src/input/pointer.js @@ -1,5 +1,5 @@ -import Vector2d from "./../math/vector2.js"; -import Bounds from "./../physics/bounds.js"; +import { Vector2d } from "../math/vector2d.ts"; +import { Bounds } from "./../physics/bounds.ts"; import { game } from "../index.js"; import { globalToLocal } from "./input.js"; import { locked } from "./pointerevent.js"; diff --git a/packages/melonjs/src/input/pointerevent.js b/packages/melonjs/src/input/pointerevent.js index a9859cc00..d28d853fe 100644 --- a/packages/melonjs/src/input/pointerevent.js +++ b/packages/melonjs/src/input/pointerevent.js @@ -4,7 +4,6 @@ import { renderer } from "./../video/video.js"; import { throttle } from "./../utils/function.ts"; import { remove } from "./../utils/array.ts"; import timer from "./../system/timer.ts"; -import pool from "./../system/pooling.js"; import * as device from "./../system/device.js"; import Pointer from "./pointer.js"; import Rect from "./../geometries/rectangle.js"; @@ -14,9 +13,10 @@ import { POINTERLOCKCHANGE, POINTERMOVE, } from "../system/event.ts"; +import { vector2dPool } from "../math/vector2d.ts"; /** - * @import Vector2d from "./../math/vector2.js"; + * @import {Vector2d} from "../math/vector2d.js"; */ /** @@ -594,7 +594,7 @@ export function hasRegisteredEvents() { * }; */ export function globalToLocal(x, y, v) { - v = v || pool.pull("Vector2d"); + v = v || vector2dPool.get(); const rect = device.getElementBounds(renderer.getCanvas()); const pixelRatio = globalThis.devicePixelRatio || 1; x -= rect.left + (globalThis.pageXOffset || 0); diff --git a/packages/melonjs/src/level/level.js b/packages/melonjs/src/level/level.js index bbd266f18..9723a3ba8 100644 --- a/packages/melonjs/src/level/level.js +++ b/packages/melonjs/src/level/level.js @@ -63,7 +63,7 @@ function safeLoadLevel(levelId, options, restart) { */ function loadTMXLevel(levelId, container, flatten, setViewportBounds) { const level = levels[levelId]; - + console.log(level); // reset the GUID generator // and pass the level id as parameter resetGUID(levelId, level.nextobjectid); diff --git a/packages/melonjs/src/level/tiled/TMXLayer.js b/packages/melonjs/src/level/tiled/TMXLayer.js index e01974c6b..ec211d127 100644 --- a/packages/melonjs/src/level/tiled/TMXLayer.js +++ b/packages/melonjs/src/level/tiled/TMXLayer.js @@ -1,9 +1,9 @@ import { createCanvas } from "./../../video/video.js"; -import pool from "./../../system/pooling.js"; import * as TMXUtils from "./TMXUtils.js"; import Tile from "./TMXTile.js"; import Renderable from "./../../renderable/renderable.js"; import CanvasRenderer from "./../../video/canvas/canvas_renderer"; +import { vector2dPool } from "../../math/vector2d.ts"; /** * Create required arrays for the given layer object @@ -304,10 +304,10 @@ export default class TMXLayer extends Renderable { const coord = this.getRenderer().pixelToTileCoords( x, y, - pool.pull("Vector2d"), + vector2dPool.get(), ); tile = this.cellAt(coord.x, coord.y); - pool.push(coord); + vector2dPool.release(coord); } return tile; } diff --git a/packages/melonjs/src/level/tiled/TMXObject.js b/packages/melonjs/src/level/tiled/TMXObject.js index c17dc2c85..a59c09d35 100644 --- a/packages/melonjs/src/level/tiled/TMXObject.js +++ b/packages/melonjs/src/level/tiled/TMXObject.js @@ -2,6 +2,8 @@ import pool from "./../../system/pooling.js"; import { applyTMXProperties } from "./TMXUtils.js"; import Tile from "./TMXTile.js"; import { degToRad } from "./../../math/math.ts"; +import { vector2dPool } from "../../math/vector2d.ts"; +import { pointPool } from "../../geometries/point.ts"; /** * a TMX Object defintion, as defined in Tiled @@ -223,7 +225,7 @@ export default class TMXObject { .rotate(this.rotation), ); } else if (this.isPoint === true) { - shapes.push(pool.pull("Point", this.x, this.y)); + shapes.push(pointPool.get(this.x, this.y)); } else { // add a polygon if (this.isPolygon === true) { @@ -246,8 +248,8 @@ export default class TMXObject { for (let i = 0; i < segments; i++) { // clone the value before, as [i + 1] // is reused later by the next segment - p1 = pool.pull("Vector2d", p[i].x, p[i].y); - p2 = pool.pull("Vector2d", p[i + 1].x, p[i + 1].y); + p1 = vector2dPool.get(p[i].x, p[i].y); + p2 = vector2dPool.get(p[i + 1].x, p[i + 1].y); if (this.rotation !== 0) { p1 = p1.rotate(this.rotation); p2 = p2.rotate(this.rotation); @@ -261,10 +263,10 @@ export default class TMXObject { shapes.push( pool .pull("Polygon", 0, 0, [ - pool.pull("Vector2d"), - pool.pull("Vector2d", this.width, 0), - pool.pull("Vector2d", this.width, this.height), - pool.pull("Vector2d", 0, this.height), + vector2dPool.get(), + vector2dPool.get(this.width, 0), + vector2dPool.get(this.width, this.height), + vector2dPool.get(0, this.height), ]) .rotate(this.rotation), ); diff --git a/packages/melonjs/src/level/tiled/TMXTile.js b/packages/melonjs/src/level/tiled/TMXTile.js index 0606183c7..bde3b577d 100644 --- a/packages/melonjs/src/level/tiled/TMXTile.js +++ b/packages/melonjs/src/level/tiled/TMXTile.js @@ -1,6 +1,6 @@ -import Matrix2d from "./../../math/matrix2.js"; +import { Matrix2d } from "../../math/matrix2d.ts"; import Sprite from "./../../renderable/sprite.js"; -import Bounds from "./../../physics/bounds.js"; +import { Bounds } from "./../../physics/bounds.ts"; import { TMX_FLIP_V, TMX_FLIP_H, diff --git a/packages/melonjs/src/level/tiled/TMXTileMap.js b/packages/melonjs/src/level/tiled/TMXTileMap.js index 682d6c0b2..c006fa94f 100644 --- a/packages/melonjs/src/level/tiled/TMXTileMap.js +++ b/packages/melonjs/src/level/tiled/TMXTileMap.js @@ -13,6 +13,7 @@ import { COLLISION_GROUP } from "./constants.js"; import { getNewTMXRenderer } from "./renderer/autodetect.js"; import { warning } from "../../lang/console.js"; import { eventEmitter, VIEWPORT_ONRESIZE } from "../../system/event.ts"; +import { vector2dPool } from "../../math/vector2d.ts"; /** * read the layer Data @@ -48,11 +49,7 @@ function readImageLayer(map, data, z) { { name: data.name, image: data.image, - ratio: pool.pull( - "Vector2d", - +data.parallaxx || 1.0, - +data.parallaxy || 1.0, - ), + ratio: vector2dPool.get(+data.parallaxx || 1.0, +data.parallaxy || 1.0), // convert to melonJS color format (note: this should be done earlier when parsing data) tint: typeof data.tintcolor !== "undefined" @@ -483,9 +480,9 @@ export default class TMXTileMap { shape = settings.shapes; if (typeof shape === "undefined") { shape = pool.pull("Polygon", 0, 0, [ - pool.pull("Vector2d", 0, 0), - pool.pull("Vector2d", this.width, 0), - pool.pull("Vector2d", this.width, this.height), + vector2dPool.get(0, 0), + vector2dPool.get(this.width, 0), + vector2dPool.get(this.width, this.height), ]); } // check if a me.Tile object is embedded @@ -511,9 +508,9 @@ export default class TMXTileMap { shape = settings.shapes; if (typeof shape === "undefined") { shape = pool.pull("Polygon", 0, 0, [ - pool.pull("Vector2d", 0, 0), - pool.pull("Vector2d", this.width, 0), - pool.pull("Vector2d", this.width, this.height), + vector2dPool.get(0, 0), + vector2dPool.get(this.width, 0), + vector2dPool.get(this.width, this.height), ]); } obj.anchorPoint.set(0, 0); diff --git a/packages/melonjs/src/level/tiled/TMXTileset.js b/packages/melonjs/src/level/tiled/TMXTileset.js index 65e5654f4..452fa0bc7 100644 --- a/packages/melonjs/src/level/tiled/TMXTileset.js +++ b/packages/melonjs/src/level/tiled/TMXTileset.js @@ -1,4 +1,4 @@ -import Vector2d from "./../../math/vector2.js"; +import { Vector2d } from "../../math/vector2d.ts"; import { renderer } from "./../../video/video.js"; import timer from "./../../system/timer.ts"; import { getTMX, getImage } from "./../../loader/loader.js"; diff --git a/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js index f5308bbd4..e598ede3b 100644 --- a/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js +++ b/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js @@ -1,7 +1,7 @@ -import Vector2d from "./../../../math/vector2.js"; -import pool from "./../../../system/pooling.js"; +import { Vector2d, vector2dPool } from "../../../math/vector2d.ts"; import TMXRenderer from "./TMXRenderer.js"; import TMXLayer from "./../TMXLayer.js"; +import { boundsPool } from "../../../physics/bounds.ts"; // scope global variables & constants const offsetsStaggerX = [ @@ -69,8 +69,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer { * @ignore */ getBounds(layer) { - const bounds = - layer instanceof TMXLayer ? pool.pull("Bounds") : this.bounds; + const bounds = layer instanceof TMXLayer ? boundsPool.get() : this.bounds; // The map size is the same regardless of which indexes are shifted. if (this.staggerX) { @@ -215,15 +214,13 @@ export default class TMXHexagonalRenderer extends TMXRenderer { } // Start with the coordinates of a grid-aligned tile - const referencePoint = pool.pull( - "Vector2d", + const referencePoint = vector2dPool.get( Math.floor(x / (this.columnwidth * 2)), Math.floor(y / (this.rowheight * 2)), ); // Relative x and y position on the base square of the grid-aligned tile - const rel = pool.pull( - "Vector2d", + const rel = vector2dPool.get( x - referencePoint.x * (this.columnwidth * 2), y - referencePoint.y * (this.rowheight * 2), ); @@ -283,8 +280,8 @@ export default class TMXHexagonalRenderer extends TMXRenderer { referencePoint.y + offsets[nearest].y, ); - pool.push(referencePoint); - pool.push(rel); + vector2dPool.release(referencePoint); + vector2dPool.release(rel); return ret; } @@ -335,7 +332,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer { */ drawTile(renderer, x, y, tmxTile) { const tileset = tmxTile.tileset; - const point = this.tileToPixelCoords(x, y, pool.pull("Vector2d")); + const point = this.tileToPixelCoords(x, y, vector2dPool.get()); // draw the tile tileset.drawTile( @@ -345,7 +342,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer { tmxTile, ); - pool.push(point); + vector2dPool.release(point); } /** @@ -359,7 +356,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer { const startTile = this.pixelToTileCoords( rect.pos.x, rect.pos.y, - pool.pull("Vector2d"), + vector2dPool.get(), ); // Compensate for the layer position @@ -369,7 +366,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer { let startPos = this.tileToPixelCoords( startTile.x + layer.pos.x, startTile.y + layer.pos.y, - pool.pull("Vector2d"), + vector2dPool.get(), ); const rowTile = startTile.clone(); @@ -433,8 +430,8 @@ export default class TMXHexagonalRenderer extends TMXRenderer { startPos.y += this.rowheight; } - pool.push(rowTile); - pool.push(rowPos); + vector2dPool.release(rowTile); + vector2dPool.release(rowPos); } else { //ensure we are in the valid tile range startTile.x = Math.max(0, startTile.x); @@ -470,11 +467,11 @@ export default class TMXHexagonalRenderer extends TMXRenderer { } startPos.y += this.rowheight; } - pool.push(rowTile); - pool.push(rowPos); + vector2dPool.release(rowTile); + vector2dPool.release(rowPos); } - pool.push(startTile); - pool.push(startPos); + vector2dPool.release(startTile); + vector2dPool.release(startPos); } } diff --git a/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js index b259deeff..650bae468 100644 --- a/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js +++ b/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js @@ -1,7 +1,7 @@ -import Vector2d from "./../../../math/vector2.js"; -import pool from "./../../../system/pooling.js"; +import { Vector2d, vector2dPool } from "../../../math/vector2d.ts"; import TMXRenderer from "./TMXRenderer.js"; import TMXLayer from "./../TMXLayer.js"; +import { boundsPool } from "../../../physics/bounds.ts"; /** * an Isometric Map Renderder @@ -31,8 +31,7 @@ export default class TMXIsometricRenderer extends TMXRenderer { * @ignore */ getBounds(layer) { - const bounds = - layer instanceof TMXLayer ? pool.pull("Bounds") : this.bounds; + const bounds = layer instanceof TMXLayer ? boundsPool.get() : this.bounds; bounds.setMinMax( 0, 0, @@ -74,14 +73,14 @@ export default class TMXIsometricRenderer extends TMXRenderer { adjustPosition(obj) { const tileX = obj.x / this.hTilewidth; const tileY = obj.y / this.tileheight; - const isoPos = pool.pull("Vector2d"); + const isoPos = vector2dPool.get(); this.tileToPixelCoords(tileX, tileY, isoPos); obj.x = isoPos.x; obj.y = isoPos.y; - pool.push(isoPos); + vector2dPool.release(isoPos); } /** @@ -111,25 +110,25 @@ export default class TMXIsometricRenderer extends TMXRenderer { const rowItr = this.pixelToTileCoords( rect.pos.x - tileset.tilewidth, rect.pos.y - tileset.tileheight, - pool.pull("Vector2d"), + vector2dPool.get(), ).floorSelf(); const tileEnd = this.pixelToTileCoords( rect.pos.x + rect.width + tileset.tilewidth, rect.pos.y + rect.height + tileset.tileheight, - pool.pull("Vector2d"), + vector2dPool.get(), ).ceilSelf(); const rectEnd = this.tileToPixelCoords( tileEnd.x, tileEnd.y, - pool.pull("Vector2d"), + vector2dPool.get(), ); // Determine the tile and pixel coordinates to start at const startPos = this.tileToPixelCoords( rowItr.x, rowItr.y, - pool.pull("Vector2d"), + vector2dPool.get(), ); startPos.x -= this.hTilewidth; startPos.y += this.tileheight; @@ -199,10 +198,10 @@ export default class TMXIsometricRenderer extends TMXRenderer { } } - pool.push(columnItr); - pool.push(rowItr); - pool.push(tileEnd); - pool.push(rectEnd); - pool.push(startPos); + vector2dPool.release(columnItr); + vector2dPool.release(rowItr); + vector2dPool.release(tileEnd); + vector2dPool.release(rectEnd); + vector2dPool.release(startPos); } } diff --git a/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js index dd34f6451..01ea6db0a 100644 --- a/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js +++ b/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js @@ -1,5 +1,4 @@ -import Vector2d from "./../../../math/vector2.js"; -import pool from "./../../../system/pooling.js"; +import { Vector2d, vector2dPool } from "../../../math/vector2d.ts"; import TMXRenderer from "./TMXRenderer.js"; /** @@ -80,13 +79,13 @@ export default class TMXOrthogonalRenderer extends TMXRenderer { const start = this.pixelToTileCoords( Math.max(rect.pos.x - (layer.maxTileSize.width - layer.tilewidth), 0), Math.max(rect.pos.y - (layer.maxTileSize.height - layer.tileheight), 0), - pool.pull("Vector2d"), + vector2dPool.get(), ).floorSelf(); const end = this.pixelToTileCoords( rect.pos.x + rect.width + this.tilewidth, rect.pos.y + rect.height + this.tileheight, - pool.pull("Vector2d"), + vector2dPool.get(), ).ceilSelf(); //ensure we are in the valid tile range @@ -126,7 +125,7 @@ export default class TMXOrthogonalRenderer extends TMXRenderer { } } - pool.push(start); - pool.push(end); + vector2dPool.release(start); + vector2dPool.release(end); } } diff --git a/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js index 6eaa2d107..8b2706217 100644 --- a/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js +++ b/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js @@ -1,6 +1,5 @@ -import pool from "./../../../system/pooling.js"; import TMXLayer from "./../TMXLayer.js"; -import Bounds from "./../../../physics/bounds.js"; +import { Bounds, boundsPool } from "./../../../physics/bounds.ts"; /** * The map renderer base class @@ -44,8 +43,7 @@ export default class TMXRenderer { * @returns {Bounds} */ getBounds(layer) { - const bounds = - layer instanceof TMXLayer ? pool.pull("Bounds") : this.bounds; + const bounds = layer instanceof TMXLayer ? boundsPool.get() : this.bounds; bounds.setMinMax( 0, 0, diff --git a/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js index 78cbdd727..6d8eccd14 100644 --- a/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js +++ b/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js @@ -1,5 +1,4 @@ -import Vector2d from "./../../../math/vector2.js"; -import pool from "./../../../system/pooling.js"; +import { Vector2d, vector2dPool } from "../../../math/vector2d.ts"; import TMXHexagonalRenderer from "./TMXHexagonalRenderer.js"; import { degToRad } from "./../../../math/math.ts"; @@ -32,8 +31,7 @@ export default class TMXStaggeredRenderer extends TMXHexagonalRenderer { } // Start with the coordinates of a grid-aligned tile - let referencePoint = pool.pull( - "Vector2d", + let referencePoint = vector2dPool.get( Math.floor(alignedX / this.tilewidth), Math.floor(alignedY / this.tileheight), ); @@ -52,8 +50,7 @@ export default class TMXStaggeredRenderer extends TMXHexagonalRenderer { } // Relative x and y position on the base square of the grid-aligned tile - const rel = pool.pull( - "Vector2d", + const rel = vector2dPool.get( alignedX - referencePoint.x * this.tilewidth, alignedY - referencePoint.y * this.tileheight, ); @@ -105,8 +102,8 @@ export default class TMXStaggeredRenderer extends TMXHexagonalRenderer { .rotate(degToRad(-45)) .add(referencePoint); - pool.push(referencePoint); - pool.push(rel); + vector2dPool.release(referencePoint); + vector2dPool.release(rel); return ret; } diff --git a/packages/melonjs/src/math/matrix2.js b/packages/melonjs/src/math/matrix2.js deleted file mode 100644 index 195812733..000000000 --- a/packages/melonjs/src/math/matrix2.js +++ /dev/null @@ -1,509 +0,0 @@ -import pool from "./../system/pooling.js"; - -/** - * additional import for TypeScript - * @import Matrix3d from "./matrix3.js"; - * @import Vector2d from "./vector2.js"; - * @import Vector3d from "./vector3.js"; - */ - -/** - * a Matrix2d Object.
- * the identity matrix and parameters position :
- * - */ -export default class Matrix2d { - /** - * @param {(Matrix2d|Matrix3d|...number)} args - an instance of me.Matrix2d or me.Matrix3d to copy from, or individual matrix components (See {@link Matrix2d.setTransform}). If not arguments are given, the matrix will be set to Identity. - */ - constructor(...args) { - /** - * The matrix values - * @ignore - */ - this.val = undefined; - this.onResetEvent(...args); - } - - /** - * @ignore - */ - onResetEvent() { - const arg0 = arguments[0]; - const argLen = arguments.length; - - if (typeof this.val === "undefined") { - this.val = new Float32Array(9); - } - - if (argLen === 1) { - // matrix2d or matrix3d - if (arg0.val.length === 9) { - this.copy(arg0); - } else if (arg0.val.length === 16) { - this.fromMat3d(arguments[0]); - } else { - throw new Error("invalid Matrix2d constructor parameter"); - } - } else if (arguments.length >= 6) { - // individual components - this.setTransform.apply(this, arguments); - } else { - // invalid or no arguments - this.identity(); - } - } - - /** - * tx component of the matrix - * @type {number} - * @see {@link translate} - */ - get tx() { - return this.val[6]; - } - - /** - * ty component of the matrix - * @type {number} - * @see {@link translate} - */ - get ty() { - return this.val[7]; - } - - /** - * reset the transformation matrix to the identity matrix (no transformation).
- * the identity matrix and parameters position :
- * - * @returns {Matrix2d} Reference to this object for method chaining - */ - identity() { - this.setTransform(1, 0, 0, 0, 1, 0, 0, 0, 1); - return this; - } - - /** - * set the matrix to the specified value - * @param {number} a - * @param {number} b - * @param {number} c - * @param {number} d - * @param {number} e - * @param {number} f - * @param {number} [g=0] - * @param {number} [h=0] - * @param {number} [i=1] - * @returns {Matrix2d} Reference to this object for method chaining - */ - setTransform() { - const a = this.val; - - if (arguments.length === 9) { - a[0] = arguments[0]; // a - m00 - a[1] = arguments[1]; // b - m10 - a[2] = arguments[2]; // c - m20 - a[3] = arguments[3]; // d - m01 - a[4] = arguments[4]; // e - m11 - a[5] = arguments[5]; // f - m21 - a[6] = arguments[6]; // g - m02 - a[7] = arguments[7]; // h - m12 - a[8] = arguments[8]; // i - m22 - } else if (arguments.length === 6) { - a[0] = arguments[0]; // a - a[1] = arguments[2]; // c - a[2] = arguments[4]; // e - a[3] = arguments[1]; // b - a[4] = arguments[3]; // d - a[5] = arguments[5]; // f - a[6] = 0; // g - a[7] = 0; // h - a[8] = 1; // i - } - - return this; - } - - /** - * Multiplies the current transformation with the matrix described by the arguments of this method - * @param {number} a - * @param {number} b - * @param {number} c - * @param {number} d - * @param {number} e - * @param {number} f - * @returns {Matrix2d} Reference to this object for method chaining - */ - transform(a, b, c, d, e, f) { - const v = this.val; - const a0 = v[0]; - const a1 = v[1]; - const a3 = v[3]; - const a4 = v[4]; - const b0 = a; - const b1 = b; - const b3 = c; - const b4 = d; - const b6 = e; - const b7 = f; - - v[0] = a0 * b0 + a3 * b1; - v[1] = a1 * b0 + a4 * b1; - v[3] = a0 * b3 + a3 * b4; - v[4] = a1 * b3 + a4 * b4; - v[6] += a0 * b6 + a3 * b7; - v[7] += a1 * b6 + a4 * b7; - - return this; - } - - /** - * Copies over the values from another me.Matrix2d. - * @param {Matrix2d} m - the matrix object to copy from - * @returns {Matrix2d} Reference to this object for method chaining - */ - copy(m) { - this.val.set(m.val); - return this; - } - - /** - * Copies over the upper-left 3x3 values from the given me.Matrix3d - * @param {Matrix3d} m - the matrix object to copy from - * @returns {Matrix2d} Reference to this object for method chaining - */ - fromMat3d(m) { - const b = m.val; - const a = this.val; - - a[0] = b[0]; - a[1] = b[1]; - a[2] = b[2]; - a[3] = b[4]; - a[4] = b[5]; - a[5] = b[6]; - a[6] = b[8]; - a[7] = b[9]; - a[8] = b[10]; - - return this; - } - - /** - * multiply both matrix - * @param {Matrix2d} m - the other matrix - * @returns {Matrix2d} Reference to this object for method chaining - */ - multiply(m) { - const b = m.val; - const a = this.val; - const a0 = a[0]; - const a1 = a[1]; - const a3 = a[3]; - const a4 = a[4]; - const b0 = b[0]; - const b1 = b[1]; - const b3 = b[3]; - const b4 = b[4]; - const b6 = b[6]; - const b7 = b[7]; - - a[0] = a0 * b0 + a3 * b1; - a[1] = a1 * b0 + a4 * b1; - a[3] = a0 * b3 + a3 * b4; - a[4] = a1 * b3 + a4 * b4; - a[6] += a0 * b6 + a3 * b7; - a[7] += a1 * b6 + a4 * b7; - - return this; - } - - /** - * Transpose the value of this matrix. - * @returns {Matrix2d} Reference to this object for method chaining - */ - transpose() { - const a = this.val; - const a1 = a[1]; - const a2 = a[2]; - const a5 = a[5]; - - a[1] = a[3]; - a[2] = a[6]; - a[3] = a1; - a[5] = a[7]; - a[6] = a2; - a[7] = a5; - - return this; - } - - /** - * invert this matrix, causing it to apply the opposite transformation. - * @returns {Matrix2d} Reference to this object for method chaining - */ - invert() { - const val = this.val; - - const a = val[0]; - const b = val[1]; - const c = val[2]; - const d = val[3]; - const e = val[4]; - const f = val[5]; - const g = val[6]; - const h = val[7]; - const i = val[8]; - - const ta = i * e - f * h; - const td = f * g - i * d; - const tg = h * d - e * g; - - const n = a * ta + b * td + c * tg; - - val[0] = ta / n; - val[1] = (c * h - i * b) / n; - val[2] = (f * b - c * e) / n; - - val[3] = td / n; - val[4] = (i * a - c * g) / n; - val[5] = (c * d - f * a) / n; - - val[6] = tg / n; - val[7] = (b * g - h * a) / n; - val[8] = (e * a - b * d) / n; - - return this; - } - - /** - * apply the current transform to the given 2d or 3d vector - * @param {Vector2d|Vector3d} v - the vector object to be transformed - * @returns {Vector2d|Vector3d} result vector object. - */ - apply(v) { - const a = this.val; - const x = v.x; - const y = v.y; - const z = typeof v.z !== "undefined" ? v.z : 1; - - v.x = x * a[0] + y * a[3] + z * a[6]; - v.y = x * a[1] + y * a[4] + z * a[7]; - - if (typeof v.z !== "undefined") { - v.z = x * a[2] + y * a[5] + z * a[8]; - } - - return v; - } - - /** - * apply the inverted current transform to the given 2d vector - * @param {Vector2d} v - the vector object to be transformed - * @returns {Vector2d} result vector object. - */ - applyInverse(v) { - const a = this.val; - const x = v.x; - const y = v.y; - - const invD = 1 / (a[0] * a[4] + a[3] * -a[1]); - - v.x = - a[4] * invD * x + -a[3] * invD * y + (a[7] * a[3] - a[6] * a[4]) * invD; - v.y = - a[0] * invD * y + -a[1] * invD * x + (-a[7] * a[0] + a[6] * a[1]) * invD; - - return v; - } - - /** - * scale the matrix - * @param {number} x - a number representing the abscissa of the scaling vector. - * @param {number} [y=x] - a number representing the ordinate of the scaling vector. - * @returns {Matrix2d} Reference to this object for method chaining - */ - scale(x, y = x) { - const a = this.val; - - a[0] *= x; - a[1] *= x; - //a[2] *= x; // z axis remains unchanged for 2d scale operation - - a[3] *= y; - a[4] *= y; - //a[5] *= y; // w axis remains unchanged for 2d scale operation - - return this; - } - - /** - * adds a 2D scaling transformation. - * @param {Vector2d} v - scaling vector - * @returns {Matrix2d} Reference to this object for method chaining - */ - scaleV(v) { - return this.scale(v.x, v.y); - } - - /** - * specifies a 2D scale operation using the [sx, 1] scaling vector - * @param {number} x - x scaling vector - * @returns {Matrix2d} Reference to this object for method chaining - */ - scaleX(x) { - return this.scale(x, 1); - } - - /** - * specifies a 2D scale operation using the [1,sy] scaling vector - * @param {number} y - y scaling vector - * @returns {Matrix2d} Reference to this object for method chaining - */ - scaleY(y) { - return this.scale(1, y); - } - - /** - * rotate the matrix (counter-clockwise) by the specified angle (in radians). - * @param {number} angle - Rotation angle in radians. - * @returns {Matrix2d} Reference to this object for method chaining - */ - rotate(angle) { - if (angle !== 0) { - const a = this.val; - const a00 = a[0]; - const a01 = a[1]; - const a02 = a[2]; - const a10 = a[3]; - const a11 = a[4]; - const a12 = a[5]; - const s = Math.sin(angle); - const c = Math.cos(angle); - - a[0] = c * a00 + s * a10; - a[1] = c * a01 + s * a11; - a[2] = c * a02 + s * a12; - - a[3] = c * a10 - s * a00; - a[4] = c * a11 - s * a01; - a[5] = c * a12 - s * a02; - } - return this; - } - - /** - * translate the matrix position on the horizontal and vertical axis - * @param {number|Vector2d} x - the x coordindates or a vector to translate the matrix by - * @param {number} [y] - the y coordindates to translate the matrix by - * @returns {Matrix2d} Reference to this object for method chaining - */ - translate() { - const a = this.val; - let _x; - let _y; - - if (arguments.length === 2) { - // x, y - _x = arguments[0]; - _y = arguments[1]; - } else { - // vector - _x = arguments[0].x; - _y = arguments[0].y; - } - - a[6] += a[0] * _x + a[3] * _y; - a[7] += a[1] * _x + a[4] * _y; - - return this; - } - - /** - * returns true if the matrix is an identity matrix. - * @returns {boolean} - */ - isIdentity() { - const a = this.val; - - return ( - a[0] === 1 && - a[1] === 0 && - a[2] === 0 && - a[3] === 0 && - a[4] === 1 && - a[5] === 0 && - a[6] === 0 && - a[7] === 0 && - a[8] === 1 - ); - } - - /** - * return true if the two matrices are identical - * @param {Matrix2d} m - the other matrix - * @returns {boolean} true if both are equals - */ - equals(m) { - const b = m.val; - const a = this.val; - - return ( - a[0] === b[0] && - a[1] === b[1] && - a[2] === b[2] && - a[3] === b[3] && - a[4] === b[4] && - a[5] === b[5] && - a[6] === b[6] && - a[7] === b[7] && - a[8] === b[8] - ); - } - - /** - * Clone the Matrix - * @returns {Matrix2d} - */ - clone() { - return pool.pull("Matrix2d", this); - } - - /** - * return an array representation of this Matrix - * @returns {Float32Array} - */ - toArray() { - return this.val; - } - - /** - * convert the object to a string representation - * @returns {string} - */ - toString() { - const a = this.val; - - return ( - "me.Matrix2d(" + - a[0] + - ", " + - a[1] + - ", " + - a[2] + - ", " + - a[3] + - ", " + - a[4] + - ", " + - a[5] + - ", " + - a[6] + - ", " + - a[7] + - ", " + - a[8] + - ")" - ); - } -} diff --git a/packages/melonjs/src/math/matrix2d.ts b/packages/melonjs/src/math/matrix2d.ts new file mode 100644 index 000000000..25e17a0c4 --- /dev/null +++ b/packages/melonjs/src/math/matrix2d.ts @@ -0,0 +1,476 @@ +import { Point } from "../geometries/point.js"; +import { createPool } from "../system/pool.js"; +import { Matrix3d } from "./matrix3d.js"; +import { Vector2d } from "./vector2d.js"; +import { Vector3d } from "./vector3d.js"; + +type ConstructorArg = + | [Matrix2d] + | [Matrix3d] + | [number, number, number, number, number, number] + | [number, number, number, number, number, number, number, number, number] + | [undefined] + | []; + +const reset = (instance: Matrix2d, ...value: ConstructorArg) => { + if (value[0] instanceof Matrix3d) { + instance.fromMat3d(value[0]); + } else if (value[0] instanceof Matrix2d) { + instance.copy(value[0]); + } else if (typeof value[0] === "number") { + instance.setTransform(...value); + } else { + instance.identity(); + } +}; + +/** + * a Matrix2d Object.
+ * the identity matrix and parameters position :
+ * + */ +export class Matrix2d { + /** + * The matrix values + */ + val: Float32Array; + + /** + * Constructs a new Matrix2d object. + * @param value - The values to initialize the matrix with. + */ + constructor(...value: ConstructorArg) { + this.val = new Float32Array(9); + reset(this, ...value); + } + + /** + * Gets the tx component of the matrix. + * @returns The tx component of the matrix. + */ + get tx() { + return this.val[6]; + } + + /** + * Gets the ty component of the matrix. + * @returns The ty component of the matrix. + */ + get ty() { + return this.val[7]; + } + + /** + * reset the transformation matrix to the identity matrix (no transformation).
+ * the identity matrix and parameters position :
+ * + * @returns Reference to this object for method chaining + */ + identity() { + this.setTransform(1, 0, 0, 0, 1, 0, 0, 0, 1); + return this; + } + + /** + * Set the matrix to the specified value. + * @param values - The matrix components. + * @returns Reference to this object for method chaining + */ + setTransform( + ...values: + | [number, number, number, number, number, number] + | [number, number, number, number, number, number, number, number, number] + ) { + if (values.length === 9) { + this.val[0] = values[0]; // a - m00 + this.val[1] = values[1]; // b - m10 + this.val[2] = values[2]; // c - m20 + this.val[3] = values[3]; // d - m01 + this.val[4] = values[4]; // e - m11 + this.val[5] = values[5]; // f - m21 + this.val[6] = values[6]; // g - m02 + this.val[7] = values[7]; // h - m12 + this.val[8] = values[8]; // i - m22 + } else if (values.length === 6) { + this.val[0] = values[0]; // a + this.val[1] = values[2]; // c + this.val[2] = values[4]; // e + this.val[3] = values[1]; // b + this.val[4] = values[3]; // d + this.val[5] = values[5]; // f + this.val[6] = 0; // g + this.val[7] = 0; // h + this.val[8] = 1; // i + } + + return this; + } + + /** + * Multiplies the current transformation with the matrix described by the arguments of this method. + * @param a a component + * @param b b component + * @param c c component + * @param d d component + * @param e e component + * @param f f component + * @returns Reference to this object for method chaining + */ + transform(a: number, b: number, c: number, d: number, e: number, f: number) { + const v = this.val; + const a0 = v[0]; + const a1 = v[1]; + const a3 = v[3]; + const a4 = v[4]; + const b0 = a; + const b1 = b; + const b3 = c; + const b4 = d; + const b6 = e; + const b7 = f; + + v[0] = a0 * b0 + a3 * b1; + v[1] = a1 * b0 + a4 * b1; + v[3] = a0 * b3 + a3 * b4; + v[4] = a1 * b3 + a4 * b4; + v[6] += a0 * b6 + a3 * b7; + v[7] += a1 * b6 + a4 * b7; + + return this; + } + + /** + * Copies over the values from another me.Matrix2d. + * @param m - the matrix object to copy from + * @returns Reference to this object for method chaining + */ + copy(m: Matrix2d) { + this.val.set(m.val); + return this; + } + + /** + * Copies over the upper-left 3x3 values from the given Matrix3d + * @param m - the matrix object to copy from + * @returns Reference to this object for method chaining + */ + fromMat3d(m: Matrix3d) { + this.val[0] = m.val[0]; + this.val[1] = m.val[1]; + this.val[2] = m.val[2]; + this.val[3] = m.val[4]; + this.val[4] = m.val[5]; + this.val[5] = m.val[6]; + this.val[6] = m.val[8]; + this.val[7] = m.val[9]; + this.val[8] = m.val[10]; + + return this; + } + + /** + * multiply both matrix + * @param m - the other matrix + * @returns Reference to this object for method chaining + */ + multiply(m: Matrix2d) { + const b = m.val; + const a = this.val; + const a0 = a[0]; + const a1 = a[1]; + const a3 = a[3]; + const a4 = a[4]; + const b0 = b[0]; + const b1 = b[1]; + const b3 = b[3]; + const b4 = b[4]; + const b6 = b[6]; + const b7 = b[7]; + + a[0] = a0 * b0 + a3 * b1; + a[1] = a1 * b0 + a4 * b1; + a[3] = a0 * b3 + a3 * b4; + a[4] = a1 * b3 + a4 * b4; + a[6] += a0 * b6 + a3 * b7; + a[7] += a1 * b6 + a4 * b7; + + return this; + } + + /** + * Transpose the value of this matrix. + * @returns Reference to this object for method chaining + */ + transpose() { + const a = this.val; + const a1 = a[1]; + const a2 = a[2]; + const a5 = a[5]; + + a[1] = a[3]; + a[2] = a[6]; + a[3] = a1; + a[5] = a[7]; + a[6] = a2; + a[7] = a5; + + return this; + } + + /** + * invert this matrix, causing it to apply the opposite transformation. + * @returns Reference to this object for method chaining + */ + invert() { + const val = this.val; + + const a = val[0]; + const b = val[1]; + const c = val[2]; + const d = val[3]; + const e = val[4]; + const f = val[5]; + const g = val[6]; + const h = val[7]; + const i = val[8]; + + const ta = i * e - f * h; + const td = f * g - i * d; + const tg = h * d - e * g; + + const n = a * ta + b * td + c * tg; + + val[0] = ta / n; + val[1] = (c * h - i * b) / n; + val[2] = (f * b - c * e) / n; + + val[3] = td / n; + val[4] = (i * a - c * g) / n; + val[5] = (c * d - f * a) / n; + + val[6] = tg / n; + val[7] = (b * g - h * a) / n; + val[8] = (e * a - b * d) / n; + + return this; + } + + /** + * apply the current transform to the given 2d or 3d vector or point + * @param v - the vector object to be transformed + * @returns result vector object. + */ + apply(v: Vector2d | Vector3d | Point) { + const a = this.val; + const x = v.x; + const y = v.y; + const z = "z" in v ? v.z : 1; + + v.x = x * a[0] + y * a[3] + z * a[6]; + v.y = x * a[1] + y * a[4] + z * a[7]; + + if ("z" in v) { + v.z = x * a[2] + y * a[5] + z * a[8]; + } + + return v; + } + + /** + * apply the inverted current transform to the given 2d vector + * @param v - the vector object to be transformed + * @returns result vector object. + */ + applyInverse(v: Vector2d) { + const a = this.val; + const x = v.x; + const y = v.y; + + const invD = 1 / (a[0] * a[4] + a[3] * -a[1]); + + v.x = + a[4] * invD * x + -a[3] * invD * y + (a[7] * a[3] - a[6] * a[4]) * invD; + v.y = + a[0] * invD * y + -a[1] * invD * x + (-a[7] * a[0] + a[6] * a[1]) * invD; + + return v; + } + + /** + * scale the matrix + * @param x - a number representing the abscissa of the scaling vector. + * @param [y] - a number representing the ordinate of the scaling vector. + * @returns Reference to this object for method chaining + */ + scale(x: number, y = x) { + const a = this.val; + + a[0] *= x; + a[1] *= x; + //a[2] *= x; // z axis remains unchanged for 2d scale operation + + a[3] *= y; + a[4] *= y; + //a[5] *= y; // w axis remains unchanged for 2d scale operation + + return this; + } + + /** + * adds a 2D scaling transformation. + * @param v - scaling vector + * @returns Reference to this object for method chaining + */ + scaleV(v: Vector2d) { + return this.scale(v.x, v.y); + } + + /** + * specifies a 2D scale operation using the [sx, 1] scaling vector + * @param x - x scaling vector + * @returns Reference to this object for method chaining + */ + scaleX(x: number) { + return this.scale(x, 1); + } + + /** + * specifies a 2D scale operation using the [1,sy] scaling vector + * @param y - y scaling vector + * @returns Reference to this object for method chaining + */ + scaleY(y: number) { + return this.scale(1, y); + } + + /** + * rotate the matrix (counter-clockwise) by the specified angle (in radians). + * @param angle - Rotation angle in radians. + * @returns Reference to this object for method chaining + */ + rotate(angle: number) { + if (angle !== 0) { + const a00 = this.val[0]; + const a01 = this.val[1]; + const a02 = this.val[2]; + const a10 = this.val[3]; + const a11 = this.val[4]; + const a12 = this.val[5]; + const s = Math.sin(angle); + const c = Math.cos(angle); + + this.val[0] = c * a00 + s * a10; + this.val[1] = c * a01 + s * a11; + this.val[2] = c * a02 + s * a12; + + this.val[3] = c * a10 - s * a00; + this.val[4] = c * a11 - s * a01; + this.val[5] = c * a12 - s * a02; + } + return this; + } + + /** + * translate the matrix position on the horizontal and vertical axis + * @param x - the x coordindates or a vector to translate the matrix by + * @param [y] - the y coordindates to translate the matrix by + * @returns Reference to this object for method chaining + */ + translate(x: number, y: number): Matrix2d; + translate(vector: Vector2d): Matrix2d; + translate(xOrVector: Vector2d | number, y?: number) { + let _x: number; + let _y: number; + + if (xOrVector instanceof Vector2d) { + _x = xOrVector.x; + _y = xOrVector.y; + } else { + _x = xOrVector; + _y = y!; + } + + this.val[6] += this.val[0] * _x + this.val[3] * _y; + this.val[7] += this.val[1] * _x + this.val[4] * _y; + + return this; + } + + /** + * Check if matrix is an identity matrix. + * @returns true if the matrix is an identity matrix + */ + isIdentity() { + return ( + this.val[0] === 1 && + this.val[1] === 0 && + this.val[2] === 0 && + this.val[3] === 0 && + this.val[4] === 1 && + this.val[5] === 0 && + this.val[6] === 0 && + this.val[7] === 0 && + this.val[8] === 1 + ); + } + + /** + * return true if the two matrices are identical + * @param m - the other matrix + * @returns true if both are equals + */ + equals(m: Matrix2d) { + return ( + this.val[0] === m.val[0] && + this.val[1] === m.val[1] && + this.val[2] === m.val[2] && + this.val[3] === m.val[3] && + this.val[4] === m.val[4] && + this.val[5] === m.val[5] && + this.val[6] === m.val[6] && + this.val[7] === m.val[7] && + this.val[8] === m.val[8] + ); + } + + /** + * Clone the Matrix + * @returns a clones matrix + */ + clone() { + return matrix2dPool.get(this); + } + + /** + * return an array representation of this Matrix + * @returns the internal matrix values + */ + toArray() { + return this.val; + } + + /** + * convert the object to a string representation + * @returns string representation of the matrix + */ + toString() { + const a = this.val; + + return `Matrix2d(${a[0]}, ${a[1]}, ${a[2]}, ${a[3]}, ${a[4]}, ${a[5]}, ${ + a[6] + }, ${a[7]}, ${a[8]})`; + } +} + +export const matrix2dPool = createPool( + (...values) => { + const instance = new Matrix2d(...values); + + return { + instance, + reset(...value) { + reset(instance, ...value); + }, + }; + }, +); diff --git a/packages/melonjs/src/math/matrix3.js b/packages/melonjs/src/math/matrix3d.ts similarity index 61% rename from packages/melonjs/src/math/matrix3.js rename to packages/melonjs/src/math/matrix3d.ts index b9ecab50f..7d71373b9 100644 --- a/packages/melonjs/src/math/matrix3.js +++ b/packages/melonjs/src/math/matrix3d.ts @@ -1,71 +1,78 @@ -import pool from "./../system/pooling.js"; +import { Point } from "../geometries/point.ts"; +import { createPool } from "../system/pool.ts"; import { EPSILON } from "./math.ts"; - -/** - * additional import for TypeScript - * @import Matrix2d from "./matrix2.js"; - * @import Vector2d from "./vector2.js"; - * @import Vector3d from "./vector3.js"; - */ +import { Matrix2d } from "./matrix2d.ts"; +import { Vector2d } from "./vector2d.ts"; +import { Vector3d } from "./vector3d.ts"; + +type SixteenNumbers = [ + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, +]; + +type ConstructorArg = [Matrix3d] | SixteenNumbers | [undefined] | []; + +const reset = (instance: Matrix3d, ...value: ConstructorArg) => { + if (value[0] instanceof Matrix3d) { + instance.copy(value[0]); + } else if (typeof value[0] === "number") { + instance.setTransform(...value); + } else { + instance.identity(); + } +}; /** * a 4x4 Matrix3d Object */ -export default class Matrix3d { +export class Matrix3d { /** - * @param {(Matrix3d|...number)} args - An instance of me.Matrix3d to copy from, or individual Matrix components (See {@link Matrix3d.setTransform}). If not arguments are given, the matrix will be set to Identity. + * The matrix values */ - constructor(...args) { - /** - * The matrix values - * @ignore - */ - this.val = undefined; - this.onResetEvent(...args); - } + val: Float32Array; /** - * @ignore + * Constructs a new Matrix3d object. + * @param value - The values to initialize the matrix with. */ - onResetEvent() { - const arg0 = arguments[0]; - const argLen = arguments.length; - - if (typeof this.val === "undefined") { - this.val = new Float32Array(16); - } - - if (argLen === 1 && arg0.val.length === 16) { - // matrix3d - this.copy(arg0); - } else if (argLen === 16) { - // individual components - this.setTransform.apply(this, arguments); - } else { - // invalid or no arguments - this.identity(); - } + constructor(...value: ConstructorArg) { + this.val = new Float32Array(16); + reset(this, ...value); } /** - * tx component of the matrix - * @type {number} + * Gets the tx component of the matrix. + * @returns The tx component of the matrix. */ get tx() { return this.val[12]; } /** - * ty component of the matrix - * @type {number} + * Gets the ty component of the matrix. + * @returns The ty component of the matrix. */ get ty() { return this.val[13]; } /** - * ty component of the matrix - * @type {number} + * Gets the tz component of the matrix. + * @returns The tz component of the matrix. */ get tz() { return this.val[14]; @@ -75,88 +82,56 @@ export default class Matrix3d { * reset the transformation matrix to the identity matrix (no transformation).
* the identity matrix and parameters position :
* - * @returns {Matrix3d} Reference to this object for method chaining + * @returns Reference to this object for method chaining */ identity() { return this.setTransform(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /** - * set the matrix to the specified value - * @param {number} m00 - * @param {number} m01 - * @param {number} m02 - * @param {number} m03 - * @param {number} m10 - * @param {number} m11 - * @param {number} m12 - * @param {number} m13 - * @param {number} m20 - * @param {number} m21 - * @param {number} m22 - * @param {number} m23 - * @param {number} m30 - * @param {number} m31 - * @param {number} m32 - * @param {number} m33 - * @returns {Matrix3d} Reference to this object for method chaining + * Set the matrix to the specified value. + * @param values - The matrix components. + * @returns Reference to this object for method chaining */ - setTransform( - m00, - m01, - m02, - m03, - m10, - m11, - m12, - m13, - m20, - m21, - m22, - m23, - m30, - m31, - m32, - m33, - ) { + setTransform(...values: SixteenNumbers) { const a = this.val; - a[0] = m00; - a[1] = m01; - a[2] = m02; - a[3] = m03; - a[4] = m10; - a[5] = m11; - a[6] = m12; - a[7] = m13; - a[8] = m20; - a[9] = m21; - a[10] = m22; - a[11] = m23; - a[12] = m30; - a[13] = m31; - a[14] = m32; - a[15] = m33; + a[0] = values[0]; + a[1] = values[1]; + a[2] = values[2]; + a[3] = values[3]; + a[4] = values[4]; + a[5] = values[5]; + a[6] = values[6]; + a[7] = values[7]; + a[8] = values[8]; + a[9] = values[9]; + a[10] = values[10]; + a[11] = values[11]; + a[12] = values[12]; + a[13] = values[13]; + a[14] = values[14]; + a[15] = values[15]; return this; } /** * Copies over the values from another me.Matrix3d. - * @param {Matrix3d} m - the matrix object to copy from - * @returns {Matrix3d} Reference to this object for method chaining + * @param m - the matrix object to copy from + * @returns Reference to this object for method chaining */ - copy(m) { + copy(m: Matrix3d) { this.val.set(m.val); return this; } /** * Copies over the upper-left 2x2 values from the given me.Matrix2d - * @param {Matrix2d} m - the matrix object to copy from - * @returns {Matrix2d} Reference to this object for method chaining + * @param m - the matrix object to copy from + * @returns Reference to this object for method chaining */ - fromMat2d(m) { + fromMat2d(m: Matrix2d) { const b = m.val; return this.setTransform( b[0], @@ -180,10 +155,10 @@ export default class Matrix3d { /** * multiply both matrix - * @param {Matrix3d} m - Other matrix - * @returns {Matrix3d} Reference to this object for method chaining + * @param m - Other matrix + * @returns Reference to this object for method chaining */ - multiply(m) { + multiply(m: Matrix3d) { const a = this.val; const b = m.val; @@ -248,7 +223,7 @@ export default class Matrix3d { /** * Transpose the value of this matrix. - * @returns {Matrix3d} Reference to this object for method chaining + * @returns Reference to this object for method chaining */ transpose() { const a = this.val; @@ -277,7 +252,7 @@ export default class Matrix3d { /** * invert this matrix, causing it to apply the opposite transformation. - * @returns {Matrix3d} Reference to this object for method chaining + * @returns Reference to this object for method chaining */ invert() { const a = this.val; @@ -319,7 +294,7 @@ export default class Matrix3d { b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (!det) { - return null; + return this.identity(); } det = 1 / det; @@ -345,22 +320,22 @@ export default class Matrix3d { } /** - * apply the current transform to the given 2d or 3d vector - * @param {Vector2d|Vector3d} v - the vector object to be transformed - * @returns {Vector2d|Vector3d} result vector object. + * apply the current transform to the given 2d or 3d vector or point + * @param v - the vector object to be transformed + * @returns result vector object. */ - apply(v) { + apply(v: Vector3d | Vector2d | Point) { const a = this.val; const x = v.x; const y = v.y; - const z = typeof v.z !== "undefined" ? v.z : 1; + const z = "z" in v ? v.z : 1; const w = a[3] * x + a[7] * y + a[11] * z + a[15] || 1.0; v.x = (a[0] * x + a[4] * y + a[8] * z + a[12]) / w; v.y = (a[1] * x + a[5] * y + a[9] * z + a[13]) / w; - if (typeof v.z !== "undefined") { + if ("z" in v) { v.z = (a[2] * x + a[6] * y + a[10] * z + a[14]) / w; } @@ -369,17 +344,16 @@ export default class Matrix3d { /** * apply the inverted current transform to the given 2d or 3d vector - * @param {Vector2d|Vector3d} v - the vector object to be transformed - * @returns {Vector2d|Vector3d} result vector object. + * @param v - the vector object to be transformed + * @returns result vector object. */ - applyInverse(v) { + applyInverse(v: Vector3d | Vector2d) { // invert the current matrix - const im = pool.pull("Matrix3d", this).invert(); - + const im = matrix3dPool.get(this).invert(); // apply the inverted matrix im.apply(v); - pool.push(im); + matrix3dPool.release(im); return v; } @@ -387,15 +361,22 @@ export default class Matrix3d { /** * generate an orthogonal projection matrix, with the result replacing the current matrix *
- * @param {number} left - farthest left on the x-axis - * @param {number} right - farthest right on the x-axis - * @param {number} bottom - farthest down on the y-axis - * @param {number} top - farthest up on the y-axis - * @param {number} near - distance to the near clipping plane along the -Z axis - * @param {number} far - distance to the far clipping plane along the -Z axis - * @returns {Matrix3d} Reference to this object for method chaining + * @param left - farthest left on the x-axis + * @param right - farthest right on the x-axis + * @param bottom - farthest down on the y-axis + * @param top - farthest up on the y-axis + * @param near - distance to the near clipping plane along the -Z axis + * @param far - distance to the far clipping plane along the -Z axis + * @returns Reference to this object for method chaining */ - ortho(left, right, bottom, top, near, far) { + ortho( + left: number, + right: number, + bottom: number, + top: number, + near: number, + far: number, + ) { const a = this.val; const leftRight = 1.0 / (left - right); const bottomTop = 1.0 / (bottom - top); @@ -423,12 +404,12 @@ export default class Matrix3d { /** * scale the matrix - * @param {number} x - a number representing the abscissa of the scaling vector. - * @param {number} [y=x] - a number representing the ordinate of the scaling vector. - * @param {number} [z=0] - a number representing the depth vector - * @returns {Matrix3d} Reference to this object for method chaining + * @param x - a number representing the abscissa of the scaling vector. + * @param [y] - a number representing the ordinate of the scaling vector. + * @param [z] - a number representing the depth vector + * @returns Reference to this object for method chaining */ - scale(x, y = x, z = 0) { + scale(x: number, y = x, z = 0) { const a = this.val; a[0] = a[0] * x; @@ -451,38 +432,38 @@ export default class Matrix3d { /** * adds a 2D scaling transformation. - * @param {Vector2d|Vector3d} v - scaling vector - * @returns {Matrix3d} Reference to this object for method chaining + * @param v - scaling vector + * @returns Reference to this object for method chaining */ - scaleV(v) { + scaleV(v: Vector3d) { return this.scale(v.x, v.y, v.z); } /** * specifies a 2D scale operation using the [sx, 1] scaling vector - * @param {number} x - x scaling vector - * @returns {Matrix3d} Reference to this object for method chaining + * @param x - x scaling vector + * @returns Reference to this object for method chaining */ - scaleX(x) { + scaleX(x: number) { return this.scale(x, 1); } /** * specifies a 2D scale operation using the [1,sy] scaling vector - * @param {number} y - y scaling vector - * @returns {Matrix3d} Reference to this object for method chaining + * @param y - y scaling vector + * @returns Reference to this object for method chaining */ - scaleY(y) { + scaleY(y: number) { return this.scale(1, y); } /** * rotate this matrix (counter-clockwise) by the specified angle (in radians). - * @param {number} angle - Rotation angle in radians. - * @param {Vector3d} v - the axis to rotate around - * @returns {Matrix3d} Reference to this object for method chaining + * @param angle - Rotation angle in radians. + * @param v - the axis to rotate around + * @returns Reference to this object for method chaining */ - rotate(angle, v) { + rotate(angle: number, v: Vector3d) { if (angle !== 0) { const a = this.val; let x = v.x; @@ -547,27 +528,31 @@ export default class Matrix3d { /** * translate the matrix position using the given vector - * @param {number|Vector2d|Vector3d} x - a number representing the abscissa of the vector, or a vector object - * @param {number} [y] - a number representing the ordinate of the vector. - * @param {number} [z=0] - a number representing the depth of the vector - * @returns {Matrix3d} Reference to this object for method chaining + * @param x - a number representing the abscissa of the vector, or a vector object + * @param [y] - a number representing the ordinate of the vector. + * @param [z] - a number representing the depth of the vector + * @returns Reference to this object for method chaining */ - translate() { + translate(x: number, y: number, z?: number | undefined): Matrix3d; + translate(vector: Vector3d | Vector2d): Matrix3d; + translate(xOrVector: Vector3d | Vector2d | number, y?: number, z?: number) { const a = this.val; - let _x; - let _y; - let _z; - - if (arguments.length > 1) { - // x, y (, z) - _x = arguments[0]; - _y = arguments[1]; - _z = typeof arguments[2] === "undefined" ? 0 : arguments[2]; + let _x: number; + let _y: number; + let _z: number; + + if (xOrVector instanceof Vector3d) { + _x = xOrVector.x; + _y = xOrVector.y; + _z = xOrVector.z; + } else if (xOrVector instanceof Vector2d) { + _x = xOrVector.x; + _y = xOrVector.y; + _z = 0; } else { - // 2d/3d vector - _x = arguments[0].x; - _y = arguments[0].y; - _z = typeof arguments[0].z === "undefined" ? 0 : arguments[0].z; + _x = xOrVector; + _y = y!; + _z = z ?? 0; } a[12] = a[0] * _x + a[4] * _y + a[8] * _z + a[12]; @@ -579,8 +564,8 @@ export default class Matrix3d { } /** - * returns true if the matrix is an identity matrix. - * @returns {boolean} + * Check if the matrix is an identity matrix. + * @returns true if the matrix is an identity matrix */ isIdentity() { const a = this.val; @@ -607,10 +592,10 @@ export default class Matrix3d { /** * return true if the two matrices are identical - * @param {Matrix3d} m - the other matrix - * @returns {boolean} true if both are equals + * @param m - the other matrix + * @returns true if both are equals */ - equals(m) { + equals(m: Matrix3d) { const b = m.val; const a = this.val; @@ -636,15 +621,15 @@ export default class Matrix3d { /** * Clone the Matrix - * @returns {Matrix3d} + * @returns a cloned matrix */ clone() { - return pool.pull("Matrix3d", this); + return matrix3dPool.get(this); } /** * return an array representation of this Matrix - * @returns {Float32Array} + * @returns internal matrix values */ toArray() { return this.val; @@ -652,45 +637,28 @@ export default class Matrix3d { /** * convert the object to a string representation - * @returns {string} + * @returns stringified representation */ toString() { const a = this.val; - return ( - "me.Matrix3d(" + - a[0] + - ", " + - a[1] + - ", " + - a[2] + - ", " + - a[3] + - ", " + - a[4] + - ", " + - a[5] + - ", " + - a[6] + - ", " + - a[7] + - ", " + - a[8] + - ", " + - a[9] + - ", " + - a[10] + - ", " + - a[11] + - ", " + - a[12] + - ", " + - a[13] + - ", " + - a[14] + - ", " + - a[15] + - ")" - ); + return `Matrix3d(${a[0]}, ${a[1]}, ${a[2]}, ${a[3]}, ${a[4]}, ${a[5]}, ${ + a[6] + }, ${a[7]}, ${a[8]}, ${a[9]}, ${a[10]}, ${a[11]}, ${a[12]}, ${a[13]}, ${ + a[14] + }, ${a[15]})`; } } + +export const matrix3dPool = createPool( + (...values) => { + const instance = new Matrix3d(...values); + + return { + instance, + reset(...value) { + reset(instance, ...value); + }, + }; + }, +); diff --git a/packages/melonjs/src/math/observableVector2d.ts b/packages/melonjs/src/math/observableVector2d.ts new file mode 100644 index 000000000..70c36a9ce --- /dev/null +++ b/packages/melonjs/src/math/observableVector2d.ts @@ -0,0 +1,200 @@ +import { TupleToUnion } from "type-fest"; +import { Vector2d, vector2dPool } from "./vector2d"; +import { createPool } from "../system/pool"; +import { clamp } from "./math"; + +const propertiesToObserve = ["x", "y"] as const; +type ObservableProperty = keyof Pick< + Vector2d, + TupleToUnion +>; +const setOfProperties = new Set(propertiesToObserve); + +const isObservableProperty = ( + property: string | symbol, +): property is ObservableProperty => { + return setOfProperties.has(property as any); +}; + +/** + * Function type for the observable vector update callback. + * @param options - The update options. + * @param options.newX - The new x value. + * @param options.newY - The new y value. + * @param options.currentX - The current x value. + * @param options.currentY - The current y value. + * @returns - The updated values or undefined. If the values are returned, they will become the new x and y values. + */ +export type ObservableVector2dUpdateFn = (options: { + newX: number; + newY: number; + currentX: number; + currentY: number; +}) => { x?: number | undefined; y?: number | undefined } | void; + +export interface ObservableVector2d extends Vector2d { + /** + * Returns a `Vector2d` copy of this `ObservableVector2d` object. + * @returns - The new Vector2d. + */ + toVector2d(): Vector2d; + + /** + * Sets the vector value without triggering the callback. + * @param x - The x value of the vector. + * @param y - The y value of the vector. + * @returns - Reference to this object for method chaining. + */ + setMuted(x: number, y: number): ObservableVector2d; + + /** + * Returns a clone copy of this vector. + * @returns - The cloned vector. + */ + clone(): ObservableVector2d; + + /** + * Negates the vector values. + * @returns - The negated vector. + */ + negate(): ObservableVector2d; + + /** + * Ceils the vector values. + * @returns - The ceiled vector. + */ + ceil(): ObservableVector2d; + + /** + * Floors the vector values. + * @returns - The floored vector. + */ + floor(): ObservableVector2d; + + /** + * Clamps the vector values within the specified value range. + * @param low - The lower bound. + * @param high - The upper bound. + * @returns - The clamped vector. + */ + clamp(low: number, high: number): ObservableVector2d; +} + +interface CreateObservableVector2dOptions { + target: Vector2d; + updateFn: ObservableVector2dUpdateFn; +} + +/** + * Creates an observable vector. + * This function wraps a given `Vector2d` object with a proxy that intercepts changes to the `x` and `y` properties, + * allowing for custom update logic via the provided `updateFn` callback. + * @param options - The options for creating the observable vector. + * @param options.target - The target vector to be made observable. + * @param options.updateFn - The update function to be called whenever the vector's properties change. + * @returns - The observable vector with additional methods for vector manipulation. + */ +export const createObservableVector2d = ( + options: CreateObservableVector2dOptions, +) => { + return new Proxy(options.target, { + set(target, prop, newValue, receiver) { + if (isObservableProperty(prop)) { + const retVal = options.updateFn({ + newX: prop === "x" ? newValue : target.x, + newY: prop === "y" ? newValue : target.y, + currentX: target.x, + currentY: target.y, + }); + const newVal = retVal && prop in retVal ? retVal[prop] : newValue; + return Reflect.set(target, prop, newVal, receiver); + } + + return true; + }, + get(target, prop: keyof ObservableVector2d, receiver) { + if (prop === "toVector2d") { + return () => { + return vector2dPool.get(target.x, target.y); + }; + } + + if (prop === "setMuted") { + return (x: number, y: number) => { + target.x = x; + target.y = y; + + return receiver; + }; + } + + if (prop === "set") { + return (x: number, y: number) => { + const retVal = options.updateFn({ + newX: x, + newY: y, + currentX: target.x, + currentY: target.y, + }); + if ( + retVal && + typeof retVal.x === "number" && + typeof retVal.y === "number" + ) { + target.x = retVal.x; + target.y = retVal.y; + } else { + target.x = x; + target.y = y; + } + return receiver; + }; + } + + if (prop === "clone") { + return () => + observableVector2dPool.get(target.x, target.y, options.updateFn); + } + + if (prop === "clamp") { + return (low: number, high: number) => + createObservableVector2d({ + target: new Vector2d( + clamp(target.x, low, high), + clamp(target.y, low, high), + ), + updateFn: options.updateFn, + }); + } + + if (prop === "negate" || prop === "ceil" || prop === "floor") { + return () => + createObservableVector2d({ + target: target[prop](), + updateFn: options.updateFn, + }); + } + return Reflect.get(target, prop, receiver); + }, + }) as ObservableVector2d; +}; + +export const observableVector2dPool = createPool< + ObservableVector2d, + [number, number, ObservableVector2dUpdateFn] +>((x, y, updateFn) => { + const vector = new Vector2d(x, y); + + const options: CreateObservableVector2dOptions = { target: vector, updateFn }; + + const instance = createObservableVector2d(options); + + return { + instance, + reset(x, y, updateFn) { + vector.x = x; + vector.y = y; + options.updateFn = updateFn; + }, + }; +}); diff --git a/packages/melonjs/src/math/observableVector3d.ts b/packages/melonjs/src/math/observableVector3d.ts new file mode 100644 index 000000000..124ad4837 --- /dev/null +++ b/packages/melonjs/src/math/observableVector3d.ts @@ -0,0 +1,226 @@ +import { TupleToUnion } from "type-fest"; +import { createPool } from "../system/pool"; +import { clamp } from "./math"; +import { Vector3d, vector3dPool } from "./vector3d"; + +const propertiesToObserve = ["x", "y", "z"] as const; +type ObservableProperty = keyof Pick< + Vector3d, + TupleToUnion +>; +const setOfProperties = new Set(propertiesToObserve); + +const isObservableProperty = ( + property: string | symbol, +): property is ObservableProperty => { + return setOfProperties.has(property as any); +}; + +/** + * Function type for the observable vector update callback. + * @param options - The update options. + * @param options.newX - The new x value. + * @param options.newY - The new y value. + * @param options.newZ - The new z value. + * @param options.currentX - The current x value. + * @param options.currentY - The current y value. + * @param options.currentZ - The current z value. + * @returns - The updated values or undefined. If the values are returned, they will become the new x,y and z values. + */ +export type ObservableVector3dUpdateFn = (options: { + newX: number; + newY: number; + newZ: number; + currentX: number; + currentY: number; + currentZ: number; +}) => { + x?: number | undefined; + y?: number | undefined; + z?: number | undefined; +} | void; + +export interface ObservableVector3d extends Vector3d { + /** + * Returns a `Vector3d` copy of this `ObservableVector3d` object. + * @returns - The new Vector3d. + */ + toVector3d(): Vector3d; + + /** + * Sets the vector value without triggering the callback. + * @param x - The x value of the vector. + * @param y - The y value of the vector. + * @returns - Reference to this object for method chaining. + */ + setMuted(x: number, y: number, z: number): ObservableVector3d; + + /** + * Returns a clone copy of this vector. + * @returns - The cloned vector. + */ + clone(): ObservableVector3d; + + /** + * Negates the vector values. + * @returns - The negated vector. + */ + negate(): ObservableVector3d; + + /** + * Ceils the vector values. + * @returns - The ceiled vector. + */ + ceil(): ObservableVector3d; + + /** + * Floors the vector values. + * @returns - The floored vector. + */ + floor(): ObservableVector3d; + + /** + * Clamps the vector values within the specified value range. + * @param low - The lower bound. + * @param high - The upper bound. + * @returns - The clamped vector. + */ + clamp(low: number, high: number): ObservableVector3d; +} + +interface CreateObservableVector3dOptions { + target: Vector3d; + updateFn: ObservableVector3dUpdateFn; +} + +/** + * Creates an observable vector. + * This function wraps a given `Vector3d` object with a proxy that intercepts changes to the `x`, `y`, and `z` properties, + * allowing for custom update logic via the provided `updateFn` callback. + * @param options - The options for creating the observable vector. + * @param options.target - The target vector to be made observable. + * @param options.updateFn - The update function to be called whenever the vector's properties change. + * @returns - The observable vector with additional methods for vector manipulation. + */ +export const createObservableVector3d = ( + options: CreateObservableVector3dOptions, +) => { + return new Proxy(options.target, { + set(target, prop, newValue, receiver) { + if (isObservableProperty(prop)) { + const retVal = options.updateFn({ + newX: prop === "x" ? newValue : target.x, + newY: prop === "y" ? newValue : target.y, + newZ: prop === "z" ? newValue : target.z, + currentX: target.x, + currentY: target.y, + currentZ: target.z, + }); + const newVal = retVal && prop in retVal ? retVal[prop] : newValue; + return Reflect.set(target, prop, newVal, receiver); + } + + return true; + }, + get(target, prop: keyof ObservableVector3d, receiver) { + if (prop === "toVector3d") { + return () => { + return vector3dPool.get(target.x, target.y, target.z); + }; + } + + if (prop === "setMuted") { + return (x: number, y: number, z: number) => { + target.x = x; + target.y = y; + target.z = z; + + return receiver; + }; + } + + if (prop === "set") { + return (x: number, y: number, z: number) => { + const retVal = options.updateFn({ + newX: x, + newY: y, + newZ: z, + currentX: target.x, + currentY: target.y, + currentZ: target.z, + }); + if ( + retVal && + typeof retVal.x === "number" && + typeof retVal.y === "number" && + typeof retVal.z === "number" + ) { + target.x = retVal.x; + target.y = retVal.y; + target.z = retVal.z; + } else { + target.x = x; + target.y = y; + target.z = z; + } + return receiver; + }; + } + + if (prop === "clone") { + return () => + observableVector3dPool.get( + target.x, + target.y, + target.z, + options.updateFn, + ); + } + + if (prop === "clamp") { + return (low: number, high: number) => + createObservableVector3d({ + target: new Vector3d( + clamp(target.x, low, high), + clamp(target.y, low, high), + clamp(target.z, low, high), + ), + updateFn: options.updateFn, + }); + } + + if (prop === "negate" || prop === "ceil" || prop === "floor") { + return () => + createObservableVector3d({ + target: target[prop](), + updateFn: options.updateFn, + }); + } + return Reflect.get(target, prop, receiver); + }, + }) as ObservableVector3d; +}; + +export const observableVector3dPool = createPool< + ObservableVector3d, + [number, number, number, ObservableVector3dUpdateFn] +>((x, y, z, updateFn) => { + const vector = new Vector3d(x, y, z); + + const options: CreateObservableVector3dOptions = { + target: vector, + updateFn, + }; + + const instance = createObservableVector3d(options); + + return { + instance: instance, + reset(x, y, z, updateFn) { + vector.x = x; + vector.y = y; + vector.z = z; + options.updateFn = updateFn; + }, + }; +}); diff --git a/packages/melonjs/src/math/observable_vector2.js b/packages/melonjs/src/math/observable_vector2.js deleted file mode 100644 index 7e3e6f992..000000000 --- a/packages/melonjs/src/math/observable_vector2.js +++ /dev/null @@ -1,425 +0,0 @@ -import pool from "./../system/pooling.js"; -import Vector2d from "./vector2.js"; -import { clamp } from "./math.ts"; - -/** - * A Vector2d object that provide notification by executing the given callback when the vector is changed. - */ -export default class ObservableVector2d extends Vector2d { - /** - * @param {number} x - x value of the vector - * @param {number} y - y value of the vector - * @param {object} settings - additional required parameters - * @param {Function} settings.onUpdate - the callback to be executed when the vector is changed - * @param {Function} [settings.scope] - the value to use as this when calling onUpdate - */ - constructor(x = 0, y = 0, settings) { - super(x, y); - if (typeof settings === "undefined") { - throw new Error("undefined `onUpdate` callback"); - } - this.setCallback(settings.onUpdate, settings.scope); - } - - /** - * @ignore - */ - onResetEvent(x = 0, y = 0, settings) { - // init is call by the constructor and does not trigger the cb - this.setMuted(x, y); - if (typeof settings !== "undefined") { - this.setCallback(settings.onUpdate, settings.scope); - } - } - - /** - * x value of the vector - * @type {number} - */ - - get x() { - return this._x; - } - - set x(value) { - const ret = this.onUpdate.call( - this.scope, - value, - this._y, - this._x, - this._y, - ); - if (ret && "x" in ret) { - this._x = ret.x; - } else { - this._x = value; - } - } - - /** - * y value of the vector - * @type {number} - */ - - get y() { - return this._y; - } - - set y(value) { - const ret = this.onUpdate.call( - this.scope, - this._x, - value, - this._x, - this._y, - ); - if (ret && "y" in ret) { - this._y = ret.y; - } else { - this._y = value; - } - } - - /** @ignore */ - _set(x, y) { - const ret = this.onUpdate.call(this.scope, x, y, this._x, this._y); - if (ret && "x" in ret && "y" in ret) { - this._x = ret.x; - this._y = ret.y; - } else { - this._x = x; - this._y = y; - } - return this; - } - - /** - * set the vector value without triggering the callback - * @param {number} x - x value of the vector - * @param {number} y - y value of the vector - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - setMuted(x, y) { - this._x = x; - this._y = y; - return this; - } - - /** - * set the callback to be executed when the vector is changed - * @param {Function} fn - callback - * @param {Function} [scope=null] - scope - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - setCallback(fn, scope = null) { - if (typeof fn !== "function") { - throw new Error("invalid `onUpdate` callback"); - } - this.onUpdate = fn; - this.scope = scope; - return this; - } - - /** - * Add the passed vector to this vector - * @param {ObservableVector2d} v - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - add(v) { - return this._set(this._x + v.x, this._y + v.y); - } - - /** - * Substract the passed vector to this vector - * @param {ObservableVector2d} v - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - sub(v) { - return this._set(this._x - v.x, this._y - v.y); - } - - /** - * Multiply this vector values by the given scalar - * @param {number} x - * @param {number} [y=x] - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - scale(x, y = x) { - return this._set(this._x * x, this._y * y); - } - - /** - * Multiply this vector values by the passed vector - * @param {ObservableVector2d} v - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - scaleV(v) { - return this._set(this._x * v.x, this._y * v.y); - } - - /** - * Divide this vector values by the passed value - * @param {number} n - the value to divide the vector by - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - div(n) { - return this._set(this._x / n, this._y / n); - } - - /** - * Update this vector values to absolute values - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - abs() { - return this._set( - this._x < 0 ? -this._x : this._x, - this._y < 0 ? -this._y : this._y, - ); - } - - /** - * Clamp the vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {ObservableVector2d} new me.ObservableVector2d - */ - clamp(low, high) { - return new ObservableVector2d( - clamp(this.x, low, high), - clamp(this.y, low, high), - { onUpdate: this.onUpdate, scope: this.scope }, - ); - } - - /** - * Clamp this vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - clampSelf(low, high) { - return this._set(clamp(this._x, low, high), clamp(this._y, low, high)); - } - - /** - * Update this vector with the minimum value between this and the passed vector - * @param {ObservableVector2d} v - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - minV(v) { - return this._set( - this._x < v.x ? this._x : v.x, - this._y < v.y ? this._y : v.y, - ); - } - - /** - * Update this vector with the maximum value between this and the passed vector - * @param {ObservableVector2d} v - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - maxV(v) { - return this._set( - this._x > v.x ? this._x : v.x, - this._y > v.y ? this._y : v.y, - ); - } - - /** - * Floor the vector values - * @returns {ObservableVector2d} new me.ObservableVector2d - */ - floor() { - return new ObservableVector2d(Math.floor(this._x), Math.floor(this._y), { - onUpdate: this.onUpdate, - scope: this.scope, - }); - } - - /** - * Floor this vector values - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - floorSelf() { - return this._set(Math.floor(this._x), Math.floor(this._y)); - } - - /** - * Ceil the vector values - * @returns {ObservableVector2d} new me.ObservableVector2d - */ - ceil() { - return new ObservableVector2d(Math.ceil(this._x), Math.ceil(this._y), { - onUpdate: this.onUpdate, - scope: this.scope, - }); - } - - /** - * Ceil this vector values - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - ceilSelf() { - return this._set(Math.ceil(this._x), Math.ceil(this._y)); - } - - /** - * Negate the vector values - * @returns {ObservableVector2d} new me.ObservableVector2d - */ - negate() { - return new ObservableVector2d(-this._x, -this._y, { - onUpdate: this.onUpdate, - scope: this.scope, - }); - } - - /** - * Negate this vector values - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - negateSelf() { - return this._set(-this._x, -this._y); - } - - /** - * Copy the x,y values of the passed vector to this one - * @param {ObservableVector2d} v - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - copy(v) { - return this._set(v.x, v.y); - } - - /** - * return true if the two vectors are the same - * @param {ObservableVector2d} v - * @returns {boolean} - */ - equals(v) { - return this._x === v.x && this._y === v.y; - } - - /** - * change this vector to be perpendicular to what it was before.
- * (Effectively rotates it 90 degrees in a clockwise direction) - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - perp() { - return this._set(this._y, -this._x); - } - - /** - * Rotate this vector (counter-clockwise) by the specified angle (in radians). - * @param {number} angle - The angle to rotate (in radians) - * @param {Vector2d|ObservableVector2d} [v] - an optional point to rotate around - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - rotate(angle, v) { - let cx = 0; - let cy = 0; - - if (typeof v === "object") { - cx = v.x; - cy = v.y; - } - - const x = this._x - cx; - const y = this._y - cy; - - const c = Math.cos(angle); - const s = Math.sin(angle); - - return this._set(x * c - y * s + cx, x * s + y * c + cy); - } - - /** - * return the dot product of this vector and the passed one - * @param {Vector2d|ObservableVector2d} v - * @returns {number} The dot product. - */ - dot(v) { - return this._x * v.x + this._y * v.y; - } - - /** - * return the cross product of this vector and the passed one - * @param {Vector2d|ObservableVector2d} v - * @returns {number} The cross product. - */ - cross(v) { - return this._x * v.y - this._y * v.x; - } - - /** - * Linearly interpolate between this vector and the given one. - * @param {Vector2d|ObservableVector2d} v - * @param {number} alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one). - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - lerp(v, alpha) { - return this._set( - this._x + (v.x - this._x) * alpha, - this._y + (v.y - this._y) * alpha, - ); - } - - /** - * interpolate the position of this vector towards the given one while nsure that the distance never exceeds the given step. - * @param {Vector2d|ObservableVector2d} target - * @param {number} step - the maximum step per iteration (Negative values will push the vector away from the target) - * @returns {ObservableVector2d} Reference to this object for method chaining - */ - moveTowards(target, step) { - const angle = Math.atan2(target.y - this._y, target.x - this._x); - - const distance = this.distance(target); - - if (distance === 0 || (step >= 0 && distance <= step * step)) { - return target; - } - - this._x += Math.cos(angle) * step; - this._y += Math.sin(angle) * step; - - return this; - } - - /** - * return the distance between this vector and the passed one - * @param {ObservableVector2d} v - * @returns {number} - */ - distance(v) { - return Math.sqrt( - (this._x - v.x) * (this._x - v.x) + (this._y - v.y) * (this._y - v.y), - ); - } - - /** - * return a clone copy of this vector - * @returns {ObservableVector2d} new me.ObservableVector2d - */ - clone() { - return pool.pull("ObservableVector2d", this._x, this._y, { - onUpdate: this.onUpdate, - scope: this.scope, - }); - } - - /** - * return a `me.Vector2d` copy of this `me.ObservableVector2d` object - * @returns {Vector2d} new me.Vector2d - */ - toVector2d() { - return pool.pull("Vector2d", this._x, this._y); - } - - /** - * convert the object to a string representation - * @returns {string} - */ - toString() { - return "x:" + this._x + ",y:" + this._y; - } -} diff --git a/packages/melonjs/src/math/observable_vector3.js b/packages/melonjs/src/math/observable_vector3.js deleted file mode 100644 index 0cccfd7f6..000000000 --- a/packages/melonjs/src/math/observable_vector3.js +++ /dev/null @@ -1,513 +0,0 @@ -import Vector3d from "./vector3.js"; -import { clamp } from "./math.ts"; -import pool from "./../system/pooling.js"; - -/** - * additional import for TypeScript - * @import ObservableVector2d from "./observable_vector2.js"; - * @import Vector2d from "./vector2.js"; - */ - -/** - * A Vector3d object that provide notification by executing the given callback when the vector is changed. - */ -export default class ObservableVector3d extends Vector3d { - /** - * @param {number} x - x value of the vector - * @param {number} y - y value of the vector - * @param {number} z - z value of the vector - * @param {object} settings - additional required parameters - * @param {Function} settings.onUpdate - the callback to be executed when the vector is changed - * @param {object} [settings.scope] - the value to use as this when calling onUpdate - */ - constructor(x = 0, y = 0, z = 0, settings) { - super(x, y, z); - if (typeof settings === "undefined") { - throw new Error("undefined `onUpdate` callback"); - } - this.setCallback(settings.onUpdate, settings.scope); - } - - /** - * @ignore - */ - onResetEvent(x = 0, y = 0, z = 0, settings) { - // init is call by the constructor and does not trigger the cb - this.setMuted(x, y, z); - if (typeof settings !== "undefined") { - this.setCallback(settings.onUpdate, settings.scope); - } - return this; - } - - /** - * x value of the vector - * @type {number} - */ - - get x() { - return this._x; - } - - set x(value) { - const ret = this.onUpdate.call( - this.scope, - value, - this._y, - this._z, - this._x, - this._y, - this._z, - ); - if (ret && "x" in ret) { - this._x = ret.x; - } else { - this._x = value; - } - } - - /** - * y value of the vector - * @type {number} - */ - - get y() { - return this._y; - } - - set y(value) { - const ret = this.onUpdate.call( - this.scope, - this._x, - value, - this._z, - this._x, - this._y, - this._z, - ); - if (ret && "y" in ret) { - this._y = ret.y; - } else { - this._y = value; - } - } - - /** - * z value of the vector - * @type {number} - */ - - get z() { - return this._z; - } - - set z(value) { - const ret = this.onUpdate.call( - this.scope, - this._x, - this._y, - value, - this._x, - this._y, - this._z, - ); - if (ret && "z" in ret) { - this._z = ret.z; - } else { - this._z = value; - } - } - - /** - * @ignore - */ - _set(x, y, z) { - const ret = this.onUpdate.call( - this.scope, - x, - y, - z, - this._x, - this._y, - this._z, - ); - if (ret && "x" in ret && "y" in ret && "z" in ret) { - this._x = ret.x; - this._y = ret.y; - this._z = ret.z; - } else { - this._x = x; - this._y = y; - this._z = z || 0; - } - return this; - } - - /** - * set the vector value without triggering the callback - * @param {number} x - x value of the vector - * @param {number} y - y value of the vector - * @param {number} [z=0] - z value of the vector - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - setMuted(x, y, z) { - this._x = x; - this._y = y; - this._z = z || 0; - return this; - } - - /** - * set the callback to be executed when the vector is changed - * @param {Function} fn - callback - * @param {Function} [scope=null] - scope - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - setCallback(fn, scope = null) { - if (typeof fn !== "function") { - throw new Error("invalid `onUpdate` callback"); - } - this.onUpdate = fn; - this.scope = scope; - return this; - } - - /** - * Add the passed vector to this vector - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - add(v) { - return this._set(this._x + v.x, this._y + v.y, this._z + (v.z || 0)); - } - - /** - * Substract the passed vector to this vector - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - sub(v) { - return this._set(this._x - v.x, this._y - v.y, this._z - (v.z || 0)); - } - - /** - * Multiply this vector values by the given scalar - * @param {number} x - * @param {number} [y=x] - * @param {number} [z=1] - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - scale(x, y = x, z = 1) { - return this._set(this._x * x, this._y * y, this._z * z); - } - - /** - * Multiply this vector values by the passed vector - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - scaleV(v) { - return this._set(this._x * v.x, this._y * v.y, this._z * (v.z || 1)); - } - - /** - * Divide this vector values by the passed value - * @param {number} n - the value to divide the vector by - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - div(n) { - return this._set(this._x / n, this._y / n, this._z / n); - } - - /** - * Update this vector values to absolute values - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - abs() { - return this._set( - this._x < 0 ? -this._x : this._x, - this._y < 0 ? -this._y : this._y, - this._Z < 0 ? -this._z : this._z, - ); - } - - /** - * Clamp the vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {ObservableVector3d} new me.ObservableVector3d - */ - clamp(low, high) { - return new ObservableVector3d( - clamp(this._x, low, high), - clamp(this._y, low, high), - clamp(this._z, low, high), - { onUpdate: this.onUpdate, scope: this.scope }, - ); - } - - /** - * Clamp this vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - clampSelf(low, high) { - return this._set( - clamp(this._x, low, high), - clamp(this._y, low, high), - clamp(this._z, low, high), - ); - } - - /** - * Update this vector with the minimum value between this and the passed vector - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - minV(v) { - const _vz = v.z || 0; - return this._set( - this._x < v.x ? this._x : v.x, - this._y < v.y ? this._y : v.y, - this._z < _vz ? this._z : _vz, - ); - } - - /** - * Update this vector with the maximum value between this and the passed vector - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - maxV(v) { - const _vz = v.z || 0; - return this._set( - this._x > v.x ? this._x : v.x, - this._y > v.y ? this._y : v.y, - this._z > _vz ? this._z : _vz, - ); - } - - /** - * Floor the vector values - * @returns {ObservableVector3d} new me.ObservableVector3d - */ - floor() { - return new ObservableVector3d( - Math.floor(this._x), - Math.floor(this._y), - Math.floor(this._z), - { onUpdate: this.onUpdate, scope: this.scope }, - ); - } - - /** - * Floor this vector values - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - floorSelf() { - return this._set( - Math.floor(this._x), - Math.floor(this._y), - Math.floor(this._z), - ); - } - - /** - * Ceil the vector values - * @returns {ObservableVector3d} new me.ObservableVector3d - */ - ceil() { - return new ObservableVector3d( - Math.ceil(this._x), - Math.ceil(this._y), - Math.ceil(this._z), - { onUpdate: this.onUpdate, scope: this.scope }, - ); - } - - /** - * Ceil this vector values - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - ceilSelf() { - return this._set( - Math.ceil(this._x), - Math.ceil(this._y), - Math.ceil(this._z), - ); - } - - /** - * Negate the vector values - * @returns {ObservableVector3d} new me.ObservableVector3d - */ - negate() { - return new ObservableVector3d(-this._x, -this._y, -this._z, { - onUpdate: this.onUpdate, - scope: this.scope, - }); - } - - /** - * Negate this vector values - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - negateSelf() { - return this._set(-this._x, -this._y, -this._z); - } - - /** - * Copy the components of the given vector into this one - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - copy(v) { - return this._set(v.x, v.y, v.z || 0); - } - - /** - * return true if the two vectors are the same - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {boolean} - */ - equals(v) { - return this._x === v.x && this._y === v.y && this._z === (v.z || this._z); - } - - /** - * change this vector to be perpendicular to what it was before.
- * (Effectively rotates it 90 degrees in a clockwise direction) - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - perp() { - return this._set(this._y, -this._x, this._z); - } - - /** - * Rotate this vector (counter-clockwise) by the specified angle (in radians). - * @param {number} angle - The angle to rotate (in radians) - * @param {Vector2d|ObservableVector2d} [v] - an optional point to rotate around (on the same z axis) - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - rotate(angle, v) { - let cx = 0; - let cy = 0; - - if (typeof v === "object") { - cx = v.x; - cy = v.y; - } - - // TODO also rotate on the z axis if the given vector is a 3d one - const x = this.x - cx; - const y = this.y - cy; - - const c = Math.cos(angle); - const s = Math.sin(angle); - - return this._set(x * c - y * s + cx, x * s + y * c + cy, this.z); - } - - /** - * return the dot product of this vector and the passed one - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {number} The dot product. - */ - dot(v) { - return this._x * v.x + this._y * v.y + this._z * (v.z || 1); - } - - /** - * calculate the cross product of this vector and the passed one - * @param {Vector3d|ObservableVector3d} v - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - cross(v) { - const ax = this._x; - const ay = this._y; - const az = this._z; - const bx = v.x; - const by = v.y; - const bz = v.z; - - return this._set(ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx); - } - - /** - * Linearly interpolate between this vector and the given one. - * @param {Vector3d|ObservableVector3d} v - * @param {number} alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one). - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - lerp(v, alpha) { - return this._set( - this._x + (v.x - this._x) * alpha, - this._y + (v.y - this._y) * alpha, - this._z + (v.z - this._z) * alpha, - ); - } - - /** - * interpolate the position of this vector on the x and y axis towards the given one while ensure that the distance never exceeds the given step. - * @param {Vector2d|ObservableVector2d|Vector3d|ObservableVector3d} target - * @param {number} step - the maximum step per iteration (Negative values will push the vector away from the target) - * @returns {ObservableVector3d} Reference to this object for method chaining - */ - moveTowards(target, step) { - const angle = Math.atan2(target.y - this._y, target.x - this._x); - - const dx = this._x - target.x; - const dy = this._y - target.y; - - const distance = Math.sqrt(dx * dx + dy * dy); - - if (distance === 0 || (step >= 0 && distance <= step * step)) { - return target; - } - - return this._set( - this._x + Math.cos(angle) * step, - this._y + Math.sin(angle) * step, - this._z, - ); - } - - /** - * return the distance between this vector and the passed one - * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v - * @returns {number} - */ - distance(v) { - const dx = this._x - v.x; - const dy = this._y - v.y; - const dz = this._z - (v.z || 0); - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } - - /** - * return a clone copy of this vector - * @returns {ObservableVector3d} new me.ObservableVector3d - */ - clone() { - return pool.pull("ObservableVector3d", this._x, this._y, this._z, { - onUpdate: this.onUpdate, - }); - } - - /** - * return a `me.Vector3d` copy of this `me.ObservableVector3d` object - * @returns {Vector3d} new me.Vector3d - */ - toVector3d() { - return pool.pull("Vector3d", this._x, this._y, this._z); - } - - /** - * convert the object to a string representation - * @returns {string} - */ - toString() { - return "x:" + this._x + ",y:" + this._y + ",z:" + this._z; - } -} diff --git a/packages/melonjs/src/math/vector2.js b/packages/melonjs/src/math/vector2.js deleted file mode 100644 index 6d7ef92ae..000000000 --- a/packages/melonjs/src/math/vector2.js +++ /dev/null @@ -1,424 +0,0 @@ -import { clamp } from "./math.ts"; -import pool from "./../system/pooling.js"; - -/** - * a generic 2D Vector Object - */ -export default class Vector2d { - /** - * @param {number} [x=0] - x value of the vector - * @param {number} [y=0] - y value of the vector - */ - constructor(x = 0, y = 0) { - this.onResetEvent(x, y); - } - - /** - * @param {number} [x=0] - x value of the vector - * @param {number} [y=0] - y value of the vector - * @ignore - */ - onResetEvent(x = 0, y = 0) { - /** - * x value of the vector - * @type {number} - */ - this.x = x; - /** - * y value of the vector - * @type {number} - */ - this.y = y; - } - - /** - * @param {number} [x=0] - x value of the vector - * @param {number} [y=0] - y value of the vector - * @ignore - */ - _set(x, y) { - this.x = x; - this.y = y; - return this; - } - - /** - * set the Vector x and y properties to the given values - * @param {number} x - * @param {number} y - * @returns {Vector2d} Reference to this object for method chaining - */ - set(x, y) { - if (x !== +x || y !== +y) { - throw new Error("invalid x,y parameters (not a number)"); - } - return this._set(x, y); - } - - /** - * set the Vector x and y properties to 0 - * @returns {Vector2d} Reference to this object for method chaining - */ - setZero() { - return this.set(0, 0); - } - - /** - * set the Vector x and y properties using the passed vector - * @param {Vector2d} v - * @returns {Vector2d} Reference to this object for method chaining - */ - setV(v) { - return this._set(v.x, v.y); - } - - /** - * Add the passed vector to this vector - * @param {Vector2d} v - * @returns {Vector2d} Reference to this object for method chaining - */ - add(v) { - return this._set(this.x + v.x, this.y + v.y); - } - - /** - * Substract the passed vector to this vector - * @param {Vector2d} v - * @returns {Vector2d} Reference to this object for method chaining - */ - sub(v) { - return this._set(this.x - v.x, this.y - v.y); - } - - /** - * Multiply this vector values by the given scalar - * @param {number} x - * @param {number} [y=x] - * @returns {Vector2d} Reference to this object for method chaining - */ - scale(x, y = x) { - return this._set(this.x * x, this.y * y); - } - - /** - * Convert this vector into isometric coordinate space - * @returns {Vector2d} Reference to this object for method chaining - */ - toIso() { - return this._set(this.x - this.y, (this.x + this.y) * 0.5); - } - - /** - * Convert this vector into 2d coordinate space - * @returns {Vector2d} Reference to this object for method chaining - */ - to2d() { - return this._set(this.y + this.x / 2, this.y - this.x / 2); - } - - /** - * Multiply this vector values by the passed vector - * @param {Vector2d} v - * @returns {Vector2d} Reference to this object for method chaining - */ - scaleV(v) { - return this._set(this.x * v.x, this.y * v.y); - } - - /** - * Divide this vector values by the passed value - * @param {number} n - the value to divide the vector by - * @returns {Vector2d} Reference to this object for method chaining - */ - div(n) { - return this._set(this.x / n, this.y / n); - } - - /** - * Update this vector values to absolute values - * @returns {Vector2d} Reference to this object for method chaining - */ - abs() { - return this._set( - this.x < 0 ? -this.x : this.x, - this.y < 0 ? -this.y : this.y, - ); - } - - /** - * Clamp the vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {Vector2d} new me.Vector2d - */ - clamp(low, high) { - return new Vector2d(clamp(this.x, low, high), clamp(this.y, low, high)); - } - - /** - * Clamp this vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {Vector2d} Reference to this object for method chaining - */ - clampSelf(low, high) { - return this._set(clamp(this.x, low, high), clamp(this.y, low, high)); - } - - /** - * Update this vector with the minimum value between this and the passed vector - * @param {Vector2d} v - * @returns {Vector2d} Reference to this object for method chaining - */ - minV(v) { - return this._set(this.x < v.x ? this.x : v.x, this.y < v.y ? this.y : v.y); - } - - /** - * Update this vector with the maximum value between this and the passed vector - * @param {Vector2d} v - * @returns {Vector2d} Reference to this object for method chaining - */ - maxV(v) { - return this._set(this.x > v.x ? this.x : v.x, this.y > v.y ? this.y : v.y); - } - - /** - * Floor the vector values - * @returns {Vector2d} new me.Vector2d - */ - floor() { - return new Vector2d(Math.floor(this.x), Math.floor(this.y)); - } - - /** - * Floor this vector values - * @returns {Vector2d} Reference to this object for method chaining - */ - floorSelf() { - return this._set(Math.floor(this.x), Math.floor(this.y)); - } - - /** - * Ceil the vector values - * @returns {Vector2d} new me.Vector2d - */ - ceil() { - return new Vector2d(Math.ceil(this.x), Math.ceil(this.y)); - } - - /** - * Ceil this vector values - * @returns {Vector2d} Reference to this object for method chaining - */ - ceilSelf() { - return this._set(Math.ceil(this.x), Math.ceil(this.y)); - } - - /** - * Negate the vector values - * @returns {Vector2d} new me.Vector2d - */ - negate() { - return new Vector2d(-this.x, -this.y); - } - - /** - * Negate this vector values - * @returns {Vector2d} Reference to this object for method chaining - */ - negateSelf() { - return this._set(-this.x, -this.y); - } - - /** - * Copy the x,y values of the passed vector to this one - * @param {Vector2d} v - * @returns {Vector2d} Reference to this object for method chaining - */ - copy(v) { - return this._set(v.x, v.y); - } - - /** - * return true if this vector is equal to the given values or vector - * @param {number|Vector2d} x - * @param {number} [y] - * @returns {boolean} - */ - equals(...args) { - let _x; - let _y; - if (args.length === 2) { - // x, y - [_x, _y] = args; - } else { - // vector - [_x, _y] = [args[0].x, args[0].y]; - } - return this.x === _x && this.y === _y; - } - - /** - * normalize this vector (scale the vector so that its magnitude is 1) - * @returns {Vector2d} Reference to this object for method chaining - */ - normalize() { - return this.div(this.length() || 1); - } - - /** - * change this vector to be perpendicular to what it was before.
- * (Effectively rotates it 90 degrees in a clockwise direction) - * @returns {Vector2d} Reference to this object for method chaining - */ - perp() { - return this._set(this.y, -this.x); - } - - /** - * Rotate this vector (counter-clockwise) by the specified angle (in radians). - * @param {number} angle - The angle to rotate (in radians) - * @param {Vector2d} [v] - an optional point to rotate around - * @returns {Vector2d} Reference to this object for method chaining - */ - rotate(angle, v) { - let cx = 0; - let cy = 0; - - if (typeof v === "object") { - cx = v.x; - cy = v.y; - } - - const x = this.x - cx; - const y = this.y - cy; - - const c = Math.cos(angle); - const s = Math.sin(angle); - - return this._set(x * c - y * s + cx, x * s + y * c + cy); - } - - /** - * return the dot product of this vector and the passed one - * @param {Vector2d} v - * @returns {number} The dot product. - */ - dot(v) { - return this.x * v.x + this.y * v.y; - } - - /** - * return the cross product of this vector and the passed one - * @param {Vector2d} v - * @returns {number} The cross product. - */ - cross(v) { - return this.x * v.y - this.y * v.x; - } - - /** - * return the square length of this vector - * @returns {number} The length^2 of this vector. - */ - length2() { - return this.dot(this); - } - - /** - * return the length (magnitude) of this vector - * @returns {number} the length of this vector - */ - length() { - return Math.sqrt(this.length2()); - } - - /** - * Linearly interpolate between this vector and the given one. - * @param {Vector2d} v - * @param {number} alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one). - * @returns {Vector2d} Reference to this object for method chaining - */ - lerp(v, alpha) { - this.x += (v.x - this.x) * alpha; - this.y += (v.y - this.y) * alpha; - return this; - } - - /** - * interpolate the position of this vector towards the given one by the given maximum step. - * @param {Vector2d} target - * @param {number} step - the maximum step per iteration (Negative values will push the vector away from the target) - * @returns {Vector2d} Reference to this object for method chaining - */ - moveTowards(target, step) { - const angle = Math.atan2(target.y - this.y, target.x - this.x); - - const distance = this.distance(target); - - if (distance === 0 || (step >= 0 && distance <= step * step)) { - return target; - } - - this.x += Math.cos(angle) * step; - this.y += Math.sin(angle) * step; - - return this; - } - - /** - * return the distance between this vector and the passed one - * @param {Vector2d} v - * @returns {number} - */ - distance(v) { - const dx = this.x - v.x; - const dy = this.y - v.y; - return Math.sqrt(dx * dx + dy * dy); - } - - /** - * return the angle between this vector and the passed one - * @param {Vector2d} v - * @returns {number} angle in radians - */ - angle(v) { - return Math.acos(clamp(this.dot(v) / (this.length() * v.length()), -1, 1)); - } - - /** - * project this vector on to another vector. - * @param {Vector2d} v - The vector to project onto. - * @returns {Vector2d} Reference to this object for method chaining - */ - project(v) { - return this.scale(this.dot(v) / v.length2()); - } - - /** - * Project this vector onto a vector of unit length.
- * This is slightly more efficient than `project` when dealing with unit vectors. - * @param {Vector2d} v - The unit vector to project onto. - * @returns {Vector2d} Reference to this object for method chaining - */ - projectN(v) { - return this.scale(this.dot(v)); - } - - /** - * return a clone copy of this vector - * @returns {Vector2d} new me.Vector2d - */ - clone() { - return pool.pull("Vector2d", this.x, this.y); - } - - /** - * convert the object to a string representation - * @returns {string} - */ - toString() { - return "x:" + this.x + ",y:" + this.y; - } -} diff --git a/packages/melonjs/src/math/vector2d.ts b/packages/melonjs/src/math/vector2d.ts new file mode 100644 index 000000000..d47258550 --- /dev/null +++ b/packages/melonjs/src/math/vector2d.ts @@ -0,0 +1,433 @@ +import { clamp } from "./math.ts"; +import { createPool } from "../system/pool.ts"; + +/** + * a generic 2D Vector Object + */ +export class Vector2d { + x: number; + y: number; + + /** + * @param [x] - x value of the vector + * @param [y] - y value of the vector + */ + constructor(x: number | undefined = 0, y: number | undefined = 0) { + this.x = x; + this.y = y; + } + + /** + * @param [x] - x value of the vector + * @param [y] - y value of the vector + * @ignore + */ + onResetEvent(x = 0, y = 0) { + /** + * x value of the vector + */ + this.x = x; + /** + * y value of the vector + */ + this.y = y; + } + + /** + * set the Vector x and y properties to the given values + * @param x - x component of the vector + * @param y - y component of the vector + * @returns Reference to this object for method chaining + */ + set(x: number, y: number) { + this.x = x; + this.y = y; + return this; + } + + /** + * set the Vector x and y properties to 0 + * @returns Reference to this object for method chaining + */ + setZero() { + return this.set(0, 0); + } + + /** + * set the Vector x and y properties using the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + setV(v: Vector2d) { + return this.set(v.x, v.y); + } + + /** + * Add the passed vector to this vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + add(v: Vector2d) { + return this.set(this.x + v.x, this.y + v.y); + } + + /** + * Substract the passed vector to this vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + sub(v: Vector2d) { + return this.set(this.x - v.x, this.y - v.y); + } + + /** + * Multiply this vector values by the given scalar + * @param x x scale value + * @param [y] y scale value, if not passed, it uses the x value + * @returns Reference to this object for method chaining + */ + scale(x: number, y = x) { + return this.set(this.x * x, this.y * y); + } + + /** + * Convert this vector into isometric coordinate space + * @returns Reference to this object for method chaining + */ + toIso() { + return this.set(this.x - this.y, (this.x + this.y) * 0.5); + } + + /** + * Convert this vector into 2d coordinate space + * @returns Reference to this object for method chaining + */ + to2d() { + return this.set(this.y + this.x / 2, this.y - this.x / 2); + } + + /** + * Multiply this vector values by the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + scaleV(v: Vector2d) { + return this.set(this.x * v.x, this.y * v.y); + } + + /** + * Divide this vector values by the passed value + * @param n - the value to divide the vector by + * @returns Reference to this object for method chaining + */ + div(n: number) { + return this.set(this.x / n, this.y / n); + } + + /** + * Update this vector values to absolute values + * @returns Reference to this object for method chaining + */ + abs() { + return this.set( + this.x < 0 ? -this.x : this.x, + this.y < 0 ? -this.y : this.y, + ); + } + + /** + * Clamp the vector value within the specified value range + * @param low minimum component value + * @param high maximum component value + * @returns new me.Vector2d + */ + clamp(low: number, high: number) { + return new Vector2d(clamp(this.x, low, high), clamp(this.y, low, high)); + } + + /** + * Clamp this vector value within the specified value range + * @param low minimum component value + * @param high maximum component value + * @returns Reference to this object for method chaining + */ + clampSelf(low: number, high: number) { + return this.set(clamp(this.x, low, high), clamp(this.y, low, high)); + } + + /** + * Update this vector with the minimum value between this and the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + minV(v: Vector2d) { + return this.set(this.x < v.x ? this.x : v.x, this.y < v.y ? this.y : v.y); + } + + /** + * Update this vector with the maximum value between this and the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + maxV(v: Vector2d) { + return this.set(this.x > v.x ? this.x : v.x, this.y > v.y ? this.y : v.y); + } + + /** + * Floor the vector values + * @returns new Vector2d + */ + floor() { + return new Vector2d(Math.floor(this.x), Math.floor(this.y)); + } + + /** + * Floor this vector values + * @returns Reference to this object for method chaining + */ + floorSelf() { + return this.set(Math.floor(this.x), Math.floor(this.y)); + } + + /** + * Ceil the vector values + * @returns new Vector2d + */ + ceil() { + return new Vector2d(Math.ceil(this.x), Math.ceil(this.y)); + } + + /** + * Ceil this vector values + * @returns Reference to this object for method chaining + */ + ceilSelf() { + return this.set(Math.ceil(this.x), Math.ceil(this.y)); + } + + /** + * Negate the vector values + * @returns new Vector2d + */ + negate() { + return new Vector2d(-this.x, -this.y); + } + + /** + * Negate this vector values + * @returns Reference to this object for method chaining + */ + negateSelf() { + return this.set(-this.x, -this.y); + } + + /** + * Copy the x,y values of the passed vector to this one + * @param v other vector + * @returns Reference to this object for method chaining + */ + copy(v: Vector2d) { + return this.set(v.x, v.y); + } + + /** + * Checks if this vector is equal to another vector or a pair of coordinates. + * @param args - Either two numbers representing x and y coordinates or a single Vector2d object. + * @returns True if the coordinates are equal, false otherwise. + * @example + * let v1 = new Vector2d(3, 4); + * let v2 = new Vector2d(3, 4); + * v1.equals(v2); // returns true + * @example + * let v = new Vector2d(3, 4); + * v.equals(3, 4); // returns true + */ + equals(...args: [number, number] | [Vector2d]) { + if (args.length === 2) { + return this.x === args[0] && this.y === args[1]; + } + return this.x === args[0].x && this.y === args[0].y; + } + + /** + * normalize this vector (scale the vector so that its magnitude is 1) + * @returns Reference to this object for method chaining + */ + normalize() { + return this.div(this.length() || 1); + } + + /** + * change this vector to be perpendicular to what it was before.
+ * (Effectively rotates it 90 degrees in a clockwise direction) + * @returns Reference to this object for method chaining + */ + perp() { + return this.set(this.y, -this.x); + } + + /** + * Rotate this vector (counter-clockwise) by the specified angle (in radians). + * @param angle - The angle to rotate (in radians) + * @param [v] - an optional point to rotate around + * @returns Reference to this object for method chaining + */ + rotate(angle: number, v?: { x: number; y: number } | undefined) { + let cx = 0; + let cy = 0; + + if (v) { + cx = v.x; + cy = v.y; + } + + const x = this.x - cx; + const y = this.y - cy; + + const c = Math.cos(angle); + const s = Math.sin(angle); + + return this.set(x * c - y * s + cx, x * s + y * c + cy); + } + + /** + * return the dot product of this vector and the passed one + * @param v other vector + * @returns The dot product. + */ + dot(v: Vector2d) { + return this.x * v.x + this.y * v.y; + } + + /** + * return the cross product of this vector and the passed one + * @param v other vector + * @returns The cross product. + */ + cross(v: Vector2d) { + return this.x * v.y - this.y * v.x; + } + + /** + * return the square length of this vector + * @returns The length^2 of this vector. + */ + length2() { + return this.dot(this); + } + + /** + * return the length (magnitude) of this vector + * @returns the length of this vector + */ + length() { + return Math.sqrt(this.length2()); + } + + /** + * Linearly interpolate between this vector and the given one. + * @param v other vector + * @param alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one). + * @returns Reference to this object for method chaining + */ + lerp(v: Vector2d, alpha: number) { + this.x += (v.x - this.x) * alpha; + this.y += (v.y - this.y) * alpha; + return this; + } + + /** + * interpolate the position of this vector towards the given one by the given maximum step. + * @param target vector to rotate towards + * @param step - the maximum step per iteration (Negative values will push the vector away from the target) + * @returns Reference to this object for method chaining + */ + moveTowards(target: Vector2d, step: number) { + const angle = Math.atan2(target.y - this.y, target.x - this.x); + + const distance = this.distance(target); + + if (distance === 0 || (step >= 0 && distance <= step * step)) { + return target; + } + + this.x += Math.cos(angle) * step; + this.y += Math.sin(angle) * step; + + return this; + } + + /** + * Calculates the Euclidean distance between this vector and another vector. + * @param v - The vector to which the distance is calculated. + * @returns The Euclidean distance between this vector and the given vector. + * @example + * let v1 = new Vector2d(3, 4); + * let v2 = new Vector2d(6, 8); + * v1.distance(v2); // returns 5 + */ + distance(v: Vector2d) { + const dx = this.x - v.x; + const dy = this.y - v.y; + return Math.sqrt(dx * dx + dy * dy); + } + + /** + * return the angle between this vector and the passed one + * @param v other vector + * @returns angle in radians + */ + angle(v: Vector2d) { + return Math.acos(clamp(this.dot(v) / (this.length() * v.length()), -1, 1)); + } + + /** + * project this vector on to another vector. + * @param v - The vector to project onto. + * @returns Reference to this object for method chaining + */ + project(v: Vector2d) { + return this.scale(this.dot(v) / v.length2()); + } + + /** + * Project this vector onto a vector of unit length.
+ * This is slightly more efficient than `project` when dealing with unit vectors. + * @param v - The unit vector to project onto. + * @returns Reference to this object for method chaining + */ + projectN(v: Vector2d) { + return this.scale(this.dot(v)); + } + + /** + * return a clone copy of this vector + * @returns new Vector2d + */ + clone() { + return vector2dPool.get(this.x, this.y); + } + + /** + * convert the object to a string representation + * @returns stringified representation of this vector + */ + toString() { + return `x:${this.x},y:${this.y}` as const; + } +} + +export const vector2dPool = createPool< + Vector2d, + [x?: number | undefined, y?: number | undefined] +>((x, y) => { + const vector = new Vector2d(x, y); + + return { + instance: vector, + reset(x = 0, y = 0) { + vector.x = x; + vector.y = y; + }, + }; +}); diff --git a/packages/melonjs/src/math/vector3.js b/packages/melonjs/src/math/vector3.js deleted file mode 100644 index b2de923eb..000000000 --- a/packages/melonjs/src/math/vector3.js +++ /dev/null @@ -1,503 +0,0 @@ -import { clamp } from "./math.ts"; -import pool from "./../system/pooling.js"; - -/** - * additional import for TypeScript - * @import Vector2d from "./vector2.js"; - */ - -/** - * a generic 3D Vector Object - */ -export default class Vector3d { - /** - * @param {number} [x=0] - x value of the vector - * @param {number} [y=0] - y value of the vector - * @param {number} [z=0] - z value of the vector - */ - constructor(x = 0, y = 0, z = 0) { - this.onResetEvent(x, y, z); - } - - /** - * @param {number} [x=0] - * @param {number} [y=0] - * @param {number} [z=0] - * @ignore - */ - onResetEvent(x = 0, y = 0, z = 0) { - /** - * x value of the vector - * @type {number} - */ - this.x = x; - - /** - * y value of the vector - * @type {number} - */ - this.y = y; - - /** - * z value of the vector - * @type {number} - */ - this.z = z; - } - - /** - * @param {number} x - * @param {number} y - * @param {number} [z=0] - * @ignore - */ - _set(x, y, z = 0) { - this.x = x; - this.y = y; - this.z = z; - return this; - } - - /** - * set the Vector x and y properties to the given values - * @param {number} x - * @param {number} y - * @param {number} [z=0] - * @returns {Vector3d} Reference to this object for method chaining - */ - set(x, y, z) { - if (x !== +x || y !== +y || (typeof z !== "undefined" && z !== +z)) { - throw new Error("invalid x, y, z parameters (not a number)"); - } - return this._set(x, y, z); - } - - /** - * set the Vector x and y properties to 0 - * @returns {Vector3d} Reference to this object for method chaining - */ - setZero() { - return this.set(0, 0, 0); - } - - /** - * set the Vector x and y properties using the passed vector - * @param {Vector2d|Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - setV(v) { - return this._set(v.x, v.y, v.z); - } - - /** - * Add the passed vector to this vector - * @param {Vector2d|Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - add(v) { - return this._set(this.x + v.x, this.y + v.y, this.z + (v.z || 0)); - } - - /** - * Substract the passed vector to this vector - * @param {Vector2d|Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - sub(v) { - return this._set(this.x - v.x, this.y - v.y, this.z - (v.z || 0)); - } - - /** - * Multiply this vector values by the given scalar - * @param {number} x - * @param {number} [y=x] - * @param {number} [z=1] - * @returns {Vector3d} Reference to this object for method chaining - */ - scale(x, y = x, z = 1) { - return this._set(this.x * x, this.y * y, this.z * z); - } - - /** - * Multiply this vector values by the passed vector - * @param {Vector2d|Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - scaleV(v) { - return this.scale(v.x, v.y, v.z); - } - - /** - * Convert this vector into isometric coordinate space - * @returns {Vector3d} Reference to this object for method chaining - */ - toIso() { - return this._set(this.x - this.y, (this.x + this.y) * 0.5, this.z); - } - - /** - * Convert this vector into 2d coordinate space - * @returns {Vector3d} Reference to this object for method chaining - */ - to2d() { - return this._set(this.y + this.x / 2, this.y - this.x / 2, this.z); - } - - /** - * Divide this vector values by the passed value - * @param {number} n - the value to divide the vector by - * @returns {Vector3d} Reference to this object for method chaining - */ - div(n) { - return this._set(this.x / n, this.y / n, this.z / n); - } - - /** - * Update this vector values to absolute values - * @returns {Vector3d} Reference to this object for method chaining - */ - abs() { - return this._set( - this.x < 0 ? -this.x : this.x, - this.y < 0 ? -this.y : this.y, - this.z < 0 ? -this.z : this.z, - ); - } - - /** - * Clamp the vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {Vector3d} new me.Vector3d - */ - clamp(low, high) { - return new Vector3d( - clamp(this.x, low, high), - clamp(this.y, low, high), - clamp(this.z, low, high), - ); - } - - /** - * Clamp this vector value within the specified value range - * @param {number} low - * @param {number} high - * @returns {Vector3d} Reference to this object for method chaining - */ - clampSelf(low, high) { - return this._set( - clamp(this.x, low, high), - clamp(this.y, low, high), - clamp(this.z, low, high), - ); - } - - /** - * Update this vector with the minimum value between this and the passed vector - * @param {Vector2d|Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - minV(v) { - const _vz = v.z || 0; - return this._set( - this.x < v.x ? this.x : v.x, - this.y < v.y ? this.y : v.y, - this.z < _vz ? this.z : _vz, - ); - } - - /** - * Update this vector with the maximum value between this and the passed vector - * @param {Vector2d|Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - maxV(v) { - const _vz = v.z || 0; - return this._set( - this.x > v.x ? this.x : v.x, - this.y > v.y ? this.y : v.y, - this.z > _vz ? this.z : _vz, - ); - } - - /** - * Floor the vector values - * @returns {Vector3d} new me.Vector3d - */ - floor() { - return new Vector3d( - Math.floor(this.x), - Math.floor(this.y), - Math.floor(this.z), - ); - } - - /** - * Floor this vector values - * @returns {Vector3d} Reference to this object for method chaining - */ - floorSelf() { - return this._set( - Math.floor(this.x), - Math.floor(this.y), - Math.floor(this.z), - ); - } - - /** - * Ceil the vector values - * @returns {Vector3d} new me.Vector3d - */ - ceil() { - return new Vector3d( - Math.ceil(this.x), - Math.ceil(this.y), - Math.ceil(this.z), - ); - } - - /** - * Ceil this vector values - * @returns {Vector3d} Reference to this object for method chaining - */ - ceilSelf() { - return this._set(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z)); - } - - /** - * Negate the vector values - * @returns {Vector3d} new me.Vector3d - */ - negate() { - return new Vector3d(-this.x, -this.y, -this.z); - } - - /** - * Negate this vector values - * @returns {Vector3d} Reference to this object for method chaining - */ - negateSelf() { - return this._set(-this.x, -this.y, -this.z); - } - - /** - * Copy the components of the given vector into this one - * @param {Vector2d|Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - copy(v) { - return this._set(v.x, v.y, v.z || 0); - } - - /** - * return true if this vector is equal to the given values or vector - * @param {number|Vector2d|Vector3d} x - * @param {number} [y] - * @param {number} [z] - * @returns {boolean} true if both vectros are equals - */ - equals(...args) { - let _x; - let _y; - let _z; - if (args.length >= 2) { - // x, y, z - [_x, _y, _z] = args; - } else { - // vector - [_x, _y, _z] = [args[0].x, args[0].y, args[0].z]; - } - - if (typeof _z === "undefined") { - _z = this.z; - } - - return this.x === _x && this.y === _y && this.z === _z; - } - - /** - * normalize this vector (scale the vector so that its magnitude is 1) - * @returns {Vector3d} Reference to this object for method chaining - */ - normalize() { - return this.div(this.length() || 1); - } - - /** - * change this vector to be perpendicular to what it was before.
- * (Effectively rotates it 90 degrees in a clockwise direction around the z axis) - * @returns {Vector3d} Reference to this object for method chaining - */ - perp() { - return this._set(this.y, -this.x, this.z); - } - - /** - * Rotate this vector (counter-clockwise) by the specified angle (in radians) around the z axis - * @param {number} angle - The angle to rotate (in radians) - * @param {Vector2d} [v] - an optional point to rotate around (on the same z axis) - * @returns {Vector3d} Reference to this object for method chaining - */ - rotate(angle, v) { - let cx = 0; - let cy = 0; - - if (typeof v === "object") { - cx = v.x; - cy = v.y; - } - - // TODO also rotate on the z axis if the given vector is a 3d one - const x = this.x - cx; - const y = this.y - cy; - - const c = Math.cos(angle); - const s = Math.sin(angle); - - return this._set(x * c - y * s + cx, x * s + y * c + cy, this.z); - } - - /** - * return the dot product of this vector and the passed one - * @param {Vector2d|Vector3d} v - * @returns {number} The dot product. - */ - dot(v) { - return ( - this.x * v.x + - this.y * v.y + - this.z * (typeof v.z !== "undefined" ? v.z : this.z) - ); - } - - /** - * calculate the cross product of this vector and the passed one - * @param {Vector3d} v - * @returns {Vector3d} Reference to this object for method chaining - */ - cross(v) { - const ax = this.x; - const ay = this.y; - const az = this.z; - const bx = v.x; - const by = v.y; - const bz = v.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - - return this; - } - - /** - * return the square length of this vector - * @returns {number} The length^2 of this vector. - */ - length2() { - return this.dot(this); - } - - /** - * return the length (magnitude) of this vector - * @returns {number} the length of this vector - */ - length() { - return Math.sqrt(this.length2()); - } - - /** - * Linearly interpolate between this vector and the given one. - * @param {Vector3d} v - * @param {number} alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one). - * @returns {Vector3d} Reference to this object for method chaining - */ - lerp(v, alpha) { - this.x += (v.x - this.x) * alpha; - this.y += (v.y - this.y) * alpha; - this.z += (v.z - this.z) * alpha; - return this; - } - - /** - * interpolate the position of this vector on the x and y axis towards the given one by the given maximum step. - * @param {Vector2d|Vector3d} target - * @param {number} step - the maximum step per iteration (Negative values will push the vector away from the target) - * @returns {Vector3d} Reference to this object for method chaining - */ - moveTowards(target, step) { - const angle = Math.atan2(target.y - this.y, target.x - this.x); - - const dx = this.x - target.x; - const dy = this.y - target.y; - - const distance = Math.sqrt(dx * dx + dy * dy); - - if (distance === 0 || (step >= 0 && distance <= step * step)) { - return target; - } - - this.x += Math.cos(angle) * step; - this.y += Math.sin(angle) * step; - - return this; - } - - /** - * return the distance between this vector and the passed one - * @param {Vector2d|Vector3d} v - * @returns {number} - */ - distance(v) { - const dx = this.x - v.x; - const dy = this.y - v.y; - const dz = this.z - (v.z || 0); - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } - - /** - * return the angle between this vector and the passed one - * @param {Vector2d|Vector3d} v - * @returns {number} angle in radians - */ - angle(v) { - return Math.acos(clamp(this.dot(v) / (this.length() * v.length()), -1, 1)); - } - - /** - * project this vector on to another vector. - * @param {Vector2d|Vector3d} v - The vector to project onto. - * @returns {Vector3d} Reference to this object for method chaining - */ - project(v) { - const ratio = this.dot(v) / v.length2(); - return this.scale(ratio, ratio, ratio); - } - - /** - * Project this vector onto a vector of unit length.
- * This is slightly more efficient than `project` when dealing with unit vectors. - * @param {Vector2d|Vector3d} v - The unit vector to project onto. - * @returns {Vector3d} Reference to this object for method chaining - */ - projectN(v) { - const ratio = this.dot(v) / v.length2(); - return this.scale(ratio, ratio, ratio); - } - - /** - * return a clone copy of this vector - * @returns {Vector3d} new me.Vector3d - */ - clone() { - return pool.pull("Vector3d", this.x, this.y, this.z); - } - - /** - * convert the object to a string representation - * @returns {string} - */ - toString() { - return "x:" + this.x + ",y:" + this.y + ",z:" + this.z; - } -} diff --git a/packages/melonjs/src/math/vector3d.ts b/packages/melonjs/src/math/vector3d.ts new file mode 100644 index 000000000..f03d050d8 --- /dev/null +++ b/packages/melonjs/src/math/vector3d.ts @@ -0,0 +1,478 @@ +import { clamp } from "./math.ts"; +import { createPool } from "../system/pool.ts"; +import { Vector2d } from "./vector2d.ts"; + +/** + * a generic 3D Vector Object + */ +export class Vector3d { + x: number; + y: number; + z: number; + + /** + * @param [x] - x value of the vector + * @param [y] - y value of the vector + * @param [z] - z value of the vector + */ + constructor(x = 0, y = 0, z = 0) { + this.onResetEvent(x, y, z); + } + + onResetEvent(x = 0, y = 0, z = 0) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * set the Vector x and y properties to the given values + * @param x x component + * @param y y component + * @param [z] z component + * @returns Reference to this object for method chaining + */ + set(x: number, y: number, z: number | undefined = 0) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + /** + * set the Vector x and y properties to 0 + * @returns Reference to this object for method chaining + */ + setZero() { + return this.set(0, 0, 0); + } + + /** + * set the Vector x and y properties using the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + setV(v: Vector2d | Vector3d) { + return this.set(v.x, v.y, "z" in v ? v.z : undefined); + } + + /** + * Add the passed vector to this vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + add(v: Vector2d | Vector3d) { + return this.set(this.x + v.x, this.y + v.y, this.z + ("z" in v ? v.z : 0)); + } + + /** + * Substract the passed vector to this vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + sub(v: Vector2d | Vector3d) { + return this.set(this.x - v.x, this.y - v.y, this.z - ("z" in v ? v.z : 0)); + } + + /** + * Multiply this vector values by the given scalar + * @param x x component + * @param [y] y component + * @param [z] z component + * @returns Reference to this object for method chaining + */ + scale(x: number, y = x, z = 1) { + return this.set(this.x * x, this.y * y, this.z * z); + } + + /** + * Multiply this vector values by the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + scaleV(v: Vector3d) { + return this.scale(v.x, v.y, v.z); + } + + /** + * Convert this vector into isometric coordinate space + * @returns Reference to this object for method chaining + */ + toIso() { + return this.set(this.x - this.y, (this.x + this.y) * 0.5, this.z); + } + + /** + * Convert this vector into 2d coordinate space + * @returns Reference to this object for method chaining + */ + to2d() { + return this.set(this.y + this.x / 2, this.y - this.x / 2, this.z); + } + + /** + * Divide this vector values by the passed value + * @param n - the value to divide the vector by + * @returns Reference to this object for method chaining + */ + div(n: number) { + return this.set(this.x / n, this.y / n, this.z / n); + } + + /** + * Update this vector values to absolute values + * @returns Reference to this object for method chaining + */ + abs() { + return this.set( + this.x < 0 ? -this.x : this.x, + this.y < 0 ? -this.y : this.y, + this.z < 0 ? -this.z : this.z, + ); + } + + /** + * Clamp the vector value within the specified value range + * @param low lower bound + * @param high upper bound + * @returns new Vector3d + */ + clamp(low: number, high: number) { + return new Vector3d( + clamp(this.x, low, high), + clamp(this.y, low, high), + clamp(this.z, low, high), + ); + } + + /** + * Clamp this vector value within the specified value range + * @param low lower bound + * @param high upper bound + * @returns Reference to this object for method chaining + */ + clampSelf(low: number, high: number) { + return this.set( + clamp(this.x, low, high), + clamp(this.y, low, high), + clamp(this.z, low, high), + ); + } + + /** + * Update this vector with the minimum value between this and the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + minV(v: Vector2d | Vector3d) { + const _vz = "z" in v ? v.z : 0; + return this.set( + this.x < v.x ? this.x : v.x, + this.y < v.y ? this.y : v.y, + this.z < _vz ? this.z : _vz, + ); + } + + /** + * Update this vector with the maximum value between this and the passed vector + * @param v other vector + * @returns Reference to this object for method chaining + */ + maxV(v: Vector2d | Vector3d) { + const _vz = "z" in v ? v.z : 0; + return this.set( + this.x > v.x ? this.x : v.x, + this.y > v.y ? this.y : v.y, + this.z > _vz ? this.z : _vz, + ); + } + + /** + * Floor the vector values + * @returns new Vector3d + */ + floor() { + return new Vector3d( + Math.floor(this.x), + Math.floor(this.y), + Math.floor(this.z), + ); + } + + /** + * Floor this vector values + * @returns Reference to this object for method chaining + */ + floorSelf() { + return this.set(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z)); + } + + /** + * Ceil the vector values + * @returns new Vector3d + */ + ceil() { + return new Vector3d( + Math.ceil(this.x), + Math.ceil(this.y), + Math.ceil(this.z), + ); + } + + /** + * Ceil this vector values + * @returns Reference to this object for method chaining + */ + ceilSelf() { + return this.set(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z)); + } + + /** + * Negate the vector values + * @returns new Vector3d + */ + negate() { + return new Vector3d(-this.x, -this.y, -this.z); + } + + /** + * Negate this vector values + * @returns Reference to this object for method chaining + */ + negateSelf() { + return this.set(-this.x, -this.y, -this.z); + } + + /** + * Copy the components of the given vector into this one + * @param v other vector + * @returns Reference to this object for method chaining + */ + copy(v: Vector2d | Vector3d) { + return this.set(v.x, v.y, "z" in v ? v.z : 0); + } + + /** + * return true if this vector is equal to the given values or vector + * @param vectorOrValues other vector or vector components + * @returns true if both vectros are equals + */ + equals(x: number, y: number, z?: number | undefined): boolean; + equals(vector: Vector2d | Vector3d): boolean; + equals(xOrVector: number | Vector2d | Vector3d, y?: number, z?: number) { + let _x: number; + let _y: number; + let _z: number; + if (xOrVector instanceof Vector2d || xOrVector instanceof Vector3d) { + [_x, _y, _z] = [ + xOrVector.x, + xOrVector.y, + "z" in xOrVector ? xOrVector.z : this.z, + ]; + } else { + _x = xOrVector; + _y = y!; + _z = z ?? this.z; + } + + return this.x === _x && this.y === _y && this.z === _z; + } + + /** + * normalize this vector (scale the vector so that its magnitude is 1) + * @returns Reference to this object for method chaining + */ + normalize() { + return this.div(this.length() || 1); + } + + /** + * change this vector to be perpendicular to what it was before.
+ * (Effectively rotates it 90 degrees in a clockwise direction around the z axis) + * @returns Reference to this object for method chaining + */ + perp() { + return this.set(this.y, -this.x, this.z); + } + + /** + * Rotate this vector (counter-clockwise) by the specified angle (in radians) around the z axis + * @param angle - The angle to rotate (in radians) + * @param [v] - an optional point to rotate around (on the same z axis) + * @returns Reference to this object for method chaining + */ + rotate(angle: number, v?: { x: number; y: number } | undefined) { + let cx = 0; + let cy = 0; + + if (v) { + cx = v.x; + cy = v.y; + } + + // TODO also rotate on the z axis if the given vector is a 3d one + const x = this.x - cx; + const y = this.y - cy; + + const c = Math.cos(angle); + const s = Math.sin(angle); + + return this.set(x * c - y * s + cx, x * s + y * c + cy, this.z); + } + + /** + * return the dot product of this vector and the passed one + * @param v other vector + * @returns The dot product. + */ + dot(v: Vector2d | Vector3d) { + return this.x * v.x + this.y * v.y + this.z * ("z" in v ? v.z : this.z); + } + + /** + * calculate the cross product of this vector and the passed one + * @param v other vector + * @returns Reference to this object for method chaining + */ + cross(v: Vector3d) { + const ax = this.x; + const ay = this.y; + const az = this.z; + const bx = v.x; + const by = v.y; + const bz = v.z; + + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; + + return this; + } + + /** + * return the square length of this vector + * @returns The length^2 of this vector. + */ + length2(): number { + return this.dot(this); + } + + /** + * return the length (magnitude) of this vector + * @returns the length of this vector + */ + length() { + return Math.sqrt(this.length2()); + } + + /** + * Linearly interpolate between this vector and the given one. + * @param v other vector + * @param alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one). + * @returns Reference to this object for method chaining + */ + lerp(v: Vector3d, alpha: number) { + this.x += (v.x - this.x) * alpha; + this.y += (v.y - this.y) * alpha; + this.z += (v.z - this.z) * alpha; + return this; + } + + /** + * interpolate the position of this vector on the x and y axis towards the given one by the given maximum step. + * @param target other vector + * @param step - the maximum step per iteration (Negative values will push the vector away from the target) + * @returns Reference to this object for method chaining + */ + moveTowards(target: Vector2d | Vector3d, step: number) { + const angle = Math.atan2(target.y - this.y, target.x - this.x); + + const dx = this.x - target.x; + const dy = this.y - target.y; + + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance === 0 || (step >= 0 && distance <= step * step)) { + return target; + } + + this.x += Math.cos(angle) * step; + this.y += Math.sin(angle) * step; + + return this; + } + + /** + * return the distance between this vector and the passed one + * @param v other vector + * @returns distance + */ + distance(v: Vector2d | Vector3d) { + const dx = this.x - v.x; + const dy = this.y - v.y; + const dz = this.z - ("z" in v ? v.z : 0); + return Math.sqrt(dx * dx + dy * dy + dz * dz); + } + + /** + * return the angle between this vector and the passed one + * @param v other vector + * @returns angle in radians + */ + angle(v: Vector2d | Vector3d) { + return Math.acos(clamp(this.dot(v) / (this.length() * v.length()), -1, 1)); + } + + /** + * project this vector on to another vector. + * @param v - The vector to project onto. + * @returns Reference to this object for method chaining + */ + project(v: Vector2d | Vector3d) { + const ratio = this.dot(v) / v.length2(); + return this.scale(ratio, ratio, ratio); + } + + /** + * Project this vector onto a vector of unit length.
+ * This is slightly more efficient than `project` when dealing with unit vectors. + * @param v - The unit vector to project onto. + * @returns Reference to this object for method chaining + */ + projectN(v: Vector2d | Vector3d) { + const ratio = this.dot(v) / v.length2(); + return this.scale(ratio, ratio, ratio); + } + + /** + * return a clone copy of this vector + * @returns new Vector3d + */ + clone() { + return vector3dPool.get(this.x, this.y, this.z); + } + + /** + * convert the object to a string representation + * @returns stringified representation + */ + toString() { + return `x:${this.x},y:${this.y},z:${this.z}` as const; + } +} + +export const vector3dPool = createPool< + Vector3d, + [x?: number | undefined, y?: number | undefined, z?: number | undefined] +>((x, y, z) => { + const vector = new Vector3d(x, y, z); + + return { + instance: vector, + reset(x = 0, y = 0, z = 0) { + vector.x = x; + vector.y = y; + vector.z = z; + }, + }; +}); diff --git a/packages/melonjs/src/particles/particle.js b/packages/melonjs/src/particles/particle.js index 70fe144ee..ba4ca1103 100644 --- a/packages/melonjs/src/particles/particle.js +++ b/packages/melonjs/src/particles/particle.js @@ -1,7 +1,7 @@ -import pool from "./../system/pooling.js"; import timer from "./../system/timer.ts"; import { randomFloat, clamp } from "./../math/math.ts"; import Renderable from "./../renderable/renderable.js"; +import { vector2dPool } from "../math/vector2d.ts"; /** * @import ParticleEmitter from "./emitter.js"; @@ -35,7 +35,7 @@ export default class Particle extends Renderable { this.currentTransform.identity(); } else { // particle velocity - this.vel = pool.pull("Vector2d"); + this.vel = vector2dPool.get(); } this.image = emitter.settings.image; diff --git a/packages/melonjs/src/physics/body.js b/packages/melonjs/src/physics/body.js index 27c15c33c..5dc4e2f38 100644 --- a/packages/melonjs/src/physics/body.js +++ b/packages/melonjs/src/physics/body.js @@ -1,13 +1,14 @@ import Rect from "./../geometries/rectangle.js"; import Ellipse from "./../geometries/ellipse.js"; import Polygon from "./../geometries/poly.js"; -import Bounds from "./bounds.js"; +import { Bounds, boundsPool } from "./bounds.ts"; import pool from "./../system/pooling.js"; import { collision } from "./collision.js"; import timer from "./../system/timer.ts"; import { clamp } from "./../math/math.ts"; -import Point from "../geometries/point.js"; +import { Point, pointPool } from "../geometries/point.ts"; import { remove } from "../utils/array.ts"; +import { vector2dPool } from "../math/vector2d.ts"; /** * @import Entity from "./../renderable/entity/entity.js"; @@ -16,7 +17,7 @@ import { remove } from "../utils/array.ts"; * @import Sprite from "./../renderable/sprite.js"; * @import NineSliceSprite from "./../renderable/nineslicesprite.js"; * @import Line from "./../geometries/line.js"; - * @import Vector2d from "./../math/vector2.js"; + * @import {Vector2d} from "../math/vector2d.js"; * @import ResponseObject from "./response.js"; **/ @@ -46,7 +47,7 @@ export default class Body { * @public * @type {Bounds} */ - this.bounds = pool.pull("Bounds"); + this.bounds = boundsPool.get(); } if (typeof this.shapes === "undefined") { @@ -89,7 +90,7 @@ export default class Body { * @type {Vector2d} * @default <0,0> */ - this.vel = pool.pull("Vector2d"); + this.vel = vector2dPool.get(); } this.vel.set(0, 0); @@ -116,7 +117,7 @@ export default class Body { * } * } */ - this.force = pool.pull("Vector2d"); + this.force = vector2dPool.get(); } this.force.set(0, 0); @@ -127,7 +128,7 @@ export default class Body { * @type {Vector2d} * @default <0,0> */ - this.friction = pool.pull("Vector2d"); + this.friction = vector2dPool.get(); } this.friction.set(0, 0); @@ -155,7 +156,7 @@ export default class Body { * @type {Vector2d} * @default <490,490> */ - this.maxVel = pool.pull("Vector2d"); + this.maxVel = vector2dPool.get(); } // cap by default to half the default gravity force this.maxVel.set(490, 490); @@ -669,13 +670,17 @@ export default class Body { */ destroy() { // push back instance into object pool - pool.push(this.bounds); - pool.push(this.vel); - pool.push(this.force); - pool.push(this.friction); - pool.push(this.maxVel); + boundsPool.release(this.bounds); + vector2dPool.release(this.vel); + vector2dPool.release(this.force); + vector2dPool.release(this.friction); + vector2dPool.release(this.maxVel); this.shapes.forEach((shape) => { - pool.push(shape, false); + if (shape instanceof Point) { + pointPool.release(shape); + } else { + pool.push(shape); + } }); // set to undefined diff --git a/packages/melonjs/src/physics/bounds.js b/packages/melonjs/src/physics/bounds.js deleted file mode 100644 index 9e848b14a..000000000 --- a/packages/melonjs/src/physics/bounds.js +++ /dev/null @@ -1,437 +0,0 @@ -import pool from "./../system/pooling.js"; -import Vector2d from "./../math/vector2.js"; - -/** - * @import Point from "./../geometries/point.js"; - * @import Rect from "./../geometries/rectangle.js"; - * @import Polygon from "./../geometries/poly.js"; - **/ - -/** - * a bound object contains methods for creating and manipulating axis-aligned bounding boxes (AABB). - */ -export default class Bounds { - /** - * @param {Vector2d[]|Point[]} [vertices] - an array of Vector2d or Point - */ - constructor(vertices) { - /** @ignore */ - this._center = new Vector2d(); - this.onResetEvent(vertices); - - /** - * the object type (used internally) - * @type {string} - * @default "Bounds" - */ - this.type = "Bounds"; - } - - /** - * @ignore - */ - onResetEvent(vertices) { - if (typeof this.min === "undefined") { - this.min = { x: Infinity, y: Infinity }; - this.max = { x: -Infinity, y: -Infinity }; - } else { - this.clear(); - } - if (typeof vertices !== "undefined") { - this.update(vertices); - } - } - - /** - * reset the bound - */ - clear() { - this.setMinMax(Infinity, Infinity, -Infinity, -Infinity); - } - - /** - * sets the bounds to the given min and max value - * @param {number} minX - * @param {number} minY - * @param {number} maxX - * @param {number} maxY - */ - setMinMax(minX, minY, maxX, maxY) { - this.min.x = minX; - this.min.y = minY; - - this.max.x = maxX; - this.max.y = maxY; - } - - /** - * x position of the bound - * @type {number} - */ - get x() { - return this.min.x; - } - - set x(value) { - const deltaX = this.max.x - this.min.x; - this.min.x = value; - this.max.x = value + deltaX; - } - - /** - * y position of the bounds - * @type {number} - */ - get y() { - return this.min.y; - } - - set y(value) { - const deltaY = this.max.y - this.min.y; - - this.min.y = value; - this.max.y = value + deltaY; - } - - /** - * width of the bounds - * @type {number} - */ - get width() { - return this.max.x - this.min.x; - } - - set width(value) { - this.max.x = this.min.x + value; - } - - /** - * width of the bounds - * @type {number} - */ - get height() { - return this.max.y - this.min.y; - } - - set height(value) { - this.max.y = this.min.y + value; - } - - /** - * left coordinate of the bound - * @type {number} - */ - get left() { - return this.min.x; - } - - /** - * right coordinate of the bound - * @type {number} - */ - get right() { - return this.max.x; - } - - /** - * top coordinate of the bound - * @type {number} - */ - get top() { - return this.min.y; - } - - /** - * bottom coordinate of the bound - * @type {number} - */ - get bottom() { - return this.max.y; - } - - /** - * center position of the bound on the x axis - * @type {number} - */ - get centerX() { - return this.min.x + this.width / 2; - } - - /** - * center position of the bound on the y axis - * @type {number} - */ - get centerY() { - return this.min.y + this.height / 2; - } - - /** - * return the center position of the bound - * @type {Vector2d} - */ - get center() { - return this._center.set(this.centerX, this.centerY); - } - - /** - * center the bounds position around the given coordinates - * @param {number} x - the x coordinate around which to center this bounds - * @param {number} y - the y coordinate around which to center this bounds - */ - centerOn(x, y) { - this.shift(x - this.width / 2, y - this.height / 2); - return this; - } - - /** - * Updates bounds using the given vertices - * @param {Vector2d[]|Point[]} vertices - an array of Vector2d or Point - */ - update(vertices) { - this.add(vertices, true); - } - - /** - * add the given vertices to the bounds definition. - * @param {Vector2d[]|Point[]} vertices - an array of Vector2d or Point - * @param {boolean} [clear=false] - either to reset the bounds before adding the new vertices - */ - add(vertices, clear = false) { - const verticeCount = vertices.length; - if (clear === true) { - this.clear(); - } - for (let i = 0; i < verticeCount; i++) { - const vertex = vertices[i]; - if (vertex.x > this.max.x) { - this.max.x = vertex.x; - } - if (vertex.x < this.min.x) { - this.min.x = vertex.x; - } - if (vertex.y > this.max.y) { - this.max.y = vertex.y; - } - if (vertex.y < this.min.y) { - this.min.y = vertex.y; - } - } - } - - /** - * add the given bounds to the bounds definition. - * @param {Bounds} bounds - * @param {boolean} [clear=false] - either to reset the bounds before adding the new vertices - */ - addBounds(bounds, clear = false) { - if (clear === true) { - this.max.x = bounds.max.x; - this.min.x = bounds.min.x; - this.max.y = bounds.max.y; - this.min.y = bounds.min.y; - } else { - if (bounds.max.x > this.max.x) { - this.max.x = bounds.max.x; - } - if (bounds.min.x < this.min.x) { - this.min.x = bounds.min.x; - } - if (bounds.max.y > this.max.y) { - this.max.y = bounds.max.y; - } - if (bounds.min.y < this.min.y) { - this.min.y = bounds.min.y; - } - } - } - - /** - * add the given point to the bounds definition. - * @param {Vector2d|Point} point - the vector or point to be added to the bounds - * @param {Matrix2d} [m] - an optional transform to apply to the given point (if the given point is a Vector2d) - */ - addPoint(point, m) { - if (typeof m !== "undefined") { - // only Vectors object have a rotate function - point = m.apply(point); - } - this.min.x = Math.min(this.min.x, point.x); - this.max.x = Math.max(this.max.x, point.x); - this.min.y = Math.min(this.min.y, point.y); - this.max.y = Math.max(this.max.y, point.y); - } - - /** - * add the given quad coordinates to this bound definition, multiplied by the given matrix - * @param {number} x0 - left X coordinates of the quad - * @param {number} y0 - top Y coordinates of the quad - * @param {number} x1 - right X coordinates of the quad - * @param {number} y1 - bottom y coordinates of the quad - * @param {Matrix2d} [m] - an optional transform to apply to the given frame coordinates - */ - addFrame(x0, y0, x1, y1, m) { - const v = pool.pull("Point"); - - this.addPoint(v.set(x0, y0), m); - this.addPoint(v.set(x1, y0), m); - this.addPoint(v.set(x0, y1), m); - this.addPoint(v.set(x1, y1), m); - - pool.push(v); - } - - /** - * Returns true if the bounds contains the given point. - * @param {number|Vector2d} x - x coordinate or a vector point to check - * @param {number} [y] - y coordinate - * @returns {boolean} True if the bounds contain the point, otherwise false - * @example - * if (bounds.contains(10, 10)) { - * // do something - * } - * // or - * if (bounds.contains(myVector2d)) { - * // do something - * } - */ - contains() { - const arg0 = arguments[0]; - let _x1; - let _x2; - let _y1; - let _y2; - if (arguments.length === 2) { - // x, y - _x1 = _x2 = arg0; - _y1 = _y2 = arguments[1]; - } else { - if (typeof arg0.max !== "undefined") { - // only bounds define min and max properties - _x1 = arg0.min.x; - _x2 = arg0.max.x; - _y1 = arg0.min.y; - _y2 = arg0.max.y; - } else { - // vector - _x1 = _x2 = arg0.x; - _y1 = _y2 = arg0.y; - } - } - - return ( - _x1 >= this.min.x && - _x2 <= this.max.x && - _y1 >= this.min.y && - _y2 <= this.max.y - ); - } - - /** - * Returns true if the two bounds intersect. - * @param {Bounds|Rect} bounds - * @returns {boolean} True if the bounds overlap, otherwise false - */ - overlaps(bounds) { - return !( - this.right < bounds.left || - this.left > bounds.right || - this.bottom < bounds.top || - this.top > bounds.bottom - ); - } - - /** - * determines whether all coordinates of this bounds are finite numbers. - * @returns {boolean} false if all coordinates are positive or negative Infinity or NaN; otherwise, true. - */ - isFinite() { - return ( - isFinite(this.min.x) && - isFinite(this.max.x) && - isFinite(this.min.y) && - isFinite(this.max.y) - ); - } - - /** - * Translates the bounds by the given point - * @param {number|Vector2d} x - x coordinate or a vector point to translate by - * @param {number} [y] - * @example - * bounds.translate(10, 10); - * // or - * bounds.translate(myVector2d); - */ - translate() { - let _x; - let _y; - if (arguments.length === 2) { - // x, y - _x = arguments[0]; - _y = arguments[1]; - } else { - // vector - _x = arguments[0].x; - _y = arguments[0].y; - } - this.min.x += _x; - this.max.x += _x; - this.min.y += _y; - this.max.y += _y; - } - - /** - * Shifts the bounds to the given x, y position. - * @param {number|Vector2d} x - x coordinate or a vector point to shift to - * @param {number} [y] - * @example - * bounds.shift(10, 10); - * // or - * bounds.shift(myVector2d); - */ - shift() { - let _x; - let _y; - - if (arguments.length === 2) { - // x, y - _x = arguments[0]; - _y = arguments[1]; - } else { - // vector - _x = arguments[0].x; - _y = arguments[0].y; - } - - const deltaX = this.max.x - this.min.x; - const deltaY = this.max.y - this.min.y; - - this.min.x = _x; - this.max.x = _x + deltaX; - this.min.y = _y; - this.max.y = _y + deltaY; - } - - /** - * clone this bounds - * @returns {Bounds} - */ - clone() { - const bounds = new Bounds(); - bounds.addBounds(this); - return bounds; - } - - /** - * Returns a polygon whose edges are the same as this bounds. - * @returns {Polygon} a new Polygon that represents this bounds. - */ - toPolygon() { - return pool.pull("Polygon", this.x, this.y, [ - pool.pull("Vector2d", 0, 0), - pool.pull("Vector2d", this.width, 0), - pool.pull("Vector2d", this.width, this.height), - pool.pull("Vector2d", 0, this.height), - ]); - } -} diff --git a/packages/melonjs/src/physics/bounds.ts b/packages/melonjs/src/physics/bounds.ts new file mode 100644 index 000000000..813526ad9 --- /dev/null +++ b/packages/melonjs/src/physics/bounds.ts @@ -0,0 +1,435 @@ +import pool from "../system/pooling.js"; +import { Vector2d, vector2dPool } from "../math/vector2d.ts"; +import { Point, pointPool } from "../geometries/point.ts"; +import { createPool } from "../system/pool.ts"; +import { Matrix2d } from "../math/matrix2d.ts"; + +/** + * a bound object contains methods for creating and manipulating axis-aligned bounding boxes (AABB). + */ +export class Bounds { + _center: Vector2d; + type: "Bounds"; + min: { x: number; y: number }; + max: { x: number; y: number }; + + /** + * Constructs a Bounds object with optional vertices. + * @param [vertices] - An array of Vector2d or Point to initialize the bounds. + */ + constructor(vertices?: Vector2d[] | Point[] | undefined) { + this._center = new Vector2d(); + this.type = "Bounds"; + this.min = { x: Infinity, y: Infinity }; + this.max = { x: -Infinity, y: -Infinity }; + if (vertices) { + this.update(vertices); + } + } + + /** + * Resets the bounds to its initial state. + */ + clear() { + this.setMinMax(Infinity, Infinity, -Infinity, -Infinity); + } + + /** + * Sets the bounds to the given minimum and maximum values. + * @param minX - The minimum x value. + * @param minY - The minimum y value. + * @param maxX - The maximum x value. + * @param maxY - The maximum y value. + */ + setMinMax(minX: number, minY: number, maxX: number, maxY: number) { + this.min.x = minX; + this.min.y = minY; + + this.max.x = maxX; + this.max.y = maxY; + } + + /** + * Gets the x position of the bounds. + * @returns The x position. + */ + get x() { + return this.min.x; + } + + /** + * Sets the x position of the bounds. + * @param value - The new x position. + */ + set x(value) { + const deltaX = this.max.x - this.min.x; + this.min.x = value; + this.max.x = value + deltaX; + } + + /** + * Gets the y position of the bounds. + * @returns The y position. + */ + get y() { + return this.min.y; + } + + /** + * Sets the y position of the bounds. + * @param value - The new y position. + */ + set y(value) { + const deltaY = this.max.y - this.min.y; + + this.min.y = value; + this.max.y = value + deltaY; + } + + /** + * Gets the width of the bounds. + * @returns The width. + */ + get width() { + return this.max.x - this.min.x; + } + + /** + * Sets the width of the bounds. + * @param value - The new width. + */ + set width(value) { + this.max.x = this.min.x + value; + } + + /** + * Gets the height of the bounds. + * @returns The height. + */ + get height() { + return this.max.y - this.min.y; + } + + /** + * Sets the height of the bounds. + * @param value - The new height. + */ + set height(value) { + this.max.y = this.min.y + value; + } + + /** + * Gets the left coordinate of the bounds. + * @returns The left coordinate. + */ + get left() { + return this.min.x; + } + + /** + * Gets the right coordinate of the bounds. + * @returns The right coordinate. + */ + get right() { + return this.max.x; + } + + /** + * Gets the top coordinate of the bounds. + * @returns The top coordinate. + */ + get top() { + return this.min.y; + } + + /** + * Gets the bottom coordinate of the bounds. + * @returns The bottom coordinate. + */ + get bottom() { + return this.max.y; + } + + /** + * Gets the center position of the bounds on the x axis. + * @returns The center x coordinate. + */ + get centerX() { + return this.min.x + this.width / 2; + } + + /** + * Gets the center position of the bounds on the y axis. + * @returns The center y coordinate. + */ + get centerY() { + return this.min.y + this.height / 2; + } + + /** + * Gets the center position of the bounds. + * @returns The center position as a Vector2d. + */ + get center() { + return this._center.set(this.centerX, this.centerY); + } + + /** + * Centers the bounds position around the given coordinates. + * @param x - The x coordinate to center around. + * @param y - The y coordinate to center around. + * @returns The current Bounds instance for method chaining. + */ + centerOn(x: number, y: number) { + this.shift(x - this.width / 2, y - this.height / 2); + return this; + } + + /** + * Updates the bounds using the given vertices. + * @param vertices - An array of Vector2d or Point to update the bounds. + */ + update(vertices: Vector2d[] | Point[]) { + this.add(vertices, true); + } + + /** + * Adds the given vertices to the bounds definition. + * @param vertices - An array of Vector2d or Point to add to the bounds. + * @param [clear] - Whether to reset the bounds before adding the new vertices. + */ + add(vertices: Vector2d[] | Point[], clear = false) { + const verticeCount = vertices.length; + if (clear) { + this.clear(); + } + for (let i = 0; i < verticeCount; i++) { + const vertex = vertices[i]; + if (vertex.x > this.max.x) { + this.max.x = vertex.x; + } + if (vertex.x < this.min.x) { + this.min.x = vertex.x; + } + if (vertex.y > this.max.y) { + this.max.y = vertex.y; + } + if (vertex.y < this.min.y) { + this.min.y = vertex.y; + } + } + } + + /** + * Adds the given bounds to the bounds definition. + * @param bounds - The bounds to add. + * @param [clear] - Whether to reset the bounds before adding the new bounds. + */ + addBounds(bounds: Bounds, clear = false) { + if (clear) { + this.max.x = bounds.max.x; + this.min.x = bounds.min.x; + this.max.y = bounds.max.y; + this.min.y = bounds.min.y; + } else { + if (bounds.max.x > this.max.x) { + this.max.x = bounds.max.x; + } + if (bounds.min.x < this.min.x) { + this.min.x = bounds.min.x; + } + if (bounds.max.y > this.max.y) { + this.max.y = bounds.max.y; + } + if (bounds.min.y < this.min.y) { + this.min.y = bounds.min.y; + } + } + } + + /** + * Adds the given point to the bounds definition. + * @param point - The point to add to the bounds. + * @param [m] - An optional transform to apply to the given point. + */ + addPoint(point: Vector2d | Point, m?: Matrix2d | undefined) { + const p = m ? m.apply(point) : point; + this.min.x = Math.min(this.min.x, p.x); + this.max.x = Math.max(this.max.x, p.x); + this.min.y = Math.min(this.min.y, p.y); + this.max.y = Math.max(this.max.y, p.y); + } + + /** + * Adds the given quad coordinates to this bounds definition, multiplied by the given matrix. + * @param x0 - The left x coordinate of the quad. + * @param y0 - The top y coordinate of the quad. + * @param x1 - The right x coordinate of the quad. + * @param y1 - The bottom y coordinate of the quad. + * @param [m] - An optional transform to apply to the given coordinates. + */ + addFrame(x0: number, y0: number, x1: number, y1: number, m: Matrix2d) { + const v = pointPool.get(); + + this.addPoint(v.set(x0, y0), m); + this.addPoint(v.set(x1, y0), m); + this.addPoint(v.set(x0, y1), m); + this.addPoint(v.set(x1, y1), m); + + pointPool.release(v); + } + + /** + * Returns true if the bounds contain the given point or vector. + * @param xOrVectorOrBounds - The x coordinate, vector, or bounds to check. + * @param [y] - The y coordinate if the first parameter is a number. + * @returns True if the bounds contain the point or vector, otherwise false. + */ + contains(x: number, y: number): boolean; + contains(vector: Vector2d | Bounds): boolean; + contains(xOrVectorOrBounds: Bounds | Vector2d | number, y?: number) { + let _x1: number; + let _x2: number; + let _y1: number; + let _y2: number; + if (xOrVectorOrBounds instanceof Vector2d) { + _x1 = _x2 = xOrVectorOrBounds.x; + _y1 = _y2 = xOrVectorOrBounds.y; + } else if (xOrVectorOrBounds instanceof Bounds) { + _x1 = xOrVectorOrBounds.min.x; + _x2 = xOrVectorOrBounds.max.x; + _y1 = xOrVectorOrBounds.min.y; + _y2 = xOrVectorOrBounds.max.y; + } else { + _x1 = _x2 = xOrVectorOrBounds; + _y1 = _y2 = y!; + } + + return ( + _x1 >= this.min.x && + _x2 <= this.max.x && + _y1 >= this.min.y && + _y2 <= this.max.y + ); + } + + /** + * Returns true if the two bounds intersect. + * @param bounds - The bounds to check for intersection. + * @returns True if the bounds overlap, otherwise false. + */ + overlaps(bounds: Bounds) { + return !( + this.right < bounds.left || + this.left > bounds.right || + this.bottom < bounds.top || + this.top > bounds.bottom + ); + } + + /** + * Determines whether all coordinates of this bounds are finite numbers. + * @returns False if any coordinates are positive or negative Infinity or NaN; otherwise, true. + */ + isFinite() { + return ( + isFinite(this.min.x) && + isFinite(this.max.x) && + isFinite(this.min.y) && + isFinite(this.max.y) + ); + } + + /** + * Translates the bounds by the given point or vector. + * @param xOrVector - The x coordinate or vector to translate by. + * @param [y] - The y coordinate if the first parameter is a number. + */ + translate(x: number, y: number): void; + translate(vector: Vector2d): void; + translate(xOrVector: Vector2d | number, y?: number) { + let _x: number; + let _y: number; + if (xOrVector instanceof Vector2d) { + _x = xOrVector.x; + _y = xOrVector.y; + } else { + _x = xOrVector; + _y = y!; + } + this.min.x += _x; + this.max.x += _x; + this.min.y += _y; + this.max.y += _y; + } + + /** + * Shifts the bounds to the given x, y position or vector. + * @param xOrVector - The x coordinate or vector to shift to. + * @param [y] - The y coordinate if the first parameter is a number. + */ + shift(x: number, y: number): void; + shift(vector: Vector2d): void; + shift(xOrVector: number | Vector2d, y?: number) { + let _x: number; + let _y: number; + + if (xOrVector instanceof Vector2d) { + _x = xOrVector.x; + _y = xOrVector.y; + } else { + _x = xOrVector; + _y = y!; + } + + const deltaX = this.max.x - this.min.x; + const deltaY = this.max.y - this.min.y; + + this.min.x = _x; + this.max.x = _x + deltaX; + this.min.y = _y; + this.max.y = _y + deltaY; + } + + /** + * Creates a clone of this bounds. + * @returns A new Bounds object that is a copy of this bounds. + */ + clone() { + const bounds = new Bounds(); + bounds.addBounds(this); + return bounds; + } + + /** + * Returns a polygon whose edges are the same as this bounds. + * @returns A new Polygon that represents this bounds. + */ + toPolygon() { + return pool.pull("Polygon", this.x, this.y, [ + vector2dPool.get(0, 0), + vector2dPool.get(this.width, 0), + vector2dPool.get(this.width, this.height), + vector2dPool.get(0, this.height), + ]); + } +} + +/** + * A pool for creating and reusing Bounds objects. + */ +export const boundsPool = createPool< + Bounds, + [vertices?: Vector2d[] | Point[] | undefined] +>((vertices) => { + const instance = new Bounds(vertices); + return { + instance, + reset(vertices) { + instance.clear(); + if (vertices) { + instance.update(vertices); + } + }, + }; +}); diff --git a/packages/melonjs/src/physics/detector.js b/packages/melonjs/src/physics/detector.js index d93616e0d..8ae607475 100644 --- a/packages/melonjs/src/physics/detector.js +++ b/packages/melonjs/src/physics/detector.js @@ -1,7 +1,7 @@ import * as SAT from "./sat.js"; import ResponseObject from "./response.js"; -import Vector2d from "./../math/vector2.js"; -import Bounds from "./bounds.js"; +import { Vector2d } from "../math/vector2d.ts"; +import { Bounds } from "./bounds.ts"; /** * @import Entity from "./../renderable/entity/entity.js"; diff --git a/packages/melonjs/src/physics/quadtree.js b/packages/melonjs/src/physics/quadtree.js index c9d198a3d..840a15c9c 100644 --- a/packages/melonjs/src/physics/quadtree.js +++ b/packages/melonjs/src/physics/quadtree.js @@ -1,10 +1,10 @@ import { remove } from "../utils/array.ts"; -import Vector2d from "./../math/vector2.js"; +import { Vector2d } from "../math/vector2d.ts"; /** * @import World from "./world.js"; * @import Container from "./../renderable/container.js"; - * @import Bounds from "./bounds.js"; + * @import {Bounds} from "./bounds.ts"; */ /* diff --git a/packages/melonjs/src/physics/response.js b/packages/melonjs/src/physics/response.js index 64a81f812..d234289a2 100644 --- a/packages/melonjs/src/physics/response.js +++ b/packages/melonjs/src/physics/response.js @@ -1,4 +1,4 @@ -import Vector2d from "./../math/vector2.js"; +import { Vector2d } from "../math/vector2d.ts"; /** * An object representing the result of an intersection. diff --git a/packages/melonjs/src/physics/sat.js b/packages/melonjs/src/physics/sat.js index 223551e1b..21b8e9c15 100644 --- a/packages/melonjs/src/physics/sat.js +++ b/packages/melonjs/src/physics/sat.js @@ -1,4 +1,4 @@ -import Vector2d from "./../math/vector2.js"; +import { Vector2d } from "../math/vector2d.ts"; /* * Separating Axis Theorem implementation, based on the SAT.js library by Jim Riecken diff --git a/packages/melonjs/src/physics/world.js b/packages/melonjs/src/physics/world.js index b8f6e7eea..baae76698 100644 --- a/packages/melonjs/src/physics/world.js +++ b/packages/melonjs/src/physics/world.js @@ -1,4 +1,4 @@ -import Vector2d from "./../math/vector2.js"; +import { Vector2d } from "../math/vector2d.ts"; import QuadTree from "./quadtree.js"; import Container from "../renderable/container.js"; import { collision } from "./collision.js"; diff --git a/packages/melonjs/src/pool.ts b/packages/melonjs/src/pool.ts new file mode 100644 index 000000000..8e22b7712 --- /dev/null +++ b/packages/melonjs/src/pool.ts @@ -0,0 +1,21 @@ +import { pointPool } from "./geometries/point"; +import { matrix2dPool } from "./math/matrix2d"; +import { matrix3dPool } from "./math/matrix3d"; +import { vector2dPool } from "./math/vector2d"; +import { vector3dPool } from "./math/vector3d"; +import { boundsPool } from "./physics/bounds"; + +const pools = { + vector2d: vector2dPool, + vector3d: vector3dPool, + point: pointPool, + matrix2d: matrix2dPool, + matrix3d: matrix3dPool, + bounds: boundsPool, +} as const; + +type PoolKey = keyof typeof pools; + +export const getPool = (key: K): (typeof pools)[K] => { + return pools[key]; +}; diff --git a/packages/melonjs/src/renderable/collectable.js b/packages/melonjs/src/renderable/collectable.js index 1ac41777a..9bd5c51d8 100644 --- a/packages/melonjs/src/renderable/collectable.js +++ b/packages/melonjs/src/renderable/collectable.js @@ -2,6 +2,7 @@ import Sprite from "./sprite.js"; import Body from "./../physics/body.js"; import { collision } from "./../physics/collision.js"; import pool from "./../system/pooling.js"; +import { vector2dPool } from "../math/vector2d.ts"; /** * a basic collectable helper class for immovable object (e.g. a coin) @@ -24,9 +25,9 @@ export default class Collectable extends Sprite { let shape = settings.shapes; if (typeof shape === "undefined") { shape = pool.pull("Polygon", 0, 0, [ - pool.pull("Vector2d", 0, 0), - pool.pull("Vector2d", this.width, 0), - pool.pull("Vector2d", this.width, this.height), + vector2dPool.get(0, 0), + vector2dPool.get(this.width, 0), + vector2dPool.get(this.width, this.height), ]); } this.body = new Body(this, shape); diff --git a/packages/melonjs/src/renderable/container.js b/packages/melonjs/src/renderable/container.js index 8410e5dc6..9a8a71d0d 100644 --- a/packages/melonjs/src/renderable/container.js +++ b/packages/melonjs/src/renderable/container.js @@ -35,7 +35,7 @@ let globalFloatingCounter = 0; * @import UITextButton from "./ui/uitextbutton.js"; * @import Text from "./text/text.js"; * @import BitmapText from "./text/bitmaptext.js"; - * @import Bounds from "./../physics/bounds.js"; + * @import {Bounds} from "./../physics/bounds.ts"; * @import CanvasRenderer from "./../video/canvas/canvas_renderer.js"; * @import WebGLRenderer from "./../video/webgl/webgl_renderer.js"; */ @@ -639,17 +639,17 @@ export default class Container extends Renderable { * update the cointainer's bounding rect (private) * @ignore */ - updateBoundsPos(newX = this.pos.x, newY = this.pos.y) { + updateBoundsPos(options) { // call the parent method - super.updateBoundsPos(newX, newY); + super.updateBoundsPos(options); // Notify children that the parent's position has changed this.forEach((child) => { if (child.isRenderable) { - child.updateBoundsPos( - child.pos.x + newX - this.pos.x, - child.pos.y + newY - this.pos.y, - ); + child.updateBoundsPos({ + newX: child.pos.x + options.newX - this.pos.x, + newY: child.pos.y + options.newY - this.pos.y, + }); } }); } diff --git a/packages/melonjs/src/renderable/draggable.js b/packages/melonjs/src/renderable/draggable.js index dc36df253..63312a155 100644 --- a/packages/melonjs/src/renderable/draggable.js +++ b/packages/melonjs/src/renderable/draggable.js @@ -1,4 +1,4 @@ -import Vector2d from "./../math/vector2.js"; +import { Vector2d } from "../math/vector2d.ts"; import * as input from "./../input/input.js"; import Renderable from "./../renderable/renderable.js"; import { diff --git a/packages/melonjs/src/renderable/entity/entity.js b/packages/melonjs/src/renderable/entity/entity.js index cab875396..2ce811f74 100644 --- a/packages/melonjs/src/renderable/entity/entity.js +++ b/packages/melonjs/src/renderable/entity/entity.js @@ -2,13 +2,14 @@ import pool from "../../system/pooling.js"; import Renderable from "../renderable.js"; import Sprite from "../sprite.js"; import Body from "../../physics/body.js"; +import { vector2dPool } from "../../math/vector2d.ts"; /** * @import Line from "./../../geometries/line.js"; * @import Rect from "./../../geometries/rectangle.js"; * @import Ellipse from "./../../geometries/ellipse.js"; * @import Polygon from "./../../geometries/poly.js"; - * @import Bounds from "./../../physics/bounds.js"; + * @import {Bounds} from "./../../physics/bounds.ts"; * @import CanvasRenderer from "./../../video/canvas/canvas_renderer.js"; * @import WebGLRenderer from "./../../video/webgl/webgl_renderer.js"; **/ @@ -86,10 +87,10 @@ export default class Entity extends Renderable { // initialize the default body if (typeof settings.shapes === "undefined") { settings.shapes = pool.pull("Polygon", 0, 0, [ - pool.pull("Vector2d", 0, 0), - pool.pull("Vector2d", this.width, 0), - pool.pull("Vector2d", this.width, this.height), - pool.pull("Vector2d", 0, this.height), + vector2dPool.get(0, 0), + vector2dPool.get(this.width, 0), + vector2dPool.get(this.width, this.height), + vector2dPool.get(0, this.height), ]); } diff --git a/packages/melonjs/src/renderable/imagelayer.js b/packages/melonjs/src/renderable/imagelayer.js index 28311d3eb..57cc36993 100644 --- a/packages/melonjs/src/renderable/imagelayer.js +++ b/packages/melonjs/src/renderable/imagelayer.js @@ -1,5 +1,4 @@ import { renderer } from "./../video/video.js"; -import pool from "./../system/pooling.js"; import { game } from "../index.js"; import Sprite from "./sprite.js"; import * as stringUtil from "./../utils/string.ts"; @@ -10,10 +9,11 @@ import { VIEWPORT_ONCHANGE, VIEWPORT_ONRESIZE, } from "../system/event.ts"; +import { vector2dPool } from "../math/vector2d.ts"; /** * additional import for TypeScript - * @import Vector2d from "./../math/vector2.js"; + * @import {Vector2d} from "../math/vector2d.js"; */ /** @@ -57,7 +57,7 @@ export default class ImageLayer extends Sprite { * @type {Vector2d} * @default <1.0,1.0> */ - this.ratio = pool.pull("Vector2d", 1.0, 1.0); + this.ratio = vector2dPool.get(1.0, 1.0); if (typeof settings.ratio !== "undefined") { // little hack for backward compatiblity @@ -281,7 +281,7 @@ export default class ImageLayer extends Sprite { * @ignore */ destroy() { - pool.push(this.ratio); + vector2dPool.release(this.ratio); this.ratio = undefined; eventEmitter.removeListener(ONCONTEXT_RESTORED, this.boundCreatePattern); super.destroy(); diff --git a/packages/melonjs/src/renderable/renderable.js b/packages/melonjs/src/renderable/renderable.js index f4bcca766..496d09c8b 100644 --- a/packages/melonjs/src/renderable/renderable.js +++ b/packages/melonjs/src/renderable/renderable.js @@ -1,19 +1,21 @@ -import ObservableVector2d from "./../math/observable_vector2.js"; -import ObservableVector3d from "./../math/observable_vector3.js"; import Rect from "./../geometries/rectangle.js"; import pool from "./../system/pooling.js"; import { releaseAllPointerEvents } from "./../input/input.js"; import { clamp } from "./../math/math.ts"; import Body from "./../physics/body.js"; -import Bounds from "./../physics/bounds.js"; +import { Bounds, boundsPool } from "./../physics/bounds.ts"; import GLShader from "./../video/webgl/glshader.js"; import Color from "./../math/color.js"; +import { observableVector3dPool } from "../math/observableVector3d.ts"; +import { observableVector2dPool } from "../math/observableVector2d.ts"; +import { vector2dPool } from "../math/vector2d.ts"; +import { matrix2dPool } from "../math/matrix2d.ts"; /** * additional import for TypeScript - * @import Vector2d from "./../math/vector2.js"; - * @import Vector3d from "./../math/vector3.js"; - * @import Matrix2d from "./../math/matrix2.js"; + * @import {Vector3d} from "../math/vector3d.js"; + * @import {Vector2d} from "../math/vector2d.js"; + * @import {Matrix2d} from "../math/matrix2d.ts"; * @import Entity from "./entity/entity.js"; * @import Container from "./container.js"; * @import Line from "./../geometries/line.js"; @@ -40,48 +42,41 @@ export default class Renderable extends Rect { // parent constructor super(x, y, width, height); - if (this.pos instanceof ObservableVector3d) { - this.pos.setMuted(x, y, 0).setCallback(this.updateBoundsPos, this); - } else { - /** - * Position of the Renderable relative to its parent container - * @public - * @type {ObservableVector3d} - */ - this.pos = pool.pull("ObservableVector3d", x, y, 0, { - onUpdate: this.updateBoundsPos, - scope: this, - }); - } + /** + * Position of the Renderable relative to its parent container + * @public + * @type {ObservableVector3d} + */ + this.pos = observableVector3dPool.get( + x, + y, + 0, + this.updateBoundsPos.bind(this), + ); - if (this.anchorPoint instanceof ObservableVector2d) { - this.anchorPoint - .setMuted(0.5, 0.5) - .setCallback(this.onAnchorUpdate, this); - } else { - /** - * The anchor point is used for attachment behavior, and/or when applying transformations.
- * The coordinate system places the origin at the top left corner of the frame (0, 0) and (1, 1) means the bottom-right corner
- *
- * a Renderable's anchor point defaults to (0.5,0.5), which corresponds to the center position.
- *
- * Note: Object created through Tiled will have their anchorPoint set to (0, 0) to match Tiled Level editor implementation. - * To specify a value through Tiled, use a json expression like `json:{"x":0.5,"y":0.5}`. - * @type {ObservableVector2d} - * @default <0.5,0.5> - */ - this.anchorPoint = pool.pull("ObservableVector2d", 0.5, 0.5, { - onUpdate: this.onAnchorUpdate, - scope: this, - }); - } + /** + * The anchor point is used for attachment behavior, and/or when applying transformations.
+ * The coordinate system places the origin at the top left corner of the frame (0, 0) and (1, 1) means the bottom-right corner
+ *
+ * a Renderable's anchor point defaults to (0.5,0.5), which corresponds to the center position.
+ *
+ * Note: Object created through Tiled will have their anchorPoint set to (0, 0) to match Tiled Level editor implementation. + * To specify a value through Tiled, use a json expression like `json:{"x":0.5,"y":0.5}`. + * @type {ObservableVector2d} + * @default <0.5,0.5> + */ + this.anchorPoint = observableVector2dPool.get( + 0.5, + 0.5, + this.onAnchorUpdate.bind(this), + ); if (typeof this.currentTransform === "undefined") { /** * the renderable default transformation matrix * @type {Matrix2d} */ - this.currentTransform = pool.pull("Matrix2d"); + this.currentTransform = matrix2dPool.get(); } this.currentTransform.identity(); @@ -614,7 +609,6 @@ export default class Renderable extends Rect { const bounds = this.getBounds(); bounds.clear(); - if (this.autoTransform === true && !this.currentTransform.isIdentity()) { // temporarly translate the matrix based on the anchor point this.currentTransform.translate( @@ -654,7 +648,7 @@ export default class Renderable extends Rect { * update the renderable's bounding rect (private) * @ignore */ - updateBoundsPos(newX = this.pos.x, newY = this.pos.y) { + updateBoundsPos({ newX, newY }) { this.getBounds().translate(newX - this.pos.x, newY - this.pos.y); } @@ -664,7 +658,7 @@ export default class Renderable extends Rect { */ getAbsolutePosition() { if (typeof this._absPos === "undefined") { - this._absPos = pool.pull("Vector2d"); + this._absPos = vector2dPool.get(); } // XXX Cache me or something this._absPos.set(this.pos.x, this.pos.y); @@ -684,7 +678,7 @@ export default class Renderable extends Rect { * @param {number} x - the new X value to be set for the anchor * @param {number} y - the new Y value to be set for the anchor */ - onAnchorUpdate(x, y) { + onAnchorUpdate({ newX: x, newY: y }) { // since the callback is called before setting the new value // manually update the anchor point (required for updateBoundsPos) this.anchorPoint.setMuted(x, y); @@ -826,22 +820,22 @@ export default class Renderable extends Rect { */ destroy() { // allow recycling object properties - pool.push(this.currentTransform); + matrix2dPool.release(this.currentTransform); this.currentTransform = undefined; - pool.push(this.anchorPoint); + observableVector2dPool.release(this.anchorPoint); this.anchorPoint = undefined; - pool.push(this.pos); + observableVector3dPool.release(this.pos); this.pos = undefined; if (typeof this._absPos !== "undefined") { - pool.push(this._absPos); + vector2dPool.release(this._absPos); this._absPos = undefined; } if (this._bounds instanceof Bounds) { - pool.push(this._bounds); + boundsPool.release(this._bounds); this._bounds = undefined; } diff --git a/packages/melonjs/src/renderable/sprite.js b/packages/melonjs/src/renderable/sprite.js index 3562ab291..eaafc4f1f 100644 --- a/packages/melonjs/src/renderable/sprite.js +++ b/packages/melonjs/src/renderable/sprite.js @@ -1,14 +1,14 @@ import { renderer } from "./../video/video.js"; -import pool from "./../system/pooling.js"; import { getImage } from "./../loader/loader.js"; import { TextureAtlas } from "./../video/texture/atlas.js"; import Renderable from "./renderable.js"; import Color from "../math/color.js"; import { eventEmitter } from "../system/event.ts"; +import { vector2dPool } from "../math/vector2d.ts"; /** * additional import for TypeScript - * @import Vector2d from "./../math/vector2.js"; + * @import {Vector2d} from "../math/vector2d.js"; * @import CanvasRenderer from "./../video/canvas/canvas_renderer.js"; * @import WebGLRenderer from "./../video/webgl/webgl_renderer.js"; */ @@ -81,7 +81,7 @@ export default class Sprite extends Renderable { * @type {Vector2d} * @default <0.0,0.0> */ - this.offset = pool.pull("Vector2d", 0, 0); + this.offset = vector2dPool.get(0, 0); /** * true if this is a video sprite (e.g. a HTMLVideoElement was passed as as source) @@ -117,7 +117,7 @@ export default class Sprite extends Renderable { // length of the current animation name length: 0, //current frame texture offset - offset: pool.pull("Vector2d", 0, 0), + offset: vector2dPool.get(0, 0), // current frame size width: 0, height: 0, @@ -723,7 +723,7 @@ export default class Sprite extends Renderable { * @ignore */ destroy() { - pool.push(this.offset); + vector2dPool.release(this.offset); this.offset = undefined; if (this.isVideo) { this.removeStatePauseListener(); diff --git a/packages/melonjs/src/renderable/text/bitmaptext.js b/packages/melonjs/src/renderable/text/bitmaptext.js index 12ca91c12..f1360efb4 100644 --- a/packages/melonjs/src/renderable/text/bitmaptext.js +++ b/packages/melonjs/src/renderable/text/bitmaptext.js @@ -3,6 +3,7 @@ import pool from "../../system/pooling.js"; import { getImage, getBinary } from "../../loader/loader.js"; import Renderable from "../renderable.js"; import TextMetrics from "./textmetrics.js"; +import { vector2dPool } from "../../math/vector2d.ts"; /** * a bitmap font object @@ -87,7 +88,7 @@ export default class BitmapText extends Renderable { * scaled font size * @private */ - this.fontScale = pool.pull("Vector2d", 1.0, 1.0); + this.fontScale = vector2dPool.get(1.0, 1.0); /** * font image @@ -422,7 +423,7 @@ export default class BitmapText extends Renderable { * @ignore */ destroy() { - pool.push(this.fontScale); + vector2dPool.release(this.fontScale); this.fontScale = undefined; pool.push(this.fontData); this.fontData = undefined; diff --git a/packages/melonjs/src/renderable/text/textmetrics.js b/packages/melonjs/src/renderable/text/textmetrics.js index ee9e56f8b..f234e08df 100644 --- a/packages/melonjs/src/renderable/text/textmetrics.js +++ b/packages/melonjs/src/renderable/text/textmetrics.js @@ -1,4 +1,4 @@ -import Bounds from "../../physics/bounds.js"; +import { Bounds } from "../../physics/bounds.ts"; import Text from "./text.js"; import setContextStyle from "./textstyle.js"; diff --git a/packages/melonjs/src/renderable/trigger.js b/packages/melonjs/src/renderable/trigger.js index 697f34e54..df92885c6 100644 --- a/packages/melonjs/src/renderable/trigger.js +++ b/packages/melonjs/src/renderable/trigger.js @@ -3,6 +3,7 @@ import { collision } from "./../physics/collision.js"; import Body from "./../physics/body.js"; import { level } from "./../level/level.js"; import pool from "./../system/pooling.js"; +import { vector2dPool } from "../math/vector2d.ts"; /** * additional import for TypeScript @@ -80,9 +81,9 @@ export default class Trigger extends Renderable { let shape = settings.shapes; if (typeof shape === "undefined") { shape = pool.pull("Polygon", 0, 0, [ - pool.pull("Vector2d", 0, 0), - pool.pull("Vector2d", this.width, 0), - pool.pull("Vector2d", this.width, this.height), + vector2dPool.get(0, 0), + vector2dPool.get(this.width, 0), + vector2dPool.get(this.width, this.height), ]); } this.body = new Body(this, shape); diff --git a/packages/melonjs/src/renderable/ui/uibaseelement.js b/packages/melonjs/src/renderable/ui/uibaseelement.js index 7c7bab297..9ed53db2f 100644 --- a/packages/melonjs/src/renderable/ui/uibaseelement.js +++ b/packages/melonjs/src/renderable/ui/uibaseelement.js @@ -4,8 +4,8 @@ import { registerPointerEvent, releasePointerEvent, } from "./../../input/input.js"; -import pool from "../../system/pooling.js"; import { eventEmitter, POINTERMOVE } from "../../system/event.ts"; +import { vector2dPool } from "../../math/vector2d.ts"; /** * This is a basic clickable and draggable container which you can use in your game UI. @@ -133,7 +133,7 @@ export default class UIBaseElement extends Container { if (this.isDraggable === true) { eventEmitter.addListener(POINTERMOVE, this.#boundPointerMoveHandler); // to memorize where we grab the object - this.grabOffset = pool.pull("Vector2d", 0, 0); + this.grabOffset = vector2dPool.get(0, 0); } return this.onOver(event); } @@ -179,7 +179,7 @@ export default class UIBaseElement extends Container { if (this.isDraggable === true) { // unregister on the global pointermove event eventEmitter.removeListener(POINTERMOVE, this.#boundPointerMoveHandler); - pool.push(this.grabOffset); + vector2dPool.release(this.grabOffset); this.grabOffset = undefined; } this.release(event); @@ -282,7 +282,7 @@ export default class UIBaseElement extends Container { if (this.isDraggable === true) { eventEmitter.removeListener(POINTERMOVE, this.#boundPointerMoveHandler); if (typeof this.grabOffset !== "undefined") { - pool.push(this.grabOffset); + vector2dPool.release(this.grabOffset); this.grabOffset = undefined; } } diff --git a/packages/melonjs/src/system/event.ts b/packages/melonjs/src/system/event.ts index 22a9318f4..14e5e43a0 100644 --- a/packages/melonjs/src/system/event.ts +++ b/packages/melonjs/src/system/event.ts @@ -3,7 +3,7 @@ */ import Pointer from "../input/pointer.js"; -import Vector2d from "../math/vector2.js"; +import { Vector2d } from "../math/vector2d.ts"; import { Draggable } from "../renderable/draggable.js"; import Stage from "../state/stage.js"; import Renderer from "../video/renderer.js"; diff --git a/packages/melonjs/src/system/pool.test.ts b/packages/melonjs/src/system/pool.test.ts index 86bf95cf2..fbb20202a 100644 --- a/packages/melonjs/src/system/pool.test.ts +++ b/packages/melonjs/src/system/pool.test.ts @@ -1,23 +1,26 @@ -import { expect, test } from "vitest"; -import { createPool, Poolable } from "./pool"; +import { expect, test, vi } from "vitest"; +import { createPool } from "./pool"; -class MyObject implements Poolable { - onReset() {} -} +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +class GameObject {} test("can acquire objects from the pool", () => { - const pool = createPool({ type: MyObject }); + const pool = createPool(() => { + return { instance: new GameObject() }; + }); const object1 = pool.get(); const object2 = pool.get(); - expect(object1).toBeInstanceOf(MyObject); - expect(object2).toBeInstanceOf(MyObject); + expect(object1).toBeInstanceOf(GameObject); + expect(object2).toBeInstanceOf(GameObject); expect(object1).not.toBe(object2); expect(pool.size()).toBe(2); }); test("can release objects from the pool", () => { - const pool = createPool({ type: MyObject }); + const pool = createPool(() => { + return { instance: new GameObject() }; + }); const object1 = pool.get(); pool.release(object1); pool.get(); @@ -25,7 +28,9 @@ test("can release objects from the pool", () => { }); test("can manually purge", () => { - const pool = createPool({ type: MyObject }); + const pool = createPool(() => { + return { instance: new GameObject() }; + }); const object1 = pool.get(); const object2 = pool.get(); const object3 = pool.get(); @@ -40,3 +45,31 @@ test("can manually purge", () => { pool.purge(); expect(pool.size()).toBe(0); }); + +test("can pass arguments", () => { + class Foo { + prop: string; + constructor(arg: string) { + this.prop = arg; + } + } + + const reset = vi.fn(); + + const pool = createPool((a) => { + return { + instance: new Foo(a), + reset(a) { + reset(a); + }, + }; + }); + + expect(reset).not.toHaveBeenCalled(); + const object1 = pool.get(""); + expect(reset).not.toHaveBeenCalled(); + pool.release(object1); + expect(reset).not.toHaveBeenCalled(); + pool.get(""); + expect(reset).toHaveBeenCalledWith(""); +}); diff --git a/packages/melonjs/src/system/pool.ts b/packages/melonjs/src/system/pool.ts index 88a29fa3f..c88ae5040 100644 --- a/packages/melonjs/src/system/pool.ts +++ b/packages/melonjs/src/system/pool.ts @@ -1,101 +1,53 @@ -/** - * Interface representing a poolable object with a reset method. - * @template {any[]} T - The arguments for the onReset method. - */ -export interface Poolable { - /** - * Method to reset the object. - * @param args - Arguments for resetting the object. - */ - onReset(...args: T): void; -} - -/** - * Interface representing a pool. - * @template {Poolable} T - The type of poolable objects. - */ -export interface Pool { - /** - * Get an object from the pool, or create a new one if none are available. - * @param args - Arguments to reset the object. - * @returns The poolable object. - */ - get(...args: Parameters): T; - - /** - * Release an object back to the pool. - * @param object - The poolable object to release. - */ +export interface Pool { + get(...args: A): T; release(object: T): void; - - /** - * Purge all available objects from the pool. - */ purge(): void; - - /** - * Get the size of the pool. - * @returns The number of objects in the pool, both available and in use. - */ size(): number; } -/** - * Options for creating a pool. - * @template {Poolable} T - The type of poolable objects. - */ -export interface CreatePoolOptions { - /** - * The constructor for creating new instances of the poolable object. - */ - type: new () => T; +type Reset = ((...args: A) => void) | undefined; + +export interface CreatePoolOptions { + instance: T; + reset?: Reset; } -/** - * Creates a pool for managing poolable objects. - * @template {Poolable} T - The type of poolable objects. - * @param options - Options for creating the pool. - * @returns The pool object - */ -export const createPool = ( - options: CreatePoolOptions, -): Pool => { +export const createPool = ( + options: (...args: A) => CreatePoolOptions, +): Pool => { const available: T[] = []; const inUse: T[] = []; - - const get = (...args: Parameters) => { - const object = available.pop(); - if (object) { - object.onReset(...args); - inUse.push(object); - return object; - } - const instance = new options.type(); - inUse.push(instance); - instance.onReset(...args); - return instance; - }; - - const release = (object: T) => { - const index = inUse.indexOf(object); - if (index >= 0) { - const [instance] = inUse.splice(index, 1); - available.push(instance); - } - }; - - const purge = () => { - available.length = 0; - }; - - const size = () => { - return available.length + inUse.length; - }; + const instanceResetMethods = new Map>(); return { - release, - get, - purge, - size, + release: (object: T) => { + const index = inUse.indexOf(object); + if (index >= 0) { + const [instance] = inUse.splice(index, 1); + available.push(instance); + } else { + throw new Error("Trying to release an instance that is not in use."); + } + }, + get: (...args) => { + const object = available.pop(); + if (object) { + inUse.push(object); + const reset = instanceResetMethods.get(object); + reset?.(...args); + return object; + } else { + const { instance, reset } = options(...args); + instanceResetMethods.set(instance, reset); + inUse.push(instance); + return instance; + } + }, + purge: () => { + available.length = 0; + }, + size: () => { + return available.length + inUse.length; + }, }; }; diff --git a/packages/melonjs/src/utils/utils.ts b/packages/melonjs/src/utils/utils.ts index 65ee731ce..2d9b23580 100644 --- a/packages/melonjs/src/utils/utils.ts +++ b/packages/melonjs/src/utils/utils.ts @@ -94,7 +94,6 @@ export function getUriFragment(url: string) { }) .forEach((value) => { const kv = value.split("="); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const k = kv.shift()!; const v = kv.join("="); hash[k] = v || true; diff --git a/packages/melonjs/src/video/canvas/canvas_renderer.js b/packages/melonjs/src/video/canvas/canvas_renderer.js index c74d76034..a19b0fc73 100644 --- a/packages/melonjs/src/video/canvas/canvas_renderer.js +++ b/packages/melonjs/src/video/canvas/canvas_renderer.js @@ -15,7 +15,7 @@ import TextureCache from "./../texture/cache.js"; * @import Polygon from "./../../geometries/poly.js"; * @import Line from "./../../geometries/line.js"; * @import Ellipse from "./../../geometries/ellipse.js"; - * @import Matrix2d from "./../../math/matrix2.js"; + * @import {Matrix2d} from "../../math/matrix2d.ts"; */ /** diff --git a/packages/melonjs/src/video/renderer.js b/packages/melonjs/src/video/renderer.js index 571e371be..eb62e59a3 100644 --- a/packages/melonjs/src/video/renderer.js +++ b/packages/melonjs/src/video/renderer.js @@ -1,7 +1,7 @@ import Color from "./../math/color.js"; -import Matrix3d from "./../math/matrix3.js"; +import { Matrix3d } from "../math/matrix3d.ts"; import Path2D from "./../geometries/path2d.js"; -import Vector2d from "../math/vector2.js"; +import { Vector2d } from "../math/vector2d.ts"; import CanvasRenderTarget from "./rendertarget/canvasrendertarget.js"; import { CANVAS_ONRESIZE, eventEmitter } from "../system/event.ts"; @@ -11,7 +11,7 @@ import { CANVAS_ONRESIZE, eventEmitter } from "../system/event.ts"; * @import Polygon from "./../geometries/poly.js"; * @import Line from "./../geometries/line.js"; * @import Ellipse from "./../geometries/ellipse.js"; - * @import Bounds from "./../physics/bounds.js"; + * @import {Bounds} from "./../physics/bounds.ts"; */ /** diff --git a/packages/melonjs/src/video/texture/atlas.js b/packages/melonjs/src/video/texture/atlas.js index f3ea77bec..2d11a8456 100644 --- a/packages/melonjs/src/video/texture/atlas.js +++ b/packages/melonjs/src/video/texture/atlas.js @@ -1,4 +1,4 @@ -import Vector2d from "./../../math/vector2.js"; +import { Vector2d } from "../../math/vector2d.ts"; import Sprite from "./../../renderable/sprite.js"; import { renderer } from "./../video.js"; import pool from "./../../system/pooling.js"; diff --git a/packages/melonjs/src/video/texture/parser/aseprite.js b/packages/melonjs/src/video/texture/parser/aseprite.js index 42afc5e3c..6297061b6 100644 --- a/packages/melonjs/src/video/texture/parser/aseprite.js +++ b/packages/melonjs/src/video/texture/parser/aseprite.js @@ -1,5 +1,5 @@ import { ETA } from "../../../math/math.ts"; -import Vector2d from "../../../math/vector2.js"; +import { Vector2d } from "../../../math/vector2d.ts"; /** * parse the given data and return a corresponding atlas diff --git a/packages/melonjs/src/video/texture/parser/spritesheet.js b/packages/melonjs/src/video/texture/parser/spritesheet.js index 7f2530d29..cde9e87fb 100644 --- a/packages/melonjs/src/video/texture/parser/spritesheet.js +++ b/packages/melonjs/src/video/texture/parser/spritesheet.js @@ -1,5 +1,4 @@ -import pool from "./../../../system/pooling.js"; -import Vector2d from "./../../../math/vector2.js"; +import { Vector2d, vector2dPool } from "../../../math/vector2d.ts"; /** * parse the given data and return a corresponding atlas @@ -18,8 +17,7 @@ export function parseSpriteSheet(data, textureAtlas) { let height = image.height; // calculate the sprite count (line, col) - const spritecount = pool.pull( - "Vector2d", + const spritecount = vector2dPool.get( ~~((width - margin + spacing) / (data.framewidth + spacing)), ~~((height - margin + spacing) / (data.frameheight + spacing)), ); @@ -78,7 +76,7 @@ export function parseSpriteSheet(data, textureAtlas) { textureAtlas.addUVs(atlas, name, width, height); } - pool.push(spritecount); + vector2dPool.release(spritecount); return atlas; } diff --git a/packages/melonjs/src/video/texture/parser/texturepacker.js b/packages/melonjs/src/video/texture/parser/texturepacker.js index 4437fa565..3c0b94bdf 100644 --- a/packages/melonjs/src/video/texture/parser/texturepacker.js +++ b/packages/melonjs/src/video/texture/parser/texturepacker.js @@ -1,5 +1,5 @@ import { ETA } from "./../../../math/math.ts"; -import Vector2d from "./../../../math/vector2.js"; +import { Vector2d } from "../../../math/vector2d.ts"; /** * parse the given data and return a corresponding atlas diff --git a/packages/melonjs/src/video/webgl/compositors/compositor.js b/packages/melonjs/src/video/webgl/compositors/compositor.js index 43d5a30b9..08f331a3b 100644 --- a/packages/melonjs/src/video/webgl/compositors/compositor.js +++ b/packages/melonjs/src/video/webgl/compositors/compositor.js @@ -4,7 +4,7 @@ import GLShader from "../glshader.js"; /** * additional import for TypeScript * @import WebGLRenderer from "./../webgl_renderer.js"; - * @import Matrix3d from "./../../../math/matrix3.js"; + * @import {Matrix3d} from "../../../math/matrix3d.ts"; */ /** diff --git a/packages/melonjs/src/video/webgl/compositors/primitive_compositor.js b/packages/melonjs/src/video/webgl/compositors/primitive_compositor.js index c325c51dd..e8762a935 100644 --- a/packages/melonjs/src/video/webgl/compositors/primitive_compositor.js +++ b/packages/melonjs/src/video/webgl/compositors/primitive_compositor.js @@ -4,7 +4,7 @@ import Compositor from "./compositor.js"; /** * additional import for TypeScript - * @import Point from "./../../../geometries/point.js"; + * @import {Point} from "./../../../geometries/point.ts"; */ /** diff --git a/packages/melonjs/src/video/webgl/compositors/quad_compositor.js b/packages/melonjs/src/video/webgl/compositors/quad_compositor.js index f75ce19d4..438c2e55d 100644 --- a/packages/melonjs/src/video/webgl/compositors/quad_compositor.js +++ b/packages/melonjs/src/video/webgl/compositors/quad_compositor.js @@ -1,4 +1,4 @@ -import Vector2d from "../../../math/vector2.js"; +import { Vector2d } from "../../../math/vector2d.ts"; import { isPowerOfTwo } from "../../../math/math.ts"; import quadVertex from "./../shaders/quad.vert"; import quadFragment from "./../shaders/quad.frag"; diff --git a/packages/melonjs/src/video/webgl/webgl_renderer.js b/packages/melonjs/src/video/webgl/webgl_renderer.js index 8a273ad1e..b2be387e4 100644 --- a/packages/melonjs/src/video/webgl/webgl_renderer.js +++ b/packages/melonjs/src/video/webgl/webgl_renderer.js @@ -1,5 +1,5 @@ import Color from "./../../math/color.js"; -import Matrix2d from "./../../math/matrix2.js"; +import { Matrix2d, matrix2dPool } from "../../math/matrix2d.ts"; import QuadCompositor from "./compositors/quad_compositor"; import PrimitiveCompositor from "./compositors/primitive_compositor"; import Renderer from "./../renderer.js"; @@ -23,7 +23,7 @@ import { * @import Polygon from "./../../geometries/poly.js"; * @import Line from "./../../geometries/line.js"; * @import Ellipse from "./../../geometries/ellipse.js"; - * @import Matrix3d from "./../../math/matrix3.js"; + * @import {Matrix3d} from "../../math/matrix3d.ts"; * @import Compositor from "./compositors/compositor.js"; */ @@ -299,7 +299,7 @@ export default class WebGLRenderer extends Renderer { pool.push(color); }); this._matrixStack.forEach((matrix) => { - pool.push(matrix); + matrix2dPool.release(matrix); }); this._colorStack.length = 0; this._matrixStack.length = 0; @@ -794,7 +794,7 @@ export default class WebGLRenderer extends Renderer { // recycle objects pool.push(color); - pool.push(matrix); + matrix2dPool.release(matrix); } if (this._scissorStack.length !== 0) { diff --git a/packages/melonjs/tests/earcut/expected.json b/packages/melonjs/tests/earcut/expected.json new file mode 100644 index 000000000..0c4a6cf47 --- /dev/null +++ b/packages/melonjs/tests/earcut/expected.json @@ -0,0 +1,63 @@ +{ + "triangles": { + "building": 13, + "dude": 106, + "water": 2482, + "water2": 1212, + "water3": 197, + "water3b": 25, + "water4": 705, + "water-huge": 5177, + "water-huge2": 4462, + "degenerate": 0, + "bad-hole": 42, + "empty-square": 0, + "issue16": 12, + "issue17": 11, + "steiner": 9, + "issue29": 40, + "issue34": 139, + "issue35": 844, + "self-touching": 124, + "outside-ring": 64, + "simplified-us-border": 120, + "touching-holes": 57, + "hole-touching-outer": 77, + "hilbert": 1024, + "issue45": 10, + "eberly-3": 73, + "eberly-6": 1429, + "issue52": 109, + "shared-points": 4, + "bad-diagonals": 7, + "issue83": 0, + "issue107": 0, + "issue111": 19, + "boxy": 57, + "collinear-diagonal": 14, + "issue119": 18, + "hourglass": 2, + "touching2": 8, + "touching3": 15, + "touching4": 20, + "rain": 2681, + "issue131": 12, + "infinite-loop-jhl": 0, + "filtered-bridge-jhl": 25, + "issue149": 2, + "issue142": 4 + }, + "errors": { + "dude": 2e-15, + "water": 0.0008, + "water-huge": 0.0011, + "water-huge2": 0.0028, + "bad-hole": 0.019, + "issue16": 4e-16, + "issue17": 2e-16, + "issue29": 2e-15, + "self-touching": 2e-13, + "eberly-6": 2e-14, + "issue142": 0.13 + } +} diff --git a/packages/melonjs/tests/earcut/fixtures/bad-diagonals.json b/packages/melonjs/tests/earcut/fixtures/bad-diagonals.json new file mode 100644 index 000000000..269934119 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/bad-diagonals.json @@ -0,0 +1,15 @@ +[ + [ + [440, 4152], + [440, 4208], + [296, 4192], + [368, 4192], + [400, 4200], + [400, 4176], + [368, 4192], + [296, 4192], + [264, 4200], + [288, 4160], + [296, 4192] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/bad-hole.json b/packages/melonjs/tests/earcut/fixtures/bad-hole.json new file mode 100644 index 000000000..76f5c4120 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/bad-hole.json @@ -0,0 +1,52 @@ +[ + [ + [810, 2828], + [818, 2828], + [832, 2818], + [844, 2806], + [855, 2808], + [866, 2816], + [867, 2824], + [876, 2827], + [883, 2834], + [875, 2834], + [867, 2840], + [878, 2838], + [889, 2844], + [880, 2847], + [870, 2847], + [860, 2864], + [852, 2879], + [847, 2867], + [810, 2828], + [810, 2828] + ], + [ + [818, 2834], + [823, 2833], + [831, 2828], + [839, 2829], + [839, 2837], + [851, 2845], + [847, 2835], + [846, 2827], + [847, 2827], + [837, 2827], + [840, 2815], + [835, 2823], + [818, 2834], + [818, 2834] + ], + [[857, 2846], [864, 2850], [866, 2839], [857, 2846], [857, 2846]], + [ + [848, 2863], + [848, 2866], + [854, 2852], + [846, 2854], + [847, 2862], + [838, 2851], + [838, 2859], + [848, 2863], + [848, 2863] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/boxy.json b/packages/melonjs/tests/earcut/fixtures/boxy.json new file mode 100644 index 000000000..2a4772519 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/boxy.json @@ -0,0 +1,63 @@ +[ + [ + [3432, 2779], + [3432, 2794], + [3450, 2794], + [3450, 2825], + [3413, 2825], + [3413, 2856], + [3395, 2856], + [3395, 2871], + [3377, 2871], + [3377, 2856], + [3359, 2856], + [3359, 2840], + [3341, 2840], + [3341, 2871], + [3322, 2871], + [3322, 2887], + [3249, 2887], + [3249, 2871], + [3268, 2871], + [3268, 2840], + [3304, 2840], + [3304, 2825], + [3322, 2825], + [3322, 2810], + [3304, 2810], + [3304, 2794], + [3322, 2794], + [3322, 2779], + [3341, 2779], + [3341, 2733], + [3359, 2733], + [3359, 2687], + [3395, 2687], + [3395, 2702], + [3432, 2702], + [3432, 2717], + [3450, 2717], + [3450, 2733], + [3486, 2733], + [3486, 2748], + [3468, 2748], + [3468, 2763], + [3450, 2763], + [3450, 2779], + [3432, 2779] + ], + [ + [3359, 2794], + [3341, 2794], + [3341, 2810], + [3395, 2810], + [3395, 2794], + [3377, 2794], + [3377, 2779], + [3359, 2779], + [3359, 2794] + ], + [[3432, 2779], [3432, 2748], [3413, 2748], [3413, 2779], [3432, 2779]], + [[3377, 2779], [3395, 2779], [3395, 2748], [3377, 2748], [3377, 2779]], + [[3377, 2717], [3395, 2717], [3395, 2702], [3377, 2702], [3377, 2717]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/building.json b/packages/melonjs/tests/earcut/fixtures/building.json new file mode 100644 index 000000000..6017f8c27 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/building.json @@ -0,0 +1,19 @@ +[ + [ + [661, 112], + [661, 96], + [666, 96], + [666, 87], + [743, 87], + [771, 87], + [771, 114], + [750, 114], + [750, 113], + [742, 113], + [742, 106], + [710, 106], + [710, 113], + [666, 113], + [666, 112] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/collinear-diagonal.json b/packages/melonjs/tests/earcut/fixtures/collinear-diagonal.json new file mode 100644 index 000000000..ec5622f56 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/collinear-diagonal.json @@ -0,0 +1,28 @@ +[ + [ + [3468, 1913], + [3486, 1884], + [3413, 1869], + [3322, 1869], + [3413, 1854], + [3413, 1869], + [3486, 1869], + [3486, 1884], + [3504, 1884], + [3504, 1869], + [3432, 1869], + [3432, 1854], + [3395, 1854], + [3432, 1839], + [3432, 1854], + [3450, 1839], + [3341, 1839], + [3341, 1825], + [3195, 1825], + [3341, 1810], + [3341, 1825], + [3450, 1825], + [3523, 1854], + [3523, 1913] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/degenerate.json b/packages/melonjs/tests/earcut/fixtures/degenerate.json new file mode 100644 index 000000000..f95f3c401 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/degenerate.json @@ -0,0 +1 @@ +[[[100, 100], [100, 100], [200, 100], [200, 200], [200, 100], [0, 100]]] diff --git a/packages/melonjs/tests/earcut/fixtures/dude.json b/packages/melonjs/tests/earcut/fixtures/dude.json new file mode 100644 index 000000000..3c7255f42 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/dude.json @@ -0,0 +1,107 @@ +[ + [ + [280.35714, 648.79075], + [286.78571, 662.8979], + [263.28607, 661.17871], + [262.31092, 671.41548], + [250.53571, 677.00504], + [250.53571, 683.43361], + [256.42857, 685.21933], + [297.14286, 669.50504], + [289.28571, 649.50504], + [285, 631.6479], + [285, 608.79075], + [292.85714, 585.21932], + [306.42857, 563.79075], + [323.57143, 548.79075], + [339.28571, 545.21932], + [357.85714, 547.36218], + [375, 550.21932], + [391.42857, 568.07647], + [404.28571, 588.79075], + [413.57143, 612.36218], + [417.14286, 628.07647], + [438.57143, 619.1479], + [438.03572, 618.96932], + [437.5, 609.50504], + [426.96429, 609.86218], + [424.64286, 615.57647], + [419.82143, 615.04075], + [420.35714, 605.04075], + [428.39286, 598.43361], + [437.85714, 599.68361], + [443.57143, 613.79075], + [450.71429, 610.21933], + [431.42857, 575.21932], + [405.71429, 550.21932], + [372.85714, 534.50504], + [349.28571, 531.6479], + [346.42857, 521.6479], + [346.42857, 511.6479], + [350.71429, 496.6479], + [367.85714, 476.6479], + [377.14286, 460.93361], + [385.71429, 445.21932], + [388.57143, 404.50504], + [360, 352.36218], + [337.14286, 325.93361], + [330.71429, 334.50504], + [347.14286, 354.50504], + [337.85714, 370.21932], + [333.57143, 359.50504], + [319.28571, 353.07647], + [312.85714, 366.6479], + [350.71429, 387.36218], + [368.57143, 408.07647], + [375.71429, 431.6479], + [372.14286, 454.50504], + [366.42857, 462.36218], + [352.85714, 462.36218], + [336.42857, 456.6479], + [332.85714, 438.79075], + [338.57143, 423.79075], + [338.57143, 411.6479], + [327.85714, 405.93361], + [320.71429, 407.36218], + [315.71429, 423.07647], + [314.28571, 440.21932], + [325, 447.71932], + [324.82143, 460.93361], + [317.85714, 470.57647], + [304.28571, 483.79075], + [287.14286, 491.29075], + [263.03571, 498.61218], + [251.60714, 503.07647], + [251.25, 533.61218], + [260.71429, 533.61218], + [272.85714, 528.43361], + [286.07143, 518.61218], + [297.32143, 508.25504], + [297.85714, 507.36218], + [298.39286, 506.46932], + [307.14286, 496.6479], + [312.67857, 491.6479], + [317.32143, 503.07647], + [322.5, 514.1479], + [325.53571, 521.11218], + [327.14286, 525.75504], + [326.96429, 535.04075], + [311.78571, 540.04075], + [291.07143, 552.71932], + [274.82143, 568.43361], + [259.10714, 592.8979], + [254.28571, 604.50504], + [251.07143, 621.11218], + [250.53571, 649.1479], + [268.1955, 654.36208] + ], + [[325, 437], [320, 423], [329, 413], [332, 423]], + [ + [320.72342, 480], + [338.90617, 465.96863], + [347.99754, 480.61584], + [329.8148, 510.41534], + [339.91632, 480.11077], + [334.86556, 478.09046] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/eberly-3.json b/packages/melonjs/tests/earcut/fixtures/eberly-3.json new file mode 100644 index 000000000..3fc6cc8a4 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/eberly-3.json @@ -0,0 +1,78 @@ +[ + [ + [2328, 2408], + [2328, 2472], + [2344, 2472], + [2344, 2432], + [2384, 2448], + [2384, 2536], + [2408, 2552], + [2448, 2544], + [2456, 2560], + [2496, 2544], + [2480, 2624], + [2456, 2664], + [2424, 2680], + [2400, 2768], + [2376, 2768], + [2368, 2704], + [2336, 2704], + [2264, 2784], + [2216, 2784], + [2200, 2760], + [2168, 2760], + [2152, 2744], + [2128, 2744], + [2128, 2784], + [2072, 2768], + [2032, 2720], + [2000, 2720], + [2000, 2688], + [1936, 2696], + [1920, 2736], + [1888, 2728], + [1896, 2696], + [1928, 2688], + [1928, 2664], + [1896, 2664], + [1896, 2640], + [1912, 2632], + [1872, 2608], + [1888, 2576], + [2056, 2576], + [2088, 2600], + [2184, 2608], + [2216, 2632], + [2256, 2624], + [2248, 2600], + [2216, 2592], + [2192, 2560], + [2120, 2576], + [2072, 2544], + [2096, 2544], + [2080, 2520], + [2080, 2488], + [2096, 2480], + [2080, 2448], + [2096, 2432], + [2176, 2496], + [2200, 2488], + [2224, 2528], + [2248, 2528], + [2240, 2488], + [2256, 2472], + [2280, 2480], + [2264, 2416], + [2272, 2392], + [2328, 2408] + ], + [ + [2320, 2608], + [2304, 2640], + [2312, 2664], + [2360, 2632], + [2352, 2608], + [2320, 2608] + ], + [[1912, 2632], [1936, 2632], [1936, 2616], [1912, 2608], [1912, 2632]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/eberly-6.json b/packages/melonjs/tests/earcut/fixtures/eberly-6.json new file mode 100644 index 000000000..b00a4fc3a --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/eberly-6.json @@ -0,0 +1,1453 @@ +[ + [ + [142.807, -11.178], + [142.81, -11.171], + [142.807, -11.168], + [142.797, -11.143], + [142.795, -11.113], + [142.79, -11.085], + [142.778, -11.054], + [142.77, -11.039], + [142.759, -11.027], + [142.752, -11.015], + [142.746, -10.986], + [142.742, -10.975], + [142.725, -10.968], + [142.701, -10.97], + [142.678, -10.982], + [142.666, -11.003], + [142.66, -10.983], + [142.668, -10.951], + [142.659, -10.934], + [142.649, -10.929], + [142.64, -10.932], + [142.634, -10.931], + [142.625, -10.882], + [142.615, -10.868], + [142.591, -10.865], + [142.567, -10.87], + [142.556, -10.882], + [142.552, -10.904], + [142.54, -10.925], + [142.523, -10.942], + [142.502, -10.948], + [142.515, -10.924], + [142.514, -10.9], + [142.51, -10.877], + [142.515, -10.852], + [142.521, -10.847], + [142.542, -10.842], + [142.55, -10.838], + [142.555, -10.829], + [142.564, -10.806], + [142.57, -10.797], + [142.577, -10.792], + [142.593, -10.786], + [142.601, -10.78], + [142.606, -10.772], + [142.612, -10.762], + [142.616, -10.752], + [142.615, -10.745], + [142.601, -10.735], + [142.564, -10.717], + [142.55, -10.708], + [142.548, -10.703], + [142.55, -10.696], + [142.55, -10.69], + [142.546, -10.688], + [142.54, -10.689], + [142.537, -10.691], + [142.535, -10.693], + [142.532, -10.695], + [142.527, -10.698], + [142.511, -10.712], + [142.505, -10.715], + [142.463, -10.711], + [142.449, -10.715], + [142.434, -10.728], + [142.425, -10.745], + [142.409, -10.792], + [142.406, -10.807], + [142.401, -10.82], + [142.365, -10.858], + [142.34, -10.89], + [142.323, -10.902], + [142.3, -10.906], + [142.28, -10.907], + [142.258, -10.911], + [142.239, -10.918], + [142.228, -10.927], + [142.221, -10.92], + [142.175, -10.93], + [142.151, -10.951], + [142.145, -10.983], + [142.158, -11.067], + [142.159, -11.151], + [142.154, -11.178], + [136.72, -11.178], + [136.72, -11.174], + [136.734, -11.138], + [136.747, -11.093], + [136.764, -11.04], + [136.762, -11.019], + [136.756, -11.027], + [136.752, -11.037], + [136.749, -11.035], + [136.746, -11.034], + [136.742, -11.033], + [136.739, -11.03], + [136.719, -11.051], + [136.735, -11.064], + [136.731, -11.079], + [136.723, -11.086], + [136.711, -11.097], + [136.71, -11.121], + [136.7, -11.14], + [136.688, -11.178], + [136.685, -11.178], + [135.0, -11.178], + [135.0, -4.342], + [135.186, -4.449], + [135.228, -4.461], + [135.272, -4.458], + [135.331, -4.44], + [135.359, -4.444], + [135.413, -4.436], + [135.43, -4.43], + [135.444, -4.441], + [135.467, -4.446], + [135.587, -4.46], + [135.605, -4.468], + [135.614, -4.475], + [135.656, -4.486], + [135.7, -4.487], + [135.708, -4.489], + [135.725, -4.495], + [135.75, -4.497], + [135.776, -4.495], + [135.793, -4.486], + [135.829, -4.499], + [135.912, -4.498], + [135.95, -4.506], + [135.97, -4.52], + [136.016, -4.571], + [136.036, -4.586], + [136.05, -4.59], + [136.063, -4.591], + [136.081, -4.595], + [136.095, -4.603], + [136.107, -4.612], + [136.122, -4.619], + [136.146, -4.622], + [136.147, -4.626], + [136.177, -4.65], + [136.267, -4.676], + [136.355, -4.677], + [136.376, -4.684], + [136.403, -4.708], + [136.413, -4.712], + [136.433, -4.712], + [136.44, -4.715], + [136.464, -4.736], + [136.538, -4.774], + [136.626, -4.823], + [136.696, -4.847], + [136.743, -4.882], + [136.753, -4.88], + [136.763, -4.874], + [136.786, -4.876], + [136.799, -4.88], + [136.803, -4.883], + [136.801, -4.9], + [136.804, -4.91], + [136.812, -4.92], + [136.822, -4.928], + [136.832, -4.931], + [136.854, -4.928], + [136.875, -4.92], + [136.947, -4.876], + [136.969, -4.87], + [136.979, -4.88], + [136.974, -4.885], + [136.962, -4.891], + [136.95, -4.899], + [136.944, -4.91], + [136.947, -4.918], + [136.954, -4.923], + [137.007, -4.946], + [137.042, -4.943], + [137.073, -4.924], + [137.095, -4.889], + [137.102, -4.889], + [137.096, -4.922], + [137.088, -4.943], + [137.09, -4.96], + [137.115, -4.979], + [137.15, -4.945], + [137.152, -4.974], + [137.169, -4.991], + [137.219, -5.013], + [137.232, -4.999], + [137.224, -4.982], + [137.232, -4.969], + [137.279, -4.937], + [137.283, -4.94], + [137.267, -4.999], + [137.268, -5.014], + [137.277, -5.02], + [137.302, -5.027], + [137.309, -5.022], + [137.308, -4.999], + [137.335, -5.031], + [137.35, -5.04], + [137.363, -5.026], + [137.369, -5.026], + [137.37, -5.037], + [137.368, -5.046], + [137.363, -5.055], + [137.356, -5.062], + [137.378, -5.082], + [137.404, -5.098], + [137.433, -5.103], + [137.465, -5.096], + [137.468, -5.11], + [137.474, -5.115], + [137.482, -5.117], + [137.492, -5.123], + [137.509, -5.142], + [137.519, -5.149], + [137.533, -5.15], + [137.54, -5.144], + [137.556, -5.121], + [137.561, -5.116], + [137.573, -5.121], + [137.581, -5.143], + [137.595, -5.15], + [137.595, -5.157], + [137.574, -5.167], + [137.58, -5.182], + [137.598, -5.196], + [137.616, -5.205], + [137.647, -5.212], + [137.663, -5.22], + [137.673, -5.218], + [137.682, -5.213], + [137.691, -5.211], + [137.706, -5.222], + [137.716, -5.257], + [137.732, -5.273], + [137.752, -5.278], + [137.771, -5.272], + [137.808, -5.253], + [137.802, -5.27], + [137.783, -5.298], + [137.78, -5.315], + [137.783, -5.318], + [137.809, -5.353], + [137.814, -5.358], + [137.822, -5.363], + [137.853, -5.362], + [137.904, -5.324], + [137.925, -5.329], + [137.908, -5.363], + [137.915, -5.387], + [137.959, -5.431], + [137.987, -5.47], + [137.999, -5.479], + [138.026, -5.485], + [138.036, -5.475], + [138.035, -5.455], + [138.027, -5.431], + [138.041, -5.436], + [138.051, -5.432], + [138.058, -5.42], + [138.061, -5.404], + [138.071, -5.41], + [138.075, -5.42], + [138.074, -5.445], + [138.064, -5.489], + [138.064, -5.511], + [138.078, -5.52], + [138.085, -5.522], + [138.105, -5.531], + [138.11, -5.534], + [138.108, -5.545], + [138.101, -5.549], + [138.092, -5.55], + [138.082, -5.555], + [138.069, -5.565], + [138.06, -5.575], + [138.055, -5.59], + [138.053, -5.613], + [138.057, -5.658], + [138.068, -5.698], + [138.069, -5.708], + [138.069, -5.72], + [138.071, -5.729], + [138.082, -5.734], + [138.083, -5.738], + [138.086, -5.74], + [138.106, -5.726], + [138.152, -5.723], + [138.172, -5.717], + [138.214, -5.692], + [138.233, -5.684], + [138.253, -5.68], + [138.277, -5.679], + [138.32, -5.671], + [138.343, -5.67], + [138.363, -5.679], + [138.307, -5.696], + [138.252, -5.719], + [138.158, -5.774], + [138.17, -5.787], + [138.176, -5.796], + [138.178, -5.804], + [138.182, -5.81], + [138.209, -5.825], + [138.322, -5.851], + [138.343, -5.849], + [138.386, -5.837], + [138.404, -5.836], + [138.377, -5.856], + [138.304, -5.868], + [138.271, -5.887], + [138.262, -5.915], + [138.276, -5.946], + [138.339, -6.043], + [138.343, -6.058], + [138.347, -6.071], + [138.365, -6.092], + [138.37, -6.106], + [138.372, -6.124], + [138.39, -6.172], + [138.392, -6.186], + [138.39, -6.234], + [138.395, -6.253], + [138.414, -6.291], + [138.421, -6.319], + [138.466, -6.402], + [138.604, -6.528], + [138.619, -6.535], + [138.632, -6.544], + [138.678, -6.603], + [138.709, -6.63], + [138.829, -6.706], + [138.763, -6.67], + [138.743, -6.665], + [138.703, -6.645], + [138.682, -6.645], + [138.671, -6.672], + [138.673, -6.695], + [138.683, -6.715], + [138.7, -6.728], + [138.746, -6.74], + [138.768, -6.757], + [138.822, -6.806], + [138.838, -6.815], + [138.857, -6.82], + [138.924, -6.826], + [138.966, -6.836], + [139.0, -6.853], + [139.069, -6.918], + [139.115, -6.941], + [139.123, -6.949], + [139.133, -6.952], + [139.157, -6.954], + [139.18, -6.959], + [139.192, -6.973], + [139.182, -6.971], + [139.14, -6.973], + [139.126, -6.972], + [139.118, -6.968], + [139.104, -6.959], + [139.083, -6.953], + [139.073, -6.949], + [139.069, -6.942], + [139.038, -6.918], + [139.018, -6.909], + [138.989, -6.866], + [138.97, -6.856], + [138.96, -6.854], + [138.94, -6.845], + [138.931, -6.843], + [138.917, -6.842], + [138.884, -6.849], + [138.798, -6.856], + [138.783, -6.862], + [138.756, -6.888], + [138.74, -6.897], + [138.716, -6.898], + [138.675, -6.881], + [138.654, -6.877], + [138.613, -6.877], + [138.597, -6.881], + [138.581, -6.891], + [138.562, -6.919], + [138.572, -6.942], + [138.646, -7.0], + [138.748, -7.098], + [138.753, -7.107], + [138.762, -7.114], + [138.815, -7.131], + [138.843, -7.146], + [138.858, -7.15], + [138.925, -7.153], + [138.946, -7.157], + [138.966, -7.165], + [139.019, -7.194], + [139.038, -7.212], + [139.061, -7.212], + [139.104, -7.206], + [139.147, -7.206], + [139.159, -7.203], + [139.167, -7.195], + [139.181, -7.175], + [139.206, -7.15], + [139.222, -7.144], + [139.24, -7.151], + [139.24, -7.158], + [139.215, -7.167], + [139.199, -7.189], + [139.188, -7.215], + [139.175, -7.237], + [139.157, -7.243], + [139.004, -7.24], + [138.991, -7.236], + [138.962, -7.215], + [138.945, -7.206], + [138.905, -7.199], + [138.688, -7.193], + [138.667, -7.198], + [138.666, -7.21], + [138.677, -7.223], + [138.691, -7.234], + [138.7, -7.237], + [138.709, -7.239], + [138.729, -7.24], + [138.739, -7.244], + [138.746, -7.251], + [138.751, -7.258], + [138.767, -7.265], + [138.841, -7.315], + [138.865, -7.336], + [138.886, -7.361], + [138.926, -7.427], + [138.935, -7.449], + [138.944, -7.497], + [138.958, -7.507], + [139.0, -7.508], + [139.036, -7.515], + [139.071, -7.533], + [139.093, -7.56], + [139.089, -7.597], + [139.081, -7.606], + [139.069, -7.614], + [139.059, -7.623], + [139.055, -7.634], + [139.048, -7.668], + [139.045, -7.675], + [139.035, -7.69], + [139.007, -7.754], + [139.002, -7.836], + [138.994, -7.865], + [138.966, -7.885], + [138.927, -7.894], + [138.915, -7.903], + [138.911, -7.923], + [138.911, -8.008], + [138.906, -8.031], + [138.906, -8.044], + [138.92, -8.052], + [138.924, -8.061], + [138.925, -8.07], + [138.921, -8.08], + [138.901, -8.092], + [138.859, -8.101], + [138.843, -8.117], + [138.839, -8.138], + [138.843, -8.161], + [138.853, -8.184], + [138.876, -8.219], + [138.914, -8.292], + [138.921, -8.295], + [138.935, -8.296], + [138.943, -8.291], + [138.951, -8.281], + [138.957, -8.271], + [138.959, -8.265], + [138.963, -8.246], + [138.973, -8.23], + [139.09, -8.134], + [139.123, -8.117], + [139.201, -8.096], + [139.224, -8.074], + [139.227, -8.028], + [139.23, -8.023], + [139.232, -8.018], + [139.23, -8.011], + [139.225, -8.009], + [139.214, -8.007], + [139.212, -8.004], + [139.211, -7.994], + [139.207, -7.974], + [139.206, -7.963], + [139.217, -7.951], + [139.243, -7.957], + [139.288, -7.973], + [139.269, -7.986], + [139.252, -7.982], + [139.235, -7.975], + [139.219, -7.98], + [139.24, -8.003], + [139.245, -8.015], + [139.248, -8.049], + [139.252, -8.067], + [139.25, -8.073], + [139.246, -8.08], + [139.243, -8.091], + [139.24, -8.102], + [139.24, -8.111], + [139.255, -8.146], + [139.283, -8.173], + [139.32, -8.19], + [139.357, -8.199], + [139.395, -8.201], + [139.435, -8.197], + [139.515, -8.179], + [139.547, -8.166], + [139.599, -8.135], + [139.631, -8.125], + [139.769, -8.11], + [139.932, -8.109], + [139.974, -8.097], + [140.015, -8.074], + [140.034, -8.059], + [140.042, -8.046], + [140.046, -7.98], + [140.054, -7.936], + [140.061, -7.924], + [140.075, -7.92], + [140.1, -7.92], + [140.119, -7.915], + [140.135, -7.893], + [140.152, -7.885], + [140.129, -7.936], + [140.112, -7.947], + [140.083, -7.933], + [140.061, -7.948], + [140.054, -7.972], + [140.057, -7.996], + [140.066, -8.029], + [140.062, -8.066], + [140.058, -8.082], + [140.048, -8.087], + [140.035, -8.087], + [140.021, -8.09], + [139.998, -8.104], + [139.98, -8.122], + [139.971, -8.142], + [139.974, -8.165], + [139.988, -8.192], + [140.032, -8.246], + [140.252, -8.409], + [140.267, -8.431], + [140.301, -8.467], + [140.354, -8.489], + [140.363, -8.491], + [140.368, -8.508], + [140.378, -8.522], + [140.446, -8.578], + [140.453, -8.587], + [140.507, -8.638], + [140.622, -8.807], + [140.857, -9.049], + [140.921, -9.079], + [140.933, -9.08], + [140.977, -9.106], + [140.977, -9.106], + [141.008, -9.124], + [141.115, -9.218], + [141.153, -9.232], + [141.2, -9.228], + [141.232, -9.213], + [141.31, -9.152], + [141.346, -9.142], + [141.385, -9.142], + [141.422, -9.15], + [141.453, -9.166], + [141.495, -9.195], + [141.51, -9.215], + [141.53, -9.218], + [141.551, -9.218], + [141.563, -9.22], + [141.579, -9.213], + [141.593, -9.219], + [141.606, -9.229], + [141.621, -9.234], + [141.635, -9.232], + [141.651, -9.227], + [141.665, -9.22], + [141.673, -9.214], + [141.698, -9.215], + [141.783, -9.2], + [141.806, -9.203], + [141.847, -9.217], + [141.868, -9.22], + [141.893, -9.219], + [141.913, -9.215], + [141.974, -9.193], + [141.994, -9.189], + [142.136, -9.178], + [142.169, -9.179], + [142.181, -9.176], + [142.2, -9.162], + [142.211, -9.159], + [142.223, -9.161], + [142.276, -9.179], + [142.319, -9.204], + [142.334, -9.207], + [142.358, -9.209], + [142.373, -9.215], + [142.399, -9.228], + [142.429, -9.225], + [142.465, -9.24], + [142.499, -9.263], + [142.547, -9.304], + [142.577, -9.324], + [142.612, -9.335], + [142.653, -9.33], + [142.708, -9.299], + [142.715, -9.288], + [142.731, -9.278], + [142.838, -9.237], + [142.874, -9.209], + [142.92, -9.19], + [142.941, -9.179], + [142.949, -9.169], + [142.958, -9.156], + [142.967, -9.144], + [142.978, -9.138], + [142.988, -9.136], + [143.011, -9.122], + [143.036, -9.102], + [143.053, -9.093], + [143.142, -9.066], + [143.156, -9.063], + [143.163, -9.06], + [143.168, -9.053], + [143.171, -9.046], + [143.173, -9.043], + [143.178, -9.042], + [143.189, -9.044], + [143.204, -9.041], + [143.225, -9.039], + [143.235, -9.036], + [143.229, -9.029], + [143.258, -9.024], + [143.315, -9.024], + [143.345, -9.016], + [143.361, -9.007], + [143.373, -9.0], + [143.396, -8.978], + [143.406, -8.962], + [143.406, -8.945], + [143.4, -8.912], + [143.4, -8.782], + [143.395, -8.769], + [143.386, -8.753], + [143.348, -8.708], + [143.318, -8.659], + [143.262, -8.592], + [143.132, -8.486], + [143.102, -8.467], + [143.063, -8.453], + [142.938, -8.428], + [142.9, -8.413], + [142.835, -8.37], + [142.814, -8.365], + [142.804, -8.36], + [142.769, -8.33], + [142.728, -8.317], + [142.712, -8.323], + [142.632, -8.309], + [142.596, -8.321], + [142.53, -8.365], + [142.494, -8.378], + [142.452, -8.373], + [142.42, -8.355], + [142.397, -8.328], + [142.367, -8.232], + [142.365, -8.21], + [142.354, -8.189], + [142.33, -8.184], + [142.302, -8.188], + [142.26, -8.199], + [142.247, -8.2], + [142.231, -8.194], + [142.225, -8.198], + [142.219, -8.204], + [142.211, -8.207], + [142.196, -8.211], + [142.182, -8.22], + [142.16, -8.241], + [142.144, -8.234], + [142.14, -8.226], + [142.146, -8.217], + [142.16, -8.207], + [142.171, -8.203], + [142.182, -8.201], + [142.193, -8.198], + [142.204, -8.189], + [142.211, -8.181], + [142.217, -8.175], + [142.225, -8.173], + [142.26, -8.171], + [142.317, -8.159], + [142.36, -8.167], + [142.381, -8.193], + [142.405, -8.293], + [142.414, -8.31], + [142.429, -8.324], + [142.451, -8.33], + [142.494, -8.333], + [142.514, -8.332], + [142.536, -8.324], + [142.593, -8.287], + [142.615, -8.282], + [142.634, -8.28], + [142.684, -8.269], + [142.7, -8.261], + [142.71, -8.267], + [142.715, -8.268], + [142.841, -8.288], + [142.94, -8.333], + [142.958, -8.337], + [142.98, -8.336], + [143.215, -8.275], + [143.3, -8.269], + [143.328, -8.252], + [143.338, -8.248], + [143.592, -8.242], + [143.612, -8.239], + [143.629, -8.23], + [143.635, -8.211], + [143.628, -8.186], + [143.57, -8.085], + [143.56, -8.045], + [143.548, -8.032], + [143.467, -7.996], + [143.448, -7.982], + [143.441, -7.963], + [143.437, -7.938], + [143.426, -7.93], + [143.386, -7.926], + [143.375, -7.922], + [143.367, -7.918], + [143.361, -7.911], + [143.359, -7.902], + [143.364, -7.896], + [143.375, -7.899], + [143.386, -7.903], + [143.389, -7.906], + [143.416, -7.906], + [143.434, -7.909], + [143.448, -7.919], + [143.461, -7.939], + [143.478, -7.976], + [143.489, -7.989], + [143.506, -7.994], + [143.563, -7.998], + [143.628, -7.982], + [143.651, -7.981], + [143.67, -7.99], + [143.68, -7.997], + [143.715, -8.008], + [143.723, -8.014], + [143.741, -8.029], + [143.749, -8.035], + [143.767, -8.04], + [143.861, -8.041], + [143.881, -8.038], + [143.898, -8.028], + [143.914, -8.008], + [143.876, -7.97], + [143.859, -7.96], + [143.85, -7.957], + [143.833, -7.956], + [143.824, -7.953], + [143.818, -7.948], + [143.81, -7.937], + [143.804, -7.933], + [143.862, -7.935], + [143.879, -7.939], + [143.894, -7.953], + [143.908, -7.972], + [143.923, -7.989], + [143.941, -7.994], + [143.943, -7.992], + [143.957, -7.972], + [143.941, -7.93], + [143.893, -7.857], + [143.867, -7.826], + [143.856, -7.808], + [143.852, -7.785], + [143.851, -7.761], + [143.847, -7.74], + [143.841, -7.72], + [143.76, -7.583], + [143.742, -7.542], + [143.744, -7.536], + [143.747, -7.529], + [143.746, -7.524], + [143.723, -7.519], + [143.7, -7.51], + [143.691, -7.508], + [143.681, -7.502], + [143.649, -7.468], + [143.639, -7.452], + [143.646, -7.438], + [143.65, -7.449], + [143.653, -7.452], + [143.662, -7.462], + [143.696, -7.488], + [143.711, -7.494], + [143.723, -7.494], + [143.746, -7.497], + [143.756, -7.5], + [143.766, -7.506], + [143.769, -7.51], + [143.777, -7.528], + [143.813, -7.594], + [143.818, -7.614], + [143.828, -7.632], + [143.851, -7.652], + [143.924, -7.694], + [144.112, -7.758], + [144.129, -7.772], + [144.139, -7.777], + [144.151, -7.774], + [144.163, -7.77], + [144.174, -7.768], + [144.187, -7.772], + [144.196, -7.778], + [144.215, -7.796], + [144.229, -7.789], + [144.266, -7.776], + [144.276, -7.768], + [144.275, -7.756], + [144.265, -7.742], + [144.252, -7.731], + [144.242, -7.726], + [144.255, -7.706], + [144.261, -7.684], + [144.254, -7.667], + [144.229, -7.666], + [144.229, -7.658], + [144.241, -7.655], + [144.253, -7.65], + [144.263, -7.643], + [144.27, -7.631], + [144.285, -7.647], + [144.307, -7.693], + [144.324, -7.7], + [144.334, -7.689], + [144.327, -7.665], + [144.316, -7.637], + [144.311, -7.61], + [144.344, -7.659], + [144.355, -7.687], + [144.36, -7.717], + [144.367, -7.744], + [144.385, -7.752], + [144.403, -7.743], + [144.413, -7.72], + [144.424, -7.727], + [144.438, -7.74], + [144.45, -7.754], + [144.455, -7.765], + [144.46, -7.769], + [144.48, -7.796], + [144.482, -7.802], + [144.508, -7.798], + [144.5, -7.774], + [144.48, -7.748], + [144.469, -7.737], + [144.465, -7.721], + [144.457, -7.708], + [144.447, -7.696], + [144.441, -7.686], + [144.436, -7.66], + [144.434, -7.627], + [144.431, -7.612], + [144.418, -7.585], + [144.413, -7.569], + [144.412, -7.531], + [144.407, -7.514], + [144.413, -7.514], + [144.422, -7.527], + [144.433, -7.559], + [144.441, -7.576], + [144.446, -7.58], + [144.453, -7.584], + [144.459, -7.588], + [144.462, -7.593], + [144.462, -7.599], + [144.466, -7.617], + [144.469, -7.624], + [144.478, -7.635], + [144.504, -7.656], + [144.51, -7.669], + [144.514, -7.672], + [144.523, -7.669], + [144.533, -7.662], + [144.538, -7.652], + [144.515, -7.633], + [144.51, -7.624], + [144.509, -7.611], + [144.517, -7.579], + [144.517, -7.508], + [144.522, -7.496], + [144.538, -7.514], + [144.539, -7.525], + [144.537, -7.549], + [144.541, -7.559], + [144.547, -7.566], + [144.55, -7.573], + [144.551, -7.582], + [144.551, -7.593], + [144.555, -7.607], + [144.564, -7.625], + [144.575, -7.642], + [144.585, -7.652], + [144.604, -7.657], + [144.629, -7.656], + [144.652, -7.649], + [144.661, -7.634], + [144.658, -7.616], + [144.651, -7.598], + [144.648, -7.58], + [144.654, -7.561], + [144.679, -7.582], + [144.69, -7.594], + [144.699, -7.617], + [144.736, -7.644], + [144.757, -7.669], + [144.771, -7.681], + [144.787, -7.686], + [144.805, -7.686], + [144.825, -7.683], + [144.837, -7.674], + [144.831, -7.658], + [144.84, -7.637], + [144.844, -7.589], + [144.852, -7.569], + [144.864, -7.586], + [144.867, -7.608], + [144.866, -7.706], + [144.858, -7.724], + [144.842, -7.744], + [144.843, -7.75], + [144.851, -7.758], + [144.861, -7.765], + [144.87, -7.768], + [144.872, -7.77], + [144.878, -7.779], + [144.88, -7.782], + [144.885, -7.782], + [144.897, -7.777], + [144.904, -7.775], + [144.92, -7.781], + [144.932, -7.79], + [144.943, -7.792], + [144.955, -7.775], + [144.985, -7.81], + [144.996, -7.817], + [145.058, -7.817], + [145.068, -7.812], + [145.071, -7.806], + [145.071, -7.785], + [145.075, -7.776], + [145.082, -7.779], + [145.089, -7.788], + [145.093, -7.799], + [145.102, -7.817], + [145.124, -7.831], + [145.15, -7.838], + [145.168, -7.836], + [145.167, -7.831], + [145.175, -7.816], + [145.184, -7.806], + [145.192, -7.818], + [145.206, -7.828], + [145.213, -7.84], + [145.234, -7.859], + [145.243, -7.864], + [145.255, -7.865], + [145.265, -7.863], + [145.275, -7.859], + [145.284, -7.857], + [145.322, -7.862], + [145.35, -7.877], + [145.408, -7.932], + [145.423, -7.94], + [145.442, -7.944], + [145.466, -7.945], + [145.533, -7.933], + [145.552, -7.939], + [145.552, -7.933], + [145.568, -7.939], + [145.583, -7.937], + [145.598, -7.933], + [145.613, -7.933], + [145.627, -7.938], + [145.645, -7.956], + [145.658, -7.96], + [145.719, -7.96], + [145.737, -7.953], + [145.723, -7.933], + [145.741, -7.924], + [145.758, -7.927], + [145.772, -7.927], + [145.785, -7.912], + [145.791, -7.912], + [145.779, -7.936], + [145.778, -7.942], + [145.78, -7.947], + [145.785, -7.95], + [145.79, -7.954], + [145.791, -7.96], + [145.787, -7.965], + [145.774, -7.967], + [145.771, -7.97], + [145.773, -7.978], + [145.778, -7.983], + [145.782, -7.987], + [145.785, -7.99], + [145.798, -8.007], + [145.861, -8.028], + [145.881, -8.042], + [145.907, -8.033], + [145.939, -8.035], + [145.997, -8.049], + [146.05, -8.076], + [146.079, -8.087], + [146.1, -8.083], + [146.105, -8.093], + [146.103, -8.1], + [146.096, -8.106], + [146.086, -8.111], + [146.098, -8.122], + [146.11, -8.138], + [146.113, -8.154], + [146.1, -8.165], + [146.117, -8.2], + [146.127, -8.21], + [146.151, -8.214], + [146.16, -8.22], + [146.189, -8.248], + [146.222, -8.26], + [146.235, -8.274], + [146.245, -8.292], + [146.25, -8.307], + [146.25, -11.178], + [142.807, -11.178] + ], + [ + [138.623, -6.767], + [138.639, -6.787], + [138.65, -6.797], + [138.661, -6.802], + [138.673, -6.81], + [138.682, -6.848], + [138.695, -6.856], + [138.707, -6.859], + [138.716, -6.865], + [138.728, -6.868], + [138.747, -6.863], + [138.769, -6.849], + [138.782, -6.839], + [138.787, -6.83], + [138.783, -6.814], + [138.759, -6.792], + [138.753, -6.778], + [138.747, -6.768], + [138.731, -6.763], + [138.695, -6.761], + [138.679, -6.758], + [138.666, -6.75], + [138.641, -6.731], + [138.627, -6.72], + [138.619, -6.729], + [138.617, -6.748], + [138.623, -6.767] + ], + [ + [138.395, -7.405], + [138.244, -7.456], + [138.089, -7.56], + [138.028, -7.61], + [138.007, -7.638], + [137.985, -7.679], + [137.976, -7.703], + [137.973, -7.723], + [137.966, -7.739], + [137.918, -7.782], + [137.895, -7.816], + [137.824, -7.964], + [137.818, -7.973], + [137.81, -7.984], + [137.801, -8.042], + [137.789, -8.052], + [137.759, -8.073], + [137.753, -8.087], + [137.75, -8.101], + [137.726, -8.145], + [137.637, -8.389], + [137.638, -8.426], + [137.677, -8.426], + [137.76, -8.394], + [137.802, -8.383], + [137.849, -8.378], + [138.034, -8.382], + [138.178, -8.385], + [138.223, -8.392], + [138.293, -8.419], + [138.336, -8.419], + [138.376, -8.41], + [138.412, -8.396], + [138.444, -8.379], + [138.472, -8.358], + [138.508, -8.316], + [138.518, -8.309], + [138.536, -8.302], + [138.603, -8.255], + [138.621, -8.234], + [138.646, -8.189], + [138.661, -8.169], + [138.68, -8.157], + [138.701, -8.154], + [138.747, -8.152], + [138.772, -8.143], + [138.788, -8.13], + [138.818, -8.093], + [138.837, -8.08], + [138.858, -8.075], + [138.904, -8.076], + [138.893, -8.041], + [138.886, -8.007], + [138.884, -7.933], + [138.891, -7.898], + [138.911, -7.879], + [138.966, -7.851], + [138.977, -7.841], + [138.983, -7.83], + [138.989, -7.738], + [138.994, -7.72], + [139.02, -7.672], + [139.035, -7.63], + [139.044, -7.611], + [139.057, -7.595], + [139.076, -7.576], + [139.046, -7.562], + [138.974, -7.553], + [138.939, -7.542], + [138.923, -7.532], + [138.909, -7.52], + [138.896, -7.505], + [138.848, -7.435], + [138.843, -7.422], + [138.805, -7.374], + [138.717, -7.36], + [138.621, -7.365], + [138.556, -7.377], + [138.529, -7.386], + [138.395, -7.405] + ], + [ + [138.558, -8.367], + [138.582, -8.373], + [138.63, -8.371], + [138.654, -8.376], + [138.7, -8.395], + [138.894, -8.405], + [138.91, -8.396], + [138.911, -8.375], + [138.904, -8.352], + [138.897, -8.337], + [138.858, -8.297], + [138.842, -8.277], + [138.835, -8.251], + [138.835, -8.219], + [138.831, -8.186], + [138.817, -8.162], + [138.785, -8.159], + [138.729, -8.177], + [138.689, -8.181], + [138.675, -8.189], + [138.667, -8.203], + [138.665, -8.224], + [138.657, -8.241], + [138.64, -8.257], + [138.564, -8.307], + [138.552, -8.323], + [138.548, -8.347], + [138.558, -8.367] + ], + [ + [142.181, -9.285], + [142.222, -9.291], + [142.261, -9.29], + [142.279, -9.287], + [142.284, -9.278], + [142.28, -9.262], + [142.207, -9.24], + [142.164, -9.251], + [142.151, -9.271], + [142.181, -9.285] + ], + [ + [142.755, -9.37], + [142.719, -9.378], + [142.694, -9.38], + [142.665, -9.374], + [142.637, -9.374], + [142.612, -9.383], + [142.601, -9.4], + [142.612, -9.416], + [142.629, -9.425], + [142.642, -9.428], + [142.714, -9.429], + [142.732, -9.425], + [142.742, -9.419], + [142.752, -9.408], + [142.768, -9.398], + [142.783, -9.386], + [142.771, -9.374], + [142.755, -9.37] + ], + [ + [142.125, -10.158], + [142.139, -10.173], + [142.143, -10.186], + [142.155, -10.188], + [142.167, -10.182], + [142.176, -10.161], + [142.183, -10.153], + [142.19, -10.144], + [142.198, -10.102], + [142.198, -10.092], + [142.19, -10.081], + [142.17, -10.06], + [142.157, -10.053], + [142.142, -10.05], + [142.097, -10.119], + [142.099, -10.136], + [142.11, -10.148], + [142.125, -10.158] + ], + [ + [142.211, -10.183], + [142.204, -10.188], + [142.193, -10.194], + [142.195, -10.207], + [142.201, -10.22], + [142.211, -10.232], + [142.221, -10.242], + [142.234, -10.238], + [142.249, -10.24], + [142.264, -10.247], + [142.276, -10.256], + [142.29, -10.26], + [142.317, -10.213], + [142.334, -10.2], + [142.341, -10.191], + [142.332, -10.17], + [142.314, -10.149], + [142.293, -10.139], + [142.254, -10.138], + [142.232, -10.142], + [142.214, -10.153], + [142.213, -10.158], + [142.214, -10.177], + [142.211, -10.183] + ], + [ + [143.492, -8.553], + [143.482, -8.534], + [143.475, -8.525], + [143.465, -8.522], + [143.443, -8.518], + [143.359, -8.489], + [143.271, -8.469], + [143.256, -8.457], + [143.219, -8.415], + [143.207, -8.414], + [143.194, -8.417], + [143.179, -8.419], + [143.188, -8.43], + [143.209, -8.444], + [143.221, -8.453], + [143.244, -8.485], + [143.255, -8.495], + [143.282, -8.506], + [143.338, -8.522], + [143.401, -8.573], + [143.407, -8.587], + [143.412, -8.596], + [143.425, -8.6], + [143.44, -8.602], + [143.451, -8.608], + [143.474, -8.625], + [143.591, -8.679], + [143.606, -8.689], + [143.612, -8.703], + [143.617, -8.722], + [143.629, -8.73], + [143.642, -8.726], + [143.653, -8.706], + [143.653, -8.683], + [143.644, -8.661], + [143.629, -8.645], + [143.608, -8.638], + [143.588, -8.631], + [143.492, -8.553] + ], + [ + [143.53, -8.486], + [143.582, -8.487], + [143.601, -8.484], + [143.611, -8.475], + [143.612, -8.462], + [143.605, -8.447], + [143.589, -8.421], + [143.586, -8.406], + [143.585, -8.381], + [143.574, -8.374], + [143.484, -8.364], + [143.417, -8.365], + [143.385, -8.371], + [143.373, -8.371], + [143.365, -8.368], + [143.359, -8.362], + [143.351, -8.357], + [143.338, -8.358], + [143.317, -8.372], + [143.33, -8.394], + [143.358, -8.415], + [143.379, -8.426], + [143.424, -8.433], + [143.445, -8.439], + [143.462, -8.458], + [143.51, -8.481], + [143.53, -8.486] + ], + [ + [143.541, -8.35], + [143.59, -8.372], + [143.626, -8.412], + [143.648, -8.426], + [143.668, -8.428], + [143.679, -8.421], + [143.682, -8.413], + [143.676, -8.4], + [143.674, -8.391], + [143.669, -8.373], + [143.657, -8.355], + [143.638, -8.341], + [143.6, -8.333], + [143.551, -8.336], + [143.541, -8.35] + ], + [ + [143.783, -8.528], + [143.796, -8.538], + [143.813, -8.531], + [143.823, -8.51], + [143.822, -8.5], + [143.816, -8.495], + [143.81, -8.497], + [143.803, -8.501], + [143.792, -8.504], + [143.78, -8.513], + [143.783, -8.528] + ], + [ + [143.654, -8.104], + [143.641, -8.099], + [143.613, -8.095], + [143.599, -8.111], + [143.614, -8.139], + [143.634, -8.165], + [143.667, -8.167], + [143.688, -8.154], + [143.69, -8.137], + [143.68, -8.121], + [143.663, -8.109], + [143.654, -8.104] + ], + [ + [143.676, -8.093], + [143.69, -8.1], + [143.698, -8.091], + [143.686, -8.066], + [143.676, -8.054], + [143.656, -8.04], + [143.613, -8.02], + [143.578, -8.018], + [143.564, -8.03], + [143.574, -8.051], + [143.582, -8.069], + [143.607, -8.082], + [143.648, -8.085], + [143.676, -8.093] + ], + + [ + [142.255, -10.667], + [142.229, -10.62], + [142.212, -10.598], + [142.193, -10.591], + [142.182, -10.61], + [142.18, -10.615], + [142.177, -10.616], + [142.16, -10.626], + [142.152, -10.632], + [142.15, -10.636], + [142.146, -10.639], + [142.128, -10.641], + [142.124, -10.644], + [142.121, -10.648], + [142.118, -10.653], + [142.112, -10.684], + [142.122, -10.71], + [142.137, -10.731], + [142.146, -10.749], + [142.153, -10.756], + [142.187, -10.77], + [142.19, -10.758], + [142.197, -10.745], + [142.206, -10.733], + [142.218, -10.728], + [142.23, -10.726], + [142.253, -10.717], + [142.263, -10.716], + [142.273, -10.718], + [142.28, -10.719], + [142.283, -10.715], + [142.283, -10.701], + [142.279, -10.691], + [142.255, -10.667] + ], + [ + [142.254, -10.625], + [142.274, -10.641], + [142.303, -10.633], + [142.325, -10.612], + [142.319, -10.589], + [142.294, -10.573], + [142.262, -10.578], + [142.247, -10.6], + [142.254, -10.625] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/empty-square.json b/packages/melonjs/tests/earcut/fixtures/empty-square.json new file mode 100644 index 000000000..419bf2dac --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/empty-square.json @@ -0,0 +1,4 @@ +[ + [[0, 0], [4000, 0], [4000, 4000], [0, 4000]], + [[0, 0], [4000, 0], [4000, 4000], [0, 4000]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/filtered-bridge-jhl.json b/packages/melonjs/tests/earcut/fixtures/filtered-bridge-jhl.json new file mode 100644 index 000000000..de7a29bdf --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/filtered-bridge-jhl.json @@ -0,0 +1,14 @@ +[ + [ + [22.0, 14.0], + [17.0, 12.0], + [5.0, 12.0], + [0.0, 12.0], + [0.0, 0.0], + [22.0, 0.0] + ], + [[9.0, 4.0], [10.0, 4.0], [10.0, 3.0], [9.0, 3.0]], + [[6.0, 9.0], [7.0, 9.0], [7.0, 8.0], [6.0, 8.0]], + [[7.0, 10.0], [17.0, 10.0], [17.0, 5.0], [8.0, 5.0]], + [[13.0, 4.0], [14.0, 4.0], [14.0, 3.0], [13.0, 3.0]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/hilbert.json b/packages/melonjs/tests/earcut/fixtures/hilbert.json new file mode 100644 index 000000000..62033e0d3 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/hilbert.json @@ -0,0 +1,1031 @@ +[ + [ + [0, 0], + [-1, 0], + [-1, -1], + [0, -1], + [0, -2], + [0, -3], + [-1, -3], + [-1, -2], + [-2, -2], + [-2, -3], + [-3, -3], + [-3, -2], + [-3, -1], + [-2, -1], + [-2, 0], + [-3, 0], + [-4, 0], + [-4, -1], + [-5, -1], + [-5, 0], + [-6, 0], + [-7, 0], + [-7, -1], + [-6, -1], + [-6, -2], + [-7, -2], + [-7, -3], + [-6, -3], + [-5, -3], + [-5, -2], + [-4, -2], + [-4, -3], + [-4, -4], + [-4, -5], + [-5, -5], + [-5, -4], + [-6, -4], + [-7, -4], + [-7, -5], + [-6, -5], + [-6, -6], + [-7, -6], + [-7, -7], + [-6, -7], + [-5, -7], + [-5, -6], + [-4, -6], + [-4, -7], + [-3, -7], + [-2, -7], + [-2, -6], + [-3, -6], + [-3, -5], + [-3, -4], + [-2, -4], + [-2, -5], + [-1, -5], + [-1, -4], + [0, -4], + [0, -5], + [0, -6], + [-1, -6], + [-1, -7], + [0, -7], + [0, -8], + [0, -9], + [-1, -9], + [-1, -8], + [-2, -8], + [-3, -8], + [-3, -9], + [-2, -9], + [-2, -10], + [-3, -10], + [-3, -11], + [-2, -11], + [-1, -11], + [-1, -10], + [0, -10], + [0, -11], + [0, -12], + [-1, -12], + [-1, -13], + [0, -13], + [0, -14], + [0, -15], + [-1, -15], + [-1, -14], + [-2, -14], + [-2, -15], + [-3, -15], + [-3, -14], + [-3, -13], + [-2, -13], + [-2, -12], + [-3, -12], + [-4, -12], + [-5, -12], + [-5, -13], + [-4, -13], + [-4, -14], + [-4, -15], + [-5, -15], + [-5, -14], + [-6, -14], + [-6, -15], + [-7, -15], + [-7, -14], + [-7, -13], + [-6, -13], + [-6, -12], + [-7, -12], + [-7, -11], + [-7, -10], + [-6, -10], + [-6, -11], + [-5, -11], + [-4, -11], + [-4, -10], + [-5, -10], + [-5, -9], + [-4, -9], + [-4, -8], + [-5, -8], + [-6, -8], + [-6, -9], + [-7, -9], + [-7, -8], + [-8, -8], + [-8, -9], + [-9, -9], + [-9, -8], + [-10, -8], + [-11, -8], + [-11, -9], + [-10, -9], + [-10, -10], + [-11, -10], + [-11, -11], + [-10, -11], + [-9, -11], + [-9, -10], + [-8, -10], + [-8, -11], + [-8, -12], + [-9, -12], + [-9, -13], + [-8, -13], + [-8, -14], + [-8, -15], + [-9, -15], + [-9, -14], + [-10, -14], + [-10, -15], + [-11, -15], + [-11, -14], + [-11, -13], + [-10, -13], + [-10, -12], + [-11, -12], + [-12, -12], + [-13, -12], + [-13, -13], + [-12, -13], + [-12, -14], + [-12, -15], + [-13, -15], + [-13, -14], + [-14, -14], + [-14, -15], + [-15, -15], + [-15, -14], + [-15, -13], + [-14, -13], + [-14, -12], + [-15, -12], + [-15, -11], + [-15, -10], + [-14, -10], + [-14, -11], + [-13, -11], + [-12, -11], + [-12, -10], + [-13, -10], + [-13, -9], + [-12, -9], + [-12, -8], + [-13, -8], + [-14, -8], + [-14, -9], + [-15, -9], + [-15, -8], + [-15, -7], + [-14, -7], + [-14, -6], + [-15, -6], + [-15, -5], + [-15, -4], + [-14, -4], + [-14, -5], + [-13, -5], + [-13, -4], + [-12, -4], + [-12, -5], + [-12, -6], + [-13, -6], + [-13, -7], + [-12, -7], + [-11, -7], + [-11, -6], + [-10, -6], + [-10, -7], + [-9, -7], + [-8, -7], + [-8, -6], + [-9, -6], + [-9, -5], + [-8, -5], + [-8, -4], + [-9, -4], + [-10, -4], + [-10, -5], + [-11, -5], + [-11, -4], + [-11, -3], + [-11, -2], + [-10, -2], + [-10, -3], + [-9, -3], + [-8, -3], + [-8, -2], + [-9, -2], + [-9, -1], + [-8, -1], + [-8, 0], + [-9, 0], + [-10, 0], + [-10, -1], + [-11, -1], + [-11, 0], + [-12, 0], + [-13, 0], + [-13, -1], + [-12, -1], + [-12, -2], + [-12, -3], + [-13, -3], + [-13, -2], + [-14, -2], + [-14, -3], + [-15, -3], + [-15, -2], + [-15, -1], + [-14, -1], + [-14, 0], + [-15, 0], + [-16, 0], + [-16, -1], + [-17, -1], + [-17, 0], + [-18, 0], + [-19, 0], + [-19, -1], + [-18, -1], + [-18, -2], + [-19, -2], + [-19, -3], + [-18, -3], + [-17, -3], + [-17, -2], + [-16, -2], + [-16, -3], + [-16, -4], + [-17, -4], + [-17, -5], + [-16, -5], + [-16, -6], + [-16, -7], + [-17, -7], + [-17, -6], + [-18, -6], + [-18, -7], + [-19, -7], + [-19, -6], + [-19, -5], + [-18, -5], + [-18, -4], + [-19, -4], + [-20, -4], + [-21, -4], + [-21, -5], + [-20, -5], + [-20, -6], + [-20, -7], + [-21, -7], + [-21, -6], + [-22, -6], + [-22, -7], + [-23, -7], + [-23, -6], + [-23, -5], + [-22, -5], + [-22, -4], + [-23, -4], + [-23, -3], + [-23, -2], + [-22, -2], + [-22, -3], + [-21, -3], + [-20, -3], + [-20, -2], + [-21, -2], + [-21, -1], + [-20, -1], + [-20, 0], + [-21, 0], + [-22, 0], + [-22, -1], + [-23, -1], + [-23, 0], + [-24, 0], + [-25, 0], + [-25, -1], + [-24, -1], + [-24, -2], + [-24, -3], + [-25, -3], + [-25, -2], + [-26, -2], + [-26, -3], + [-27, -3], + [-27, -2], + [-27, -1], + [-26, -1], + [-26, 0], + [-27, 0], + [-28, 0], + [-28, -1], + [-29, -1], + [-29, 0], + [-30, 0], + [-31, 0], + [-31, -1], + [-30, -1], + [-30, -2], + [-31, -2], + [-31, -3], + [-30, -3], + [-29, -3], + [-29, -2], + [-28, -2], + [-28, -3], + [-28, -4], + [-28, -5], + [-29, -5], + [-29, -4], + [-30, -4], + [-31, -4], + [-31, -5], + [-30, -5], + [-30, -6], + [-31, -6], + [-31, -7], + [-30, -7], + [-29, -7], + [-29, -6], + [-28, -6], + [-28, -7], + [-27, -7], + [-26, -7], + [-26, -6], + [-27, -6], + [-27, -5], + [-27, -4], + [-26, -4], + [-26, -5], + [-25, -5], + [-25, -4], + [-24, -4], + [-24, -5], + [-24, -6], + [-25, -6], + [-25, -7], + [-24, -7], + [-24, -8], + [-25, -8], + [-25, -9], + [-24, -9], + [-24, -10], + [-24, -11], + [-25, -11], + [-25, -10], + [-26, -10], + [-26, -11], + [-27, -11], + [-27, -10], + [-27, -9], + [-26, -9], + [-26, -8], + [-27, -8], + [-28, -8], + [-28, -9], + [-29, -9], + [-29, -8], + [-30, -8], + [-31, -8], + [-31, -9], + [-30, -9], + [-30, -10], + [-31, -10], + [-31, -11], + [-30, -11], + [-29, -11], + [-29, -10], + [-28, -10], + [-28, -11], + [-28, -12], + [-28, -13], + [-29, -13], + [-29, -12], + [-30, -12], + [-31, -12], + [-31, -13], + [-30, -13], + [-30, -14], + [-31, -14], + [-31, -15], + [-30, -15], + [-29, -15], + [-29, -14], + [-28, -14], + [-28, -15], + [-27, -15], + [-26, -15], + [-26, -14], + [-27, -14], + [-27, -13], + [-27, -12], + [-26, -12], + [-26, -13], + [-25, -13], + [-25, -12], + [-24, -12], + [-24, -13], + [-24, -14], + [-25, -14], + [-25, -15], + [-24, -15], + [-23, -15], + [-23, -14], + [-22, -14], + [-22, -15], + [-21, -15], + [-20, -15], + [-20, -14], + [-21, -14], + [-21, -13], + [-20, -13], + [-20, -12], + [-21, -12], + [-22, -12], + [-22, -13], + [-23, -13], + [-23, -12], + [-23, -11], + [-22, -11], + [-22, -10], + [-23, -10], + [-23, -9], + [-23, -8], + [-22, -8], + [-22, -9], + [-21, -9], + [-21, -8], + [-20, -8], + [-20, -9], + [-20, -10], + [-21, -10], + [-21, -11], + [-20, -11], + [-19, -11], + [-18, -11], + [-18, -10], + [-19, -10], + [-19, -9], + [-19, -8], + [-18, -8], + [-18, -9], + [-17, -9], + [-17, -8], + [-16, -8], + [-16, -9], + [-16, -10], + [-17, -10], + [-17, -11], + [-16, -11], + [-16, -12], + [-16, -13], + [-17, -13], + [-17, -12], + [-18, -12], + [-19, -12], + [-19, -13], + [-18, -13], + [-18, -14], + [-19, -14], + [-19, -15], + [-18, -15], + [-17, -15], + [-17, -14], + [-16, -14], + [-16, -15], + [-16, -16], + [-16, -17], + [-17, -17], + [-17, -16], + [-18, -16], + [-19, -16], + [-19, -17], + [-18, -17], + [-18, -18], + [-19, -18], + [-19, -19], + [-18, -19], + [-17, -19], + [-17, -18], + [-16, -18], + [-16, -19], + [-16, -20], + [-17, -20], + [-17, -21], + [-16, -21], + [-16, -22], + [-16, -23], + [-17, -23], + [-17, -22], + [-18, -22], + [-18, -23], + [-19, -23], + [-19, -22], + [-19, -21], + [-18, -21], + [-18, -20], + [-19, -20], + [-20, -20], + [-21, -20], + [-21, -21], + [-20, -21], + [-20, -22], + [-20, -23], + [-21, -23], + [-21, -22], + [-22, -22], + [-22, -23], + [-23, -23], + [-23, -22], + [-23, -21], + [-22, -21], + [-22, -20], + [-23, -20], + [-23, -19], + [-23, -18], + [-22, -18], + [-22, -19], + [-21, -19], + [-20, -19], + [-20, -18], + [-21, -18], + [-21, -17], + [-20, -17], + [-20, -16], + [-21, -16], + [-22, -16], + [-22, -17], + [-23, -17], + [-23, -16], + [-24, -16], + [-25, -16], + [-25, -17], + [-24, -17], + [-24, -18], + [-24, -19], + [-25, -19], + [-25, -18], + [-26, -18], + [-26, -19], + [-27, -19], + [-27, -18], + [-27, -17], + [-26, -17], + [-26, -16], + [-27, -16], + [-28, -16], + [-28, -17], + [-29, -17], + [-29, -16], + [-30, -16], + [-31, -16], + [-31, -17], + [-30, -17], + [-30, -18], + [-31, -18], + [-31, -19], + [-30, -19], + [-29, -19], + [-29, -18], + [-28, -18], + [-28, -19], + [-28, -20], + [-28, -21], + [-29, -21], + [-29, -20], + [-30, -20], + [-31, -20], + [-31, -21], + [-30, -21], + [-30, -22], + [-31, -22], + [-31, -23], + [-30, -23], + [-29, -23], + [-29, -22], + [-28, -22], + [-28, -23], + [-27, -23], + [-26, -23], + [-26, -22], + [-27, -22], + [-27, -21], + [-27, -20], + [-26, -20], + [-26, -21], + [-25, -21], + [-25, -20], + [-24, -20], + [-24, -21], + [-24, -22], + [-25, -22], + [-25, -23], + [-24, -23], + [-24, -24], + [-25, -24], + [-25, -25], + [-24, -25], + [-24, -26], + [-24, -27], + [-25, -27], + [-25, -26], + [-26, -26], + [-26, -27], + [-27, -27], + [-27, -26], + [-27, -25], + [-26, -25], + [-26, -24], + [-27, -24], + [-28, -24], + [-28, -25], + [-29, -25], + [-29, -24], + [-30, -24], + [-31, -24], + [-31, -25], + [-30, -25], + [-30, -26], + [-31, -26], + [-31, -27], + [-30, -27], + [-29, -27], + [-29, -26], + [-28, -26], + [-28, -27], + [-28, -28], + [-28, -29], + [-29, -29], + [-29, -28], + [-30, -28], + [-31, -28], + [-31, -29], + [-30, -29], + [-30, -30], + [-31, -30], + [-31, -31], + [-30, -31], + [-29, -31], + [-29, -30], + [-28, -30], + [-28, -31], + [-27, -31], + [-26, -31], + [-26, -30], + [-27, -30], + [-27, -29], + [-27, -28], + [-26, -28], + [-26, -29], + [-25, -29], + [-25, -28], + [-24, -28], + [-24, -29], + [-24, -30], + [-25, -30], + [-25, -31], + [-24, -31], + [-23, -31], + [-23, -30], + [-22, -30], + [-22, -31], + [-21, -31], + [-20, -31], + [-20, -30], + [-21, -30], + [-21, -29], + [-20, -29], + [-20, -28], + [-21, -28], + [-22, -28], + [-22, -29], + [-23, -29], + [-23, -28], + [-23, -27], + [-22, -27], + [-22, -26], + [-23, -26], + [-23, -25], + [-23, -24], + [-22, -24], + [-22, -25], + [-21, -25], + [-21, -24], + [-20, -24], + [-20, -25], + [-20, -26], + [-21, -26], + [-21, -27], + [-20, -27], + [-19, -27], + [-18, -27], + [-18, -26], + [-19, -26], + [-19, -25], + [-19, -24], + [-18, -24], + [-18, -25], + [-17, -25], + [-17, -24], + [-16, -24], + [-16, -25], + [-16, -26], + [-17, -26], + [-17, -27], + [-16, -27], + [-16, -28], + [-16, -29], + [-17, -29], + [-17, -28], + [-18, -28], + [-19, -28], + [-19, -29], + [-18, -29], + [-18, -30], + [-19, -30], + [-19, -31], + [-18, -31], + [-17, -31], + [-17, -30], + [-16, -30], + [-16, -31], + [-15, -31], + [-14, -31], + [-14, -30], + [-15, -30], + [-15, -29], + [-15, -28], + [-14, -28], + [-14, -29], + [-13, -29], + [-13, -28], + [-12, -28], + [-12, -29], + [-12, -30], + [-13, -30], + [-13, -31], + [-12, -31], + [-11, -31], + [-11, -30], + [-10, -30], + [-10, -31], + [-9, -31], + [-8, -31], + [-8, -30], + [-9, -30], + [-9, -29], + [-8, -29], + [-8, -28], + [-9, -28], + [-10, -28], + [-10, -29], + [-11, -29], + [-11, -28], + [-11, -27], + [-11, -26], + [-10, -26], + [-10, -27], + [-9, -27], + [-8, -27], + [-8, -26], + [-9, -26], + [-9, -25], + [-8, -25], + [-8, -24], + [-9, -24], + [-10, -24], + [-10, -25], + [-11, -25], + [-11, -24], + [-12, -24], + [-13, -24], + [-13, -25], + [-12, -25], + [-12, -26], + [-12, -27], + [-13, -27], + [-13, -26], + [-14, -26], + [-14, -27], + [-15, -27], + [-15, -26], + [-15, -25], + [-14, -25], + [-14, -24], + [-15, -24], + [-15, -23], + [-15, -22], + [-14, -22], + [-14, -23], + [-13, -23], + [-12, -23], + [-12, -22], + [-13, -22], + [-13, -21], + [-12, -21], + [-12, -20], + [-13, -20], + [-14, -20], + [-14, -21], + [-15, -21], + [-15, -20], + [-15, -19], + [-14, -19], + [-14, -18], + [-15, -18], + [-15, -17], + [-15, -16], + [-14, -16], + [-14, -17], + [-13, -17], + [-13, -16], + [-12, -16], + [-12, -17], + [-12, -18], + [-13, -18], + [-13, -19], + [-12, -19], + [-11, -19], + [-10, -19], + [-10, -18], + [-11, -18], + [-11, -17], + [-11, -16], + [-10, -16], + [-10, -17], + [-9, -17], + [-9, -16], + [-8, -16], + [-8, -17], + [-8, -18], + [-9, -18], + [-9, -19], + [-8, -19], + [-8, -20], + [-8, -21], + [-9, -21], + [-9, -20], + [-10, -20], + [-11, -20], + [-11, -21], + [-10, -21], + [-10, -22], + [-11, -22], + [-11, -23], + [-10, -23], + [-9, -23], + [-9, -22], + [-8, -22], + [-8, -23], + [-7, -23], + [-7, -22], + [-6, -22], + [-6, -23], + [-5, -23], + [-4, -23], + [-4, -22], + [-5, -22], + [-5, -21], + [-4, -21], + [-4, -20], + [-5, -20], + [-6, -20], + [-6, -21], + [-7, -21], + [-7, -20], + [-7, -19], + [-6, -19], + [-6, -18], + [-7, -18], + [-7, -17], + [-7, -16], + [-6, -16], + [-6, -17], + [-5, -17], + [-5, -16], + [-4, -16], + [-4, -17], + [-4, -18], + [-5, -18], + [-5, -19], + [-4, -19], + [-3, -19], + [-2, -19], + [-2, -18], + [-3, -18], + [-3, -17], + [-3, -16], + [-2, -16], + [-2, -17], + [-1, -17], + [-1, -16], + [0, -16], + [0, -17], + [0, -18], + [-1, -18], + [-1, -19], + [0, -19], + [0, -20], + [0, -21], + [-1, -21], + [-1, -20], + [-2, -20], + [-3, -20], + [-3, -21], + [-2, -21], + [-2, -22], + [-3, -22], + [-3, -23], + [-2, -23], + [-1, -23], + [-1, -22], + [0, -22], + [0, -23], + [0, -24], + [-1, -24], + [-1, -25], + [0, -25], + [0, -26], + [0, -27], + [-1, -27], + [-1, -26], + [-2, -26], + [-2, -27], + [-3, -27], + [-3, -26], + [-3, -25], + [-2, -25], + [-2, -24], + [-3, -24], + [-4, -24], + [-4, -25], + [-5, -25], + [-5, -24], + [-6, -24], + [-7, -24], + [-7, -25], + [-6, -25], + [-6, -26], + [-7, -26], + [-7, -27], + [-6, -27], + [-5, -27], + [-5, -26], + [-4, -26], + [-4, -27], + [-4, -28], + [-4, -29], + [-5, -29], + [-5, -28], + [-6, -28], + [-7, -28], + [-7, -29], + [-6, -29], + [-6, -30], + [-7, -30], + [-7, -31], + [-6, -31], + [-5, -31], + [-5, -30], + [-4, -30], + [-4, -31], + [-3, -31], + [-2, -31], + [-2, -30], + [-3, -30], + [-3, -29], + [-3, -28], + [-2, -28], + [-2, -29], + [-1, -29], + [-1, -28], + [0, -28], + [0, -29], + [0, -30], + [-1, -30], + [-1, -31], + [0, -31], + [1, -31], + [1, 0], + [0, 0] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/hole-touching-outer.json b/packages/melonjs/tests/earcut/fixtures/hole-touching-outer.json new file mode 100644 index 000000000..1cf139757 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/hole-touching-outer.json @@ -0,0 +1,87 @@ +[ + [ + [-64, -64], + [253, -64], + [491, 358], + [697, 298], + [928, 197], + [929, 505], + [1346, 507], + [1347, 303], + [1771, 306], + [1770, 512], + [2191, 509], + [2198, 933], + [2621, 932], + [2623, 1115], + [2577, 1120], + [2494, 1183], + [2390, 1329], + [2326, 1590], + [2287, 1678], + [2286, 1407], + [2229, 1407], + [2182, 1493], + [2106, 1494], + [2068, 1460], + [2019, 1460], + [2016, 1775], + [1889, 1923], + [1953, 1989], + [2097, 1866], + [2198, 1925], + [2203, 1973], + [2311, 1976], + [2320, 1831], + [2352, 1824], + [2358, 1797], + [2378, 1780], + [3350, 1782], + [3307, 2086], + [3139, 2088], + [3143, 2203], + [3493, 2205], + [3543, 2187], + [3540, 2260], + [3661, 2264], + [3665, 1906], + [3630, 1902], + [3626, 1784], + [4160, 1786], + [4160, 2631], + [4076, 2631], + [4021, 2683], + [3930, 2701], + [3915, 2693], + [3898, 2639], + [2630, 2630], + [2635, 3476], + [2287, 3478], + [2118, 3203], + [2180, 3145], + [2327, 3087], + [2610, 2643], + [2613, 2536], + [2658, 2495], + [2650, 2203], + [1829, 2189], + [1732, 2241], + [1551, 2245], + [933, 1183], + [890, 1152], + [455, 401], + [398, 412], + [89, 547], + [-64, 606], + [-64, -64] + ], + [ + [1762, 928], + [1770, 512], + [1343, 513], + [1345, 715], + [931, 719], + [932, 930], + [1762, 928] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/hourglass.json b/packages/melonjs/tests/earcut/fixtures/hourglass.json new file mode 100644 index 000000000..36673770d --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/hourglass.json @@ -0,0 +1 @@ +[[[7, 18], [7, 15], [5, 15], [7, 13], [7, 15], [17, 17]]] diff --git a/packages/melonjs/tests/earcut/fixtures/infinite-loop-jhl.json b/packages/melonjs/tests/earcut/fixtures/infinite-loop-jhl.json new file mode 100644 index 000000000..49bd5cfa0 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/infinite-loop-jhl.json @@ -0,0 +1,4 @@ +[ + [[-1.0, 2.0], [0.0, 0.0], [2.0, -1.0]], + [[2.0, -1.0], [0.0, 1.0e-28], [-1.0, 2.0]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue107.json b/packages/melonjs/tests/earcut/fixtures/issue107.json new file mode 100644 index 000000000..66f6d0189 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue107.json @@ -0,0 +1,20 @@ +[ + [ + [7.943741826741378, 46.46223436733343], + [7.943741826741378, 46.43293749233343], + [7.943741826741378, 46.46223436733343] + ], + [ + [7.973038701741378, 46.46223436733343], + [8.002335576741377, 46.46223436733343], + [8.002335576741377, 46.43293749233343], + [8.031632451741377, 46.43293749233343], + [8.002335576741377, 46.43293749233343], + [8.002335576741377, 46.46223436733343], + [8.031632451741377, 46.46223436733343], + [8.031632451741377, 46.49153124233343], + [8.002335576741377, 46.49153124233343], + [8.002335576741377, 46.46223436733343], + [7.973038701741378, 46.46223436733343] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue111.json b/packages/melonjs/tests/earcut/fixtures/issue111.json new file mode 100644 index 000000000..0c4513d4e --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue111.json @@ -0,0 +1,21 @@ +[ + [ + [800, 4520], + [800, 4700], + [796, 4702], + [800, 4692], + [734, 4644], + [734, 4628], + [730, 4632], + [726, 4630], + [718, 4640], + [690, 4623], + [722, 4598], + [690, 4608], + [690, 4520], + [800, 4520] + ], + [[718, 4640], [716, 4630], [710, 4628], [718, 4640]], + [[734, 4610], [734, 4628], [740, 4622], [734, 4610]], + [[734, 4610], [745, 4600], [734, 4602], [734, 4610]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue119.json b/packages/melonjs/tests/earcut/fixtures/issue119.json new file mode 100644 index 000000000..292f1164d --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue119.json @@ -0,0 +1,7 @@ +[ + [[2, 12], [2, 20], [25, 20], [25, 12]], + [[7, 18], [7, 15], [5, 15]], + [[19, 18], [19, 17], [17, 17]], + [[19, 17], [21, 17], [19, 16]], + [[7, 15], [9, 15], [7, 13]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue131.json b/packages/melonjs/tests/earcut/fixtures/issue131.json new file mode 100644 index 000000000..451e3df87 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue131.json @@ -0,0 +1,12 @@ +[ + [[3506, -2048], [7464, 402], [-2048, 2685], [-2048, -2048], [3506, -2048]], + [ + [-2048, -37], + [1235, 747], + [338, -1464], + [-116, -1188], + [-2048, -381], + [-2048, -37] + ], + [[-1491, -1981], [-1300, -1800], [-1155, -1981], [-1491, -1981]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue142.json b/packages/melonjs/tests/earcut/fixtures/issue142.json new file mode 100644 index 000000000..7a97ab506 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue142.json @@ -0,0 +1,20 @@ +[ + [ + [5.62675358811389, 31.94879819160804], + [-16.369709114391867, 28.341954255099814], + [-10.786562672455382, -1.2779295357476745], + [10.819423740334923, 2.069348113719755] + ], + [ + [3.220439475288522, 4.197526331591453], + [5.024815373142793, 1.1716264034331543], + [10.819423740334923, 2.069348113719755], + [5.62675358811389, 31.94879819160804], + [-16.369709114391867, 28.341954255099814], + [-10.786562672455382, -1.2779295357476745], + [-6.833718161055838, -0.6655405509524673], + [-8.602352370111433, 2.142874784407777], + [-5.34630560403934, 6.768689248602321], + [-1.4053749889060216, 7.453573097663546] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue149.json b/packages/melonjs/tests/earcut/fixtures/issue149.json new file mode 100644 index 000000000..0a84e68e4 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue149.json @@ -0,0 +1,17 @@ +[ + [ + [1888, 5504], + [1872, 5504], + [1872, 5536], + [1856, 5536], + [1856, 5520], + [1840, 5520], + [1840, 5504], + [1856, 5504], + [1856, 5520], + [1872, 5520], + [1872, 5504], + [1888, 5504] + ], + [[1856, 5520], [1856, 5536], [1872, 5536], [1872, 5520]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue16.json b/packages/melonjs/tests/earcut/fixtures/issue16.json new file mode 100644 index 000000000..7e230c387 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue16.json @@ -0,0 +1,18 @@ +[ + [ + [143.129527283745121, 61.24016082659364], + [147.399527283763751, 74.780160826630892], + [154.049527283757931, 90.260160827077932], + [174.429527283762581, 81.710160826332872], + [168.03952728374861, 67.040160826407372], + [159.099527283746281, 53.590160826221112] + ], + [ + [156.85952728375561, 67.430160827003422], + [157.489527283760251, 67.160160826519132], + [159.969527283741631, 68.350160826928912], + [161.339527283766071, 67.640160826966172], + [159.649527283763751, 63.310160826891662], + [155.759527283749781, 64.880160826258362] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue17.json b/packages/melonjs/tests/earcut/fixtures/issue17.json new file mode 100644 index 000000000..066e4a7fd --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue17.json @@ -0,0 +1,17 @@ +[ + [ + [-20037508.34, 19971868.877628453], + [-20037508.34, -19971868.877628453], + [20037508.34, -19971868.877628453], + [20037508.34, 19971868.877628453] + ], + [ + [537637.6007702783, 5907542.234420554], + [539500.1483225027, 5905165.501947839], + [538610.3146341922, 5905217.430281373], + [538040.6306361248, 5906132.0755739985], + [538068.958329954, 5906571.138846622], + [537711.0379352621, 5906645.06648362], + [537629.886026485, 5907533.69114742] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue29.json b/packages/melonjs/tests/earcut/fixtures/issue29.json new file mode 100644 index 000000000..e449c3872 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue29.json @@ -0,0 +1,46 @@ +[ + [ + [200.95000055654114, 69.90565782485673], + [201.73186418809928, 76.50881049432792], + [204.05247248713854, 82.73234962527638], + [207.79442497901618, 88.23839184455574], + [212.7323883100471, 92.70045673093409], + [218.58296075442922, 95.86217257360113], + [225.00460918453172, 97.53918036725955], + [231.66534446463922, 97.66082593216561], + [238.15796607054654, 96.21973398409901], + [244.1176358256489, 93.27806596420706], + [249.2188404462824, 88.99822680730722], + [253.15628113771672, 83.64108043884043], + [255.70631344406866, 77.51111824424007], + [256.73126424155197, 70.93641692795792], + [256.19351709797047, 64.30797780468129], + [254.1057433114911, 57.996416078653425], + [250.56431880965246, 52.346517799043795], + [245.8112865351897, 47.719993951247304], + [240.07834375849924, 44.33761266223155], + [233.71343464441597, 42.419284673407674], + [227.06488359675492, 42.055728640102465], + [220.51757991796475, 43.257153422775446], + [214.45449861431845, 45.97523169373744], + [209.20995664413203, 50.053084840223896], + [205.06721924245355, 55.271000209450726], + [202.29122001552022, 61.30178454495035], + [201.02451470680535, 67.8368895214051] + ], + [ + [242.34999892718187, 69.90549289577612], + [240.7584948063828, 76.30057721128688], + [236.31611852571368, 81.17358751371503], + [230.07699953842675, 83.34595728587593], + [223.55761859836056, 82.33733346881347], + [218.2910646148026, 78.34856240227819], + [215.5668820463121, 72.34290095195175], + [215.9904494531453, 65.75019118711353], + [219.47497291108593, 60.1536534355022], + [225.2189893186092, 56.88651757836341], + [231.8100271829404, 56.72041164720431], + [237.70269737243652, 59.67713584899902], + [241.47838292121884, 65.0856644153595] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue34.json b/packages/melonjs/tests/earcut/fixtures/issue34.json new file mode 100644 index 000000000..ef9561b20 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue34.json @@ -0,0 +1,124 @@ +[ + [[1500, 0], [0, 0], [0, 1000], [1500, 1000], [1500, 0]], + [ + [804, 642], + [814, 644], + [818, 676], + [850, 690], + [838, 728], + [806, 728], + [772, 752], + [748, 746], + [764, 724], + [728, 726], + [710, 708], + [738, 656], + [764, 668], + [784, 700], + [806, 702], + [792, 666], + [804, 642] + ], + [ + [1176, 214], + [1254, 216], + [1292, 242], + [1324, 242], + [1332, 268], + [1352, 278], + [1352, 298], + [1290, 348], + [1290, 358], + [1312, 350], + [1314, 362], + [1266, 416], + [1240, 474], + [1182, 500], + [1200, 510], + [1200, 520], + [1186, 520], + [1200, 544], + [1186, 580], + [1160, 584], + [1162, 606], + [1146, 620], + [1162, 650], + [1136, 672], + [1124, 658], + [1076, 668], + [1022, 658], + [1036, 698], + [1066, 706], + [1118, 688], + [1144, 708], + [1132, 746], + [1064, 748], + [1004, 740], + [990, 668], + [966, 670], + [946, 648], + [948, 632], + [962, 628], + [992, 650], + [1016, 648], + [1054, 622], + [1044, 592], + [1054, 584], + [1078, 606], + [1076, 576], + [1052, 570], + [1056, 540], + [1038, 568], + [1004, 570], + [976, 526], + [996, 502], + [958, 496], + [948, 454], + [962, 454], + [952, 436], + [964, 390], + [986, 382], + [974, 368], + [1004, 376], + [1018, 420], + [1052, 434], + [1060, 482], + [1078, 490], + [1062, 472], + [1062, 442], + [1104, 450], + [1104, 436], + [1142, 422], + [1154, 402], + [1110, 424], + [1046, 416], + [1022, 388], + [1022, 344], + [1002, 344], + [1018, 318], + [1060, 308], + [1076, 272], + [1104, 288], + [1122, 246], + [1140, 230], + [1168, 234], + [1176, 214] + ], + [[974, 698], [986, 738], [964, 740], [952, 714], [974, 698]], + [[842, 596], [860, 626], [848, 622], [842, 596]], + [[798, 572], [792, 606], [768, 614], [740, 580], [758, 586], [798, 572]], + [[892, 584], [894, 594], [882, 588], [892, 584]], + [ + [870, 500], + [912, 538], + [922, 586], + [908, 590], + [894, 568], + [864, 564], + [854, 550], + [868, 538], + [846, 520], + [854, 500], + [870, 500] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue35.json b/packages/melonjs/tests/earcut/fixtures/issue35.json new file mode 100644 index 000000000..1ab766582 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue35.json @@ -0,0 +1,776 @@ +[ + [ + [216, -128], + [218, -98], + [232, -104], + [238, -98], + [234, -58], + [242, -32], + [232, -16], + [254, -2], + [256, 20], + [268, 6], + [274, 6], + [278, 20], + [284, 16], + [284, 6], + [266, -4], + [276, -28], + [262, -64], + [296, -68], + [312, -60], + [308, -50], + [322, -46], + [338, -46], + [344, -52], + [378, -50], + [396, -16], + [434, 22], + [446, 26], + [452, 38], + [470, 42], + [466, 58], + [450, 56], + [436, 68], + [428, 102], + [406, 96], + [408, 116], + [370, 114], + [340, 96], + [356, 124], + [358, 164], + [352, 174], + [328, 186], + [326, 208], + [342, 208], + [346, 232], + [328, 232], + [318, 248], + [306, 246], + [302, 236], + [284, 238], + [240, 190], + [218, 194], + [194, 176], + [184, 124], + [142, 102], + [134, 102], + [118, 118], + [72, 118], + [70, 90], + [52, 68], + [68, 42], + [68, 24], + [54, 40], + [36, 28], + [30, 46], + [12, 48], + [14, 82], + [30, 98], + [18, 150], + [-8, 170], + [-22, 190], + [-40, 194], + [-50, 204], + [-70, 208], + [-112, 198], + [-116, 212], + [-114, 230], + [-96, 250], + [-72, 244], + [-58, 276], + [-50, 332], + [-24, 364], + [-30, 384], + [-20, 390], + [-16, 410], + [-26, 426], + [-36, 428], + [-38, 444], + [-92, 422], + [-128, 422], + [-128, 4224], + [4224, 4224], + [4224, 3520], + [4204, 3506], + [4204, 3498], + [4212, 3498], + [4210, 3486], + [4164, 3492], + [4132, 3478], + [4104, 3474], + [4074, 3458], + [4034, 3456], + [3992, 3428], + [3928, 3362], + [3880, 3342], + [3870, 3342], + [3850, 3360], + [3814, 3374], + [3790, 3374], + [3768, 3362], + [3742, 3360], + [3706, 3344], + [3698, 3334], + [3656, 3326], + [3640, 3314], + [3592, 3298], + [3554, 3266], + [3534, 3266], + [3488, 3252], + [3464, 3224], + [3416, 3202], + [3384, 3154], + [3386, 3142], + [3398, 3140], + [3392, 3124], + [3400, 3116], + [3402, 3094], + [3392, 3088], + [3388, 3070], + [3394, 3062], + [3382, 3052], + [3378, 3038], + [3346, 3010], + [3316, 2966], + [3278, 2938], + [3278, 2926], + [3264, 2910], + [3212, 2880], + [3212, 2866], + [3220, 2858], + [3218, 2844], + [3208, 2834], + [3198, 2836], + [3184, 2814], + [3162, 2802], + [3158, 2776], + [3130, 2768], + [3090, 2720], + [3080, 2728], + [3070, 2724], + [3080, 2698], + [3044, 2628], + [3044, 2602], + [3024, 2596], + [3010, 2580], + [2992, 2584], + [2980, 2574], + [2966, 2580], + [2966, 2608], + [2972, 2614], + [2980, 2664], + [3022, 2700], + [3026, 2718], + [3056, 2746], + [3062, 2778], + [3080, 2792], + [3098, 2824], + [3112, 2832], + [3122, 2848], + [3130, 2884], + [3156, 2922], + [3156, 2954], + [3162, 2960], + [3176, 2954], + [3186, 2960], + [3202, 2988], + [3212, 2994], + [3212, 3010], + [3186, 3026], + [3170, 2992], + [3112, 2946], + [3102, 2944], + [3086, 2926], + [3090, 2882], + [3078, 2860], + [3062, 2854], + [3040, 2832], + [3018, 2832], + [3012, 2822], + [2986, 2812], + [2958, 2782], + [2960, 2776], + [2994, 2776], + [3000, 2742], + [2958, 2696], + [2928, 2680], + [2920, 2648], + [2910, 2638], + [2910, 2624], + [2900, 2616], + [2896, 2598], + [2882, 2582], + [2882, 2566], + [2862, 2538], + [2852, 2496], + [2828, 2472], + [2804, 2464], + [2796, 2448], + [2772, 2446], + [2754, 2428], + [2708, 2424], + [2702, 2418], + [2700, 2388], + [2644, 2322], + [2642, 2304], + [2648, 2292], + [2624, 2276], + [2616, 2234], + [2598, 2224], + [2590, 2202], + [2564, 2176], + [2556, 2120], + [2530, 2086], + [2542, 2054], + [2544, 2012], + [2530, 1976], + [2524, 1928], + [2542, 1870], + [2554, 1718], + [2546, 1710], + [2546, 1668], + [2540, 1664], + [2528, 1616], + [2518, 1606], + [2516, 1576], + [2524, 1574], + [2552, 1588], + [2612, 1594], + [2614, 1588], + [2606, 1580], + [2616, 1564], + [2616, 1552], + [2600, 1528], + [2586, 1528], + [2580, 1506], + [2552, 1498], + [2542, 1480], + [2534, 1480], + [2534, 1494], + [2512, 1456], + [2498, 1452], + [2498, 1470], + [2524, 1504], + [2552, 1514], + [2560, 1520], + [2564, 1536], + [2578, 1540], + [2578, 1572], + [2556, 1576], + [2498, 1550], + [2498, 1534], + [2474, 1532], + [2460, 1514], + [2434, 1502], + [2430, 1490], + [2418, 1486], + [2414, 1472], + [2402, 1468], + [2400, 1460], + [2374, 1452], + [2368, 1428], + [2350, 1414], + [2352, 1402], + [2380, 1396], + [2396, 1412], + [2418, 1420], + [2426, 1420], + [2430, 1410], + [2394, 1396], + [2378, 1380], + [2380, 1352], + [2364, 1356], + [2360, 1350], + [2360, 1340], + [2370, 1336], + [2370, 1328], + [2358, 1328], + [2356, 1312], + [2348, 1306], + [2350, 1290], + [2344, 1284], + [2332, 1288], + [2330, 1270], + [2318, 1278], + [2308, 1264], + [2314, 1246], + [2294, 1236], + [2306, 1220], + [2288, 1220], + [2278, 1228], + [2252, 1202], + [2258, 1180], + [2246, 1174], + [2246, 1164], + [2264, 1158], + [2254, 1140], + [2258, 1112], + [2232, 1102], + [2230, 1082], + [2222, 1070], + [2216, 1070], + [2220, 1096], + [2208, 1092], + [2202, 1072], + [2190, 1068], + [2196, 1032], + [2188, 1044], + [2172, 1048], + [2186, 1068], + [2182, 1110], + [2170, 1108], + [2168, 1096], + [2154, 1084], + [2144, 1090], + [2154, 1092], + [2154, 1106], + [2144, 1108], + [2130, 1086], + [2130, 1074], + [2106, 1048], + [2108, 1042], + [2122, 1040], + [2110, 1022], + [2120, 1022], + [2122, 1014], + [2102, 1012], + [2112, 996], + [2110, 980], + [2136, 980], + [2140, 966], + [2110, 970], + [2102, 964], + [2096, 992], + [2082, 992], + [2080, 976], + [2088, 966], + [2076, 950], + [2076, 934], + [2090, 930], + [2100, 938], + [2094, 916], + [2134, 922], + [2114, 906], + [2120, 892], + [2108, 872], + [2112, 858], + [2100, 842], + [2094, 840], + [2098, 896], + [2090, 898], + [2074, 920], + [2066, 920], + [2068, 880], + [2060, 868], + [2050, 814], + [2038, 820], + [2028, 808], + [2002, 802], + [1996, 812], + [1970, 818], + [1960, 806], + [1948, 804], + [1918, 776], + [1900, 748], + [1832, 708], + [1840, 692], + [1836, 674], + [1810, 690], + [1792, 690], + [1762, 678], + [1758, 662], + [1738, 666], + [1690, 654], + [1638, 662], + [1630, 652], + [1602, 640], + [1596, 624], + [1578, 632], + [1548, 616], + [1538, 630], + [1520, 638], + [1516, 622], + [1546, 612], + [1548, 604], + [1534, 596], + [1520, 598], + [1514, 570], + [1492, 580], + [1476, 574], + [1472, 582], + [1452, 590], + [1454, 570], + [1448, 570], + [1440, 592], + [1450, 594], + [1450, 608], + [1458, 614], + [1456, 632], + [1448, 642], + [1460, 654], + [1460, 664], + [1440, 658], + [1432, 668], + [1392, 664], + [1354, 706], + [1340, 710], + [1334, 722], + [1286, 738], + [1276, 730], + [1276, 720], + [1310, 696], + [1310, 690], + [1288, 694], + [1280, 686], + [1286, 660], + [1298, 646], + [1306, 622], + [1302, 596], + [1340, 568], + [1350, 568], + [1358, 578], + [1376, 572], + [1364, 548], + [1332, 546], + [1312, 566], + [1296, 570], + [1286, 580], + [1286, 594], + [1272, 602], + [1262, 614], + [1258, 634], + [1244, 644], + [1248, 660], + [1238, 674], + [1228, 676], + [1228, 688], + [1222, 694], + [1206, 694], + [1196, 712], + [1180, 722], + [1176, 744], + [1212, 754], + [1212, 774], + [1182, 798], + [1172, 828], + [1140, 838], + [1124, 860], + [1112, 862], + [1104, 876], + [1076, 892], + [1076, 912], + [1068, 924], + [1056, 926], + [1040, 940], + [1028, 940], + [1022, 956], + [1006, 956], + [1006, 966], + [984, 970], + [982, 978], + [990, 988], + [980, 1002], + [940, 1018], + [930, 1034], + [918, 1020], + [890, 1044], + [868, 1048], + [856, 1058], + [842, 1056], + [846, 1040], + [838, 1038], + [820, 1078], + [806, 1086], + [792, 1082], + [788, 1090], + [776, 1090], + [768, 1080], + [772, 1092], + [762, 1102], + [766, 1108], + [752, 1116], + [720, 1118], + [704, 1134], + [688, 1132], + [686, 1118], + [706, 1092], + [718, 1092], + [734, 1082], + [758, 1088], + [762, 1076], + [794, 1056], + [806, 1030], + [836, 1010], + [864, 1008], + [870, 1020], + [888, 1016], + [886, 1000], + [900, 974], + [952, 938], + [970, 936], + [976, 910], + [998, 894], + [1004, 882], + [1016, 878], + [1022, 800], + [1044, 774], + [1044, 766], + [1036, 766], + [990, 786], + [976, 762], + [970, 762], + [964, 776], + [968, 800], + [956, 804], + [928, 764], + [912, 770], + [898, 760], + [896, 750], + [888, 750], + [842, 786], + [826, 786], + [830, 744], + [820, 740], + [818, 730], + [830, 704], + [802, 646], + [794, 664], + [766, 678], + [724, 678], + [718, 660], + [702, 642], + [680, 630], + [676, 616], + [666, 614], + [682, 596], + [684, 580], + [674, 574], + [680, 564], + [674, 558], + [658, 562], + [652, 544], + [640, 534], + [644, 522], + [630, 518], + [630, 510], + [638, 506], + [634, 492], + [650, 488], + [650, 460], + [674, 424], + [688, 418], + [690, 382], + [706, 354], + [732, 350], + [756, 370], + [768, 370], + [794, 346], + [806, 322], + [818, 328], + [848, 328], + [868, 310], + [874, 286], + [866, 254], + [844, 230], + [844, 220], + [866, 216], + [872, 210], + [872, 194], + [854, 182], + [846, 194], + [814, 202], + [794, 220], + [788, 236], + [782, 236], + [778, 220], + [768, 210], + [768, 230], + [750, 216], + [710, 216], + [676, 228], + [634, 216], + [616, 204], + [618, 182], + [600, 160], + [614, 150], + [620, 136], + [570, 124], + [542, 104], + [542, 96], + [566, 86], + [570, 74], + [588, 72], + [620, 38], + [652, 44], + [644, 24], + [652, 16], + [684, 8], + [696, -4], + [716, -10], + [740, -4], + [732, 34], + [738, 48], + [828, 54], + [840, 30], + [860, 32], + [854, 18], + [824, 16], + [826, 2], + [846, 4], + [826, -20], + [826, -36], + [836, -54], + [820, -60], + [798, -52], + [748, -66], + [724, -128], + [216, -128] + ], + [[4124, 4134], [4118, 4136], [4120, 4130], [4126, 4130], [4124, 4134]], + [[4086, 4128], [4074, 4130], [4072, 4122], [4086, 4118], [4086, 4128]], + [[4068, 4106], [4068, 4112], [4060, 4112], [4060, 4104], [4068, 4106]], + [[1032, 4014], [1026, 4014], [1026, 4008], [1032, 4014]], + [ + [1122, 3162], + [1144, 3186], + [1142, 3198], + [1124, 3204], + [1108, 3218], + [1096, 3212], + [1090, 3176], + [1098, 3168], + [1098, 3156], + [1122, 3162] + ], + [ + [1088, 3124], + [1092, 3134], + [1074, 3138], + [1062, 3126], + [1064, 3118], + [1088, 3124] + ], + [[1054, 3114], [1038, 3114], [1038, 3108], [1050, 3108], [1054, 3114]], + [[1014, 3104], [994, 3102], [994, 3088], [1006, 3086], [1014, 3104]], + [ + [940, 3068], + [934, 3076], + [926, 3074], + [922, 3062], + [940, 3058], + [940, 3068] + ], + [ + [3042, 2702], + [3042, 2710], + [3034, 2710], + [3022, 2694], + [3030, 2690], + [3042, 2702] + ], + [ + [2598, 1566], + [2590, 1566], + [2588, 1558], + [2594, 1554], + [2600, 1554], + [2598, 1566] + ], + [ + [158, 1326], + [170, 1326], + [168, 1334], + [142, 1342], + [140, 1336], + [150, 1318], + [158, 1326] + ], + [[100, 1326], [98, 1340], [90, 1340], [84, 1322], [100, 1326]], + [[130, 1336], [120, 1338], [128, 1326], [130, 1336]], + [[-12, 1318], [-14, 1324], [-22, 1324], [-18, 1314], [-12, 1318]], + [[-112, 1318], [-116, 1320], [-110, 1312], [-112, 1318]], + [[182, 1314], [174, 1316], [174, 1310], [182, 1314]], + [ + [272, 1288], + [266, 1308], + [234, 1312], + [248, 1304], + [260, 1286], + [272, 1288] + ], + [[300, 1312], [278, 1308], [296, 1306], [300, 1312]], + [ + [2172, 1156], + [2180, 1162], + [2200, 1160], + [2188, 1196], + [2188, 1222], + [2200, 1232], + [2198, 1260], + [2208, 1264], + [2206, 1278], + [2226, 1294], + [2228, 1310], + [2208, 1298], + [2202, 1282], + [2160, 1236], + [2156, 1210], + [2142, 1202], + [2132, 1178], + [2136, 1152], + [2172, 1156] + ], + [[348, 1290], [346, 1296], [338, 1294], [342, 1288], [348, 1290]], + [[428, 1270], [420, 1272], [420, 1266], [428, 1270]], + [ + [610, 1170], + [626, 1168], + [626, 1186], + [616, 1192], + [604, 1206], + [588, 1208], + [568, 1222], + [552, 1214], + [536, 1222], + [518, 1244], + [506, 1246], + [512, 1224], + [526, 1220], + [532, 1202], + [546, 1198], + [554, 1212], + [580, 1206], + [590, 1188], + [586, 1172], + [596, 1164], + [608, 1164], + [610, 1170] + ], + [[648, 1152], [642, 1160], [632, 1158], [636, 1148], [648, 1152]], + [[2240, 1118], [2238, 1126], [2232, 1124], [2234, 1116], [2240, 1118]], + [[806, 1096], [802, 1090], [808, 1090], [806, 1096]], + [[908, 1080], [906, 1076], [914, 1072], [908, 1080]], + [[894, 1060], [884, 1072], [872, 1070], [876, 1054], [894, 1060]], + [ + [2024, 826], + [2052, 836], + [2048, 856], + [2056, 876], + [2054, 904], + [2066, 948], + [2062, 986], + [2052, 980], + [2044, 954], + [2030, 938], + [2028, 912], + [2020, 922], + [2010, 922], + [2012, 894], + [1976, 846], + [1976, 834], + [1988, 820], + [2016, 816], + [2024, 826] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue45.json b/packages/melonjs/tests/earcut/fixtures/issue45.json new file mode 100644 index 000000000..1f96a4227 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue45.json @@ -0,0 +1,5 @@ +[ + [[10, 10], [25, 10], [25, 40], [10, 40]], + [[15, 30], [20, 35], [10, 40]], + [[15, 15], [15, 20], [20, 15]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue52.json b/packages/melonjs/tests/earcut/fixtures/issue52.json new file mode 100644 index 000000000..43b1e05a6 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue52.json @@ -0,0 +1,106 @@ +[ + [ + [1920, 552], + [1904, 616], + [1912, 664], + [1984, 672], + [2008, 712], + [1944, 720], + [1904, 760], + [1896, 800], + [1856, 760], + [1824, 768], + [1824, 832], + [1864, 864], + [1888, 864], + [1904, 936], + [1936, 944], + [1936, 1064], + [1936, 1112], + [1872, 1136], + [1856, 1160], + [1840, 1144], + [1792, 1152], + [1784, 1112], + [1752, 1096], + [1608, 1096], + [1600, 1064], + [1640, 1040], + [1664, 992], + [1640, 968], + [1568, 1024], + [1560, 1056], + [1480, 1048], + [1440, 1072], + [1440, 1032], + [1400, 1032], + [1400, 1088], + [1336, 1136], + [1320, 1136], + [1264, 1072], + [1232, 1080], + [1240, 1104], + [1200, 1096], + [1232, 1048], + [1272, 1032], + [1272, 1000], + [1232, 1024], + [1176, 1024], + [1176, 1000], + [1248, 952], + [1344, 944], + [1352, 904], + [1424, 880], + [1448, 848], + [1496, 840], + [1512, 800], + [1568, 760], + [1616, 752], + [1640, 640], + [1680, 600], + [1736, 592], + [1776, 560], + [1776, 536], + [1840, 464], + [1848, 400], + [1888, 328], + [1952, 264], + [2000, 240], + [2040, 240], + [2040, 264], + [1968, 376], + [1912, 424], + [1936, 512], + [1920, 528], + [1880, 528], + [1872, 552], + [1920, 552] + ], + [ + [1608, 800], + [1576, 848], + [1520, 840], + [1512, 872], + [1456, 904], + [1440, 952], + [1528, 936], + [1552, 912], + [1584, 912], + [1608, 880], + [1664, 864], + [1680, 816], + [1656, 776], + [1608, 800] + ], + [[1720, 792], [1736, 792], [1720, 780], [1720, 792]], + [[1656, 728], [1670, 752], [1672, 728], [1656, 728]], + [ + [1712, 680], + [1696, 720], + [1720, 728], + [1736, 704], + [1736, 680], + [1712, 680] + ], + [[1968, 712], [2000, 712], [1968, 688], [1968, 712]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/issue83.json b/packages/melonjs/tests/earcut/fixtures/issue83.json new file mode 100644 index 000000000..0a7bdaba1 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/issue83.json @@ -0,0 +1,198 @@ +[ + [[0, 0], [4000, 0], [4000, 4000], [0, 4000]], + [[0, 0], [4000, 0], [4000, 4000], [0, 4000]], + [ + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1], + [-1, -1] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/outside-ring.json b/packages/melonjs/tests/earcut/fixtures/outside-ring.json new file mode 100644 index 000000000..3b915db53 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/outside-ring.json @@ -0,0 +1,67 @@ +[ + [ + [2181, 1228], + [2182, 1231], + [2178, 1231], + [2180, 1228], + [2175, 1225], + [2174, 1212], + [2182, 1210], + [2182, 1193], + [2190, 1187], + [2187, 1166], + [2194, 1158], + [2186, 1149], + [2186, 1103], + [2195, 1091], + [2207, 1092], + [2209, 1080], + [2203, 1077], + [2213, 1057], + [2213, 1035], + [2224, 1031], + [2238, 983], + [2251, 982], + [2254, 965], + [2275, 970], + [2277, 948], + [2317, 982], + [2317, 1030], + [2323, 1044], + [2306, 1041], + [2303, 1051], + [2290, 1057], + [2294, 1062], + [2287, 1071], + [2294, 1081], + [2255, 1123], + [2249, 1118], + [2253, 1128], + [2245, 1131], + [2249, 1137], + [2243, 1168], + [2265, 1195], + [2253, 1203], + [2260, 1204], + [2252, 1215], + [2249, 1208], + [2245, 1217], + [2232, 1220], + [2241, 1223], + [2235, 1223], + [2238, 1245], + [2229, 1274], + [2215, 1272], + [2209, 1288], + [2196, 1288], + [2190, 1269], + [2194, 1271], + [2195, 1262], + [2181, 1240], + [2182, 1233], + [2183, 1229], + [2181, 1228] + ], + [[2181, 1228], [2181, 1227], [2180, 1228], [2181, 1228]], + [[2246, 1197], [2230, 1201], [2251, 1203], [2246, 1197]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/rain.json b/packages/melonjs/tests/earcut/fixtures/rain.json new file mode 100644 index 000000000..7496c1ed8 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/rain.json @@ -0,0 +1,2699 @@ +[ + [ + [3755, 1974], + [3755, 1982], + [3746, 1982], + [3746, 2020], + [3755, 2020], + [3755, 2035], + [3773, 2042], + [3773, 2058], + [3837, 2058], + [3837, 2050], + [3827, 2050], + [3827, 2042], + [3873, 2042], + [3873, 2050], + [3882, 2050], + [3882, 2065], + [3891, 2065], + [3891, 2073], + [3900, 2073], + [3900, 2081], + [3909, 2081], + [3909, 2088], + [3928, 2088], + [3928, 2081], + [3937, 2081], + [3937, 2065], + [3955, 2058], + [3955, 2042], + [3964, 2042], + [3964, 2027], + [4028, 2020], + [4028, 2035], + [4010, 2042], + [4010, 2058], + [3991, 2058], + [3991, 2073], + [4000, 2073], + [4000, 2103], + [3991, 2103], + [3991, 2111], + [3973, 2111], + [3973, 2126], + [3964, 2126], + [3964, 2164], + [3955, 2164], + [3955, 2179], + [3946, 2179], + [3946, 2218], + [3937, 2218], + [3937, 2240], + [3919, 2248], + [3919, 2263], + [3909, 2263], + [3909, 2271], + [3891, 2271], + [3891, 2278], + [3736, 2278], + [3736, 2271], + [3727, 2271], + [3727, 2256], + [3718, 2256], + [3718, 2225], + [3700, 2218], + [3700, 2210], + [3682, 2210], + [3682, 2202], + [3664, 2202], + [3664, 2210], + [3645, 2202], + [3645, 2195], + [3655, 2195], + [3655, 2179], + [3664, 2179], + [3664, 2164], + [3655, 2164], + [3655, 2149], + [3636, 2149], + [3636, 2141], + [3609, 2141], + [3609, 2134], + [3600, 2134], + [3600, 2126], + [3591, 2126], + [3591, 2119], + [3582, 2119], + [3582, 2134], + [3573, 2134], + [3573, 2126], + [3554, 2119], + [3554, 2111], + [3536, 2119], + [3536, 2126], + [3545, 2126], + [3545, 2141], + [3527, 2149], + [3527, 2141], + [3518, 2141], + [3518, 2126], + [3509, 2126], + [3509, 2111], + [3500, 2111], + [3500, 2119], + [3482, 2119], + [3482, 2134], + [3500, 2141], + [3500, 2157], + [3482, 2157], + [3482, 2164], + [3472, 2164], + [3472, 2179], + [3463, 2179], + [3463, 2187], + [3482, 2195], + [3482, 2218], + [3500, 2225], + [3500, 2233], + [3518, 2233], + [3518, 2240], + [3527, 2240], + [3527, 2248], + [3536, 2248], + [3536, 2256], + [3545, 2256], + [3545, 2271], + [3536, 2271], + [3536, 2309], + [3509, 2309], + [3509, 2324], + [3472, 2324], + [3472, 2316], + [3482, 2316], + [3482, 2309], + [3472, 2309], + [3472, 2301], + [3463, 2301], + [3463, 2294], + [3445, 2294], + [3445, 2286], + [3436, 2286], + [3436, 2294], + [3454, 2301], + [3454, 2309], + [3427, 2309], + [3427, 2316], + [3354, 2309], + [3354, 2301], + [3345, 2301], + [3345, 2286], + [3336, 2286], + [3336, 2271], + [3327, 2271], + [3327, 2263], + [3318, 2263], + [3318, 2256], + [3309, 2256], + [3309, 2263], + [3290, 2263], + [3290, 2256], + [3300, 2256], + [3300, 2233], + [3290, 2233], + [3290, 2218], + [3281, 2218], + [3281, 2195], + [3272, 2195], + [3272, 2179], + [3263, 2179], + [3263, 2164], + [3245, 2157], + [3245, 2141], + [3227, 2134], + [3227, 2126], + [3190, 2119], + [3190, 2103], + [3172, 2103], + [3172, 2096], + [3118, 2096], + [3118, 2119], + [3127, 2119], + [3127, 2111], + [3163, 2111], + [3163, 2119], + [3181, 2119], + [3181, 2126], + [3190, 2126], + [3190, 2141], + [3199, 2141], + [3199, 2149], + [3190, 2149], + [3190, 2172], + [3199, 2172], + [3199, 2179], + [3190, 2179], + [3190, 2187], + [3199, 2187], + [3199, 2202], + [3218, 2202], + [3218, 2210], + [3236, 2210], + [3236, 2233], + [3227, 2233], + [3227, 2240], + [3245, 2240], + [3254, 2256], + [3263, 2256], + [3263, 2263], + [3272, 2263], + [3272, 2271], + [3290, 2278], + [3290, 2286], + [3300, 2286], + [3300, 2271], + [3309, 2271], + [3309, 2286], + [3318, 2286], + [3318, 2301], + [3309, 2301], + [3309, 2309], + [3318, 2309], + [3318, 2324], + [3327, 2324], + [3327, 2339], + [3309, 2347], + [3309, 2362], + [3318, 2362], + [3318, 2385], + [3327, 2385], + [3327, 2392], + [3345, 2392], + [3345, 2400], + [3372, 2400], + [3372, 2408], + [3381, 2408], + [3381, 2415], + [3409, 2415], + [3409, 2423], + [3418, 2423], + [3418, 2430], + [3463, 2430], + [3463, 2438], + [3482, 2438], + [3482, 2446], + [3491, 2446], + [3491, 2453], + [3509, 2453], + [3509, 2461], + [3454, 2461], + [3454, 2453], + [3436, 2453], + [3436, 2446], + [3427, 2446], + [3427, 2438], + [3409, 2438], + [3409, 2430], + [3400, 2430], + [3400, 2423], + [3336, 2423], + [3336, 2461], + [3436, 2468], + [3436, 2476], + [3454, 2476], + [3454, 2468], + [3463, 2468], + [3463, 2476], + [3472, 2476], + [3472, 2484], + [3436, 2484], + [3436, 2499], + [3427, 2499], + [3427, 2514], + [3418, 2514], + [3418, 2507], + [3381, 2507], + [3381, 2514], + [3354, 2514], + [3354, 2507], + [3345, 2507], + [3345, 2499], + [3272, 2499], + [3272, 2491], + [3254, 2491], + [3254, 2484], + [3263, 2484], + [3254, 2468], + [3227, 2468], + [3227, 2484], + [3245, 2491], + [3245, 2507], + [3218, 2507], + [3218, 2499], + [3181, 2499], + [3181, 2491], + [3163, 2491], + [3163, 2484], + [3118, 2484], + [3118, 2476], + [3072, 2476], + [3072, 2468], + [3054, 2461], + [3054, 2453], + [3045, 2453], + [3045, 2446], + [3026, 2446], + [3017, 2430], + [2999, 2423], + [2999, 2377], + [2990, 2377], + [2990, 2370], + [2999, 2370], + [2999, 2339], + [3017, 2332], + [3017, 2316], + [3036, 2309], + [3036, 2271], + [3026, 2271], + [3026, 2240], + [3036, 2240], + [3036, 2248], + [3054, 2248], + [3054, 2271], + [3090, 2263], + [3090, 2256], + [3099, 2256], + [3099, 2218], + [3127, 2218], + [3127, 2210], + [3118, 2210], + [3118, 2202], + [3127, 2202], + [3127, 2195], + [3108, 2195], + [3108, 2179], + [3081, 2179], + [3081, 2187], + [3072, 2187], + [3072, 2195], + [3063, 2195], + [3063, 2202], + [3036, 2202], + [3036, 2225], + [2999, 2225], + [2999, 2218], + [2981, 2218], + [2981, 2210], + [2917, 2210], + [2917, 2195], + [2899, 2187], + [2899, 2179], + [2926, 2179], + [2926, 2172], + [2917, 2172], + [2917, 2164], + [2890, 2164], + [2890, 2187], + [2881, 2187], + [2881, 2195], + [2863, 2195], + [2863, 2187], + [2844, 2187], + [2844, 2179], + [2826, 2172], + [2826, 2164], + [2808, 2157], + [2808, 2149], + [2799, 2149], + [2799, 2141], + [2781, 2134], + [2781, 2119], + [2763, 2111], + [2763, 2096], + [2753, 2096], + [2753, 2088], + [2744, 2088], + [2744, 2081], + [2726, 2081], + [2726, 2111], + [2735, 2111], + [2735, 2126], + [2744, 2126], + [2744, 2157], + [2753, 2157], + [2753, 2172], + [2763, 2172], + [2763, 2179], + [2772, 2179], + [2772, 2187], + [2781, 2187], + [2781, 2195], + [2790, 2195], + [2790, 2218], + [2781, 2218], + [2781, 2233], + [2772, 2233], + [2772, 2240], + [2753, 2240], + [2753, 2233], + [2744, 2233], + [2744, 2225], + [2726, 2225], + [2726, 2218], + [2708, 2218], + [2708, 2210], + [2690, 2210], + [2690, 2202], + [2672, 2195], + [2672, 2187], + [2662, 2187], + [2662, 2179], + [2644, 2179], + [2644, 2172], + [2635, 2172], + [2635, 2164], + [2626, 2164], + [2626, 2149], + [2617, 2149], + [2617, 2134], + [2608, 2134], + [2608, 2126], + [2599, 2126], + [2599, 2119], + [2590, 2119], + [2590, 2134], + [2580, 2134], + [2580, 2141], + [2590, 2141], + [2590, 2179], + [2599, 2179], + [2599, 2195], + [2617, 2202], + [2617, 2218], + [2626, 2218], + [2626, 2233], + [2635, 2233], + [2635, 2263], + [2653, 2263], + [2653, 2271], + [2681, 2271], + [2681, 2278], + [2690, 2278], + [2690, 2286], + [2699, 2286], + [2699, 2294], + [2708, 2294], + [2708, 2309], + [2735, 2309], + [2735, 2294], + [2753, 2286], + [2753, 2278], + [2763, 2278], + [2763, 2263], + [2799, 2263], + [2799, 2271], + [2817, 2278], + [2817, 2294], + [2826, 2294], + [2826, 2301], + [2817, 2301], + [2817, 2392], + [2799, 2400], + [2799, 2392], + [2772, 2392], + [2772, 2385], + [2763, 2385], + [2763, 2377], + [2726, 2377], + [2726, 2385], + [2717, 2385], + [2717, 2415], + [2708, 2415], + [2708, 2423], + [2717, 2423], + [2717, 2438], + [2726, 2438], + [2726, 2453], + [2735, 2453], + [2735, 2484], + [2744, 2484], + [2744, 2507], + [2753, 2507], + [2753, 2567], + [2763, 2567], + [2772, 2583], + [2817, 2583], + [2817, 2590], + [2826, 2590], + [2826, 2621], + [2808, 2628], + [2808, 2658], + [2817, 2658], + [2817, 2674], + [2808, 2674], + [2808, 2689], + [2790, 2689], + [2790, 2681], + [2772, 2681], + [2772, 2674], + [2726, 2674], + [2726, 2658], + [2708, 2651], + [2708, 2636], + [2699, 2636], + [2699, 2613], + [2690, 2613], + [2690, 2598], + [2672, 2598], + [2672, 2590], + [2662, 2590], + [2662, 2598], + [2644, 2598], + [2644, 2590], + [2635, 2590], + [2635, 2583], + [2580, 2583], + [2580, 2575], + [2553, 2575], + [2553, 2567], + [2535, 2567], + [2535, 2575], + [2526, 2575], + [2526, 2583], + [2508, 2590], + [2508, 2598], + [2489, 2605], + [2489, 2621], + [2480, 2621], + [2480, 2628], + [2462, 2628], + [2462, 2636], + [2444, 2636], + [2444, 2628], + [2371, 2628], + [2371, 2621], + [2353, 2621], + [2353, 2628], + [2344, 2628], + [2344, 2621], + [2298, 2621], + [2289, 2605], + [2271, 2598], + [2271, 2575], + [2262, 2575], + [2262, 2567], + [2244, 2560], + [2244, 2552], + [2235, 2552], + [2235, 2545], + [2216, 2545], + [2216, 2537], + [2198, 2537], + [2198, 2529], + [2189, 2529], + [2189, 2522], + [2171, 2522], + [2171, 2507], + [2162, 2507], + [2162, 2499], + [2153, 2499], + [2153, 2491], + [2144, 2491], + [2144, 2484], + [2134, 2484], + [2134, 2476], + [2125, 2476], + [2125, 2468], + [2107, 2461], + [2107, 2453], + [2098, 2453], + [2098, 2461], + [2089, 2461], + [2089, 2468], + [2071, 2468], + [2071, 2484], + [2062, 2484], + [2062, 2491], + [2053, 2491], + [2053, 2499], + [2043, 2499], + [2043, 2507], + [2025, 2514], + [2025, 2529], + [2016, 2529], + [2016, 2552], + [2007, 2552], + [2007, 2567], + [1998, 2567], + [1998, 2590], + [1989, 2590], + [1989, 2605], + [1980, 2605], + [1980, 2621], + [1962, 2628], + [1962, 2636], + [1952, 2636], + [1952, 2651], + [1943, 2651], + [1943, 2666], + [1925, 2666], + [1925, 2674], + [1916, 2674], + [1916, 2666], + [1880, 2658], + [1880, 2674], + [1871, 2674], + [1871, 2696], + [1861, 2696], + [1861, 2712], + [1852, 2712], + [1852, 2727], + [1843, 2727], + [1843, 2734], + [1816, 2734], + [1816, 2742], + [1807, 2742], + [1807, 2765], + [1798, 2765], + [1798, 2757], + [1789, 2757], + [1789, 2750], + [1779, 2750], + [1779, 2742], + [1725, 2742], + [1725, 2757], + [1698, 2757], + [1698, 2788], + [1688, 2788], + [1688, 2803], + [1679, 2803], + [1679, 2810], + [1652, 2810], + [1652, 2818], + [1634, 2818], + [1634, 2826], + [1607, 2826], + [1607, 2833], + [1597, 2833], + [1597, 2841], + [1588, 2841], + [1588, 2864], + [1579, 2864], + [1579, 2879], + [1534, 2879], + [1534, 2871], + [1525, 2871], + [1525, 2886], + [1516, 2886], + [1516, 2879], + [1488, 2879], + [1488, 2871], + [1470, 2871], + [1470, 2864], + [1452, 2864], + [1452, 2856], + [1434, 2856], + [1434, 2848], + [1379, 2848], + [1379, 2841], + [1370, 2841], + [1370, 2833], + [1352, 2826], + [1352, 2818], + [1343, 2818], + [1343, 2803], + [1370, 2803], + [1370, 2795], + [1379, 2795], + [1379, 2772], + [1361, 2765], + [1361, 2757], + [1343, 2757], + [1343, 2750], + [1261, 2750], + [1261, 2742], + [1224, 2742], + [1224, 2734], + [1215, 2734], + [1215, 2750], + [1197, 2750], + [1197, 2757], + [1188, 2757], + [1188, 2765], + [1179, 2765], + [1179, 2772], + [1161, 2772], + [1161, 2780], + [1142, 2780], + [1142, 2772], + [1133, 2772], + [1133, 2780], + [1115, 2780], + [1115, 2772], + [1088, 2772], + [1088, 2765], + [1070, 2765], + [1070, 2757], + [1060, 2757], + [1060, 2750], + [1051, 2750], + [1051, 2742], + [1042, 2742], + [1042, 2734], + [1024, 2734], + [1015, 2750], + [997, 2750], + [997, 2742], + [978, 2742], + [978, 2719], + [969, 2719], + [969, 2712], + [933, 2712], + [933, 2719], + [942, 2719], + [942, 2727], + [951, 2727], + [951, 2734], + [915, 2734], + [915, 2742], + [887, 2742], + [887, 2772], + [878, 2772], + [878, 2788], + [860, 2788], + [860, 2795], + [833, 2795], + [833, 2803], + [815, 2810], + [815, 2826], + [806, 2826], + [806, 2856], + [787, 2864], + [787, 2879], + [778, 2879], + [778, 2894], + [769, 2894], + [769, 2909], + [760, 2909], + [760, 2917], + [751, 2917], + [751, 2924], + [733, 2924], + [733, 2932], + [724, 2932], + [724, 2947], + [715, 2947], + [715, 2977], + [724, 2977], + [724, 2985], + [715, 2985], + [715, 2993], + [724, 2993], + [724, 3038], + [715, 3038], + [715, 3053], + [724, 3053], + [724, 3061], + [715, 3061], + [715, 3091], + [705, 3091], + [705, 3114], + [715, 3114], + [715, 3129], + [733, 3137], + [733, 3144], + [724, 3144], + [724, 3152], + [733, 3152], + [733, 3159], + [724, 3159], + [724, 3190], + [733, 3190], + [733, 3205], + [742, 3205], + [742, 3220], + [760, 3220], + [760, 3228], + [787, 3228], + [787, 3235], + [796, 3235], + [796, 3250], + [806, 3250], + [806, 3266], + [815, 3266], + [815, 3334], + [824, 3334], + [824, 3349], + [833, 3349], + [833, 3364], + [824, 3364], + [824, 3394], + [842, 3394], + [842, 3402], + [851, 3402], + [851, 3410], + [860, 3410], + [860, 3417], + [887, 3417], + [887, 3425], + [915, 3425], + [915, 3417], + [924, 3417], + [924, 3425], + [942, 3425], + [942, 3417], + [969, 3417], + [969, 3410], + [978, 3410], + [978, 3425], + [988, 3425], + [988, 3440], + [1015, 3440], + [1015, 3447], + [1024, 3447], + [1024, 3463], + [1042, 3470], + [1042, 3478], + [1060, 3485], + [1060, 3493], + [1070, 3493], + [1070, 3500], + [1079, 3500], + [1079, 3516], + [1088, 3516], + [1088, 3523], + [1097, 3523], + [1097, 3531], + [1106, 3531], + [1106, 3546], + [1115, 3546], + [1115, 3554], + [1124, 3554], + [1124, 3569], + [1133, 3569], + [1133, 3599], + [1142, 3599], + [1142, 3637], + [1133, 3637], + [1133, 3660], + [1124, 3660], + [1124, 3675], + [1106, 3682], + [1106, 3720], + [1115, 3720], + [1115, 3750], + [1124, 3750], + [1124, 3811], + [1115, 3811], + [1115, 3841], + [1133, 3841], + [1133, 3849], + [1151, 3849], + [1151, 3856], + [1170, 3849], + [1170, 3834], + [1161, 3834], + [1161, 3826], + [1179, 3826], + [1179, 3796], + [1197, 3796], + [1197, 3788], + [1188, 3788], + [1188, 3765], + [1161, 3765], + [1161, 3750], + [1170, 3750], + [1170, 3743], + [1197, 3743], + [1197, 3750], + [1206, 3750], + [1206, 3758], + [1224, 3758], + [1224, 3743], + [1233, 3743], + [1233, 3728], + [1252, 3728], + [1252, 3705], + [1261, 3705], + [1261, 3682], + [1270, 3682], + [1270, 3667], + [1279, 3667], + [1279, 3652], + [1297, 3652], + [1297, 3614], + [1306, 3614], + [1306, 3599], + [1315, 3599], + [1315, 3591], + [1306, 3591], + [1306, 3584], + [1333, 3584], + [1333, 3576], + [1343, 3576], + [1343, 3569], + [1361, 3569], + [1361, 3561], + [1388, 3561], + [1388, 3554], + [1397, 3554], + [1397, 3546], + [1406, 3546], + [1406, 3538], + [1424, 3531], + [1424, 3516], + [1434, 3516], + [1434, 3485], + [1443, 3485], + [1443, 3478], + [1461, 3478], + [1461, 3470], + [1488, 3470], + [1488, 3478], + [1497, 3478], + [1497, 3463], + [1516, 3463], + [1516, 3455], + [1525, 3455], + [1525, 3463], + [1543, 3463], + [1543, 3478], + [1525, 3470], + [1525, 3493], + [1552, 3493], + [1552, 3516], + [1543, 3516], + [1543, 3546], + [1552, 3546], + [1552, 3561], + [1561, 3561], + [1561, 3591], + [1525, 3591], + [1525, 3607], + [1534, 3607], + [1534, 3614], + [1525, 3614], + [1525, 3629], + [1516, 3629], + [1516, 3637], + [1488, 3637], + [1488, 3629], + [1479, 3629], + [1479, 3697], + [1488, 3697], + [1488, 3712], + [1497, 3712], + [1497, 3758], + [1488, 3758], + [1488, 3765], + [1479, 3765], + [1479, 3773], + [1470, 3773], + [1470, 3818], + [1461, 3818], + [1461, 3856], + [1452, 3856], + [1452, 3864], + [1434, 3864], + [1434, 3879], + [1379, 3879], + [1379, 3871], + [1361, 3871], + [1361, 3879], + [1343, 3879], + [1343, 3887], + [1306, 3887], + [1306, 3894], + [1297, 3894], + [1297, 3902], + [1288, 3902], + [1288, 3909], + [1270, 3909], + [1270, 3924], + [1261, 3924], + [1261, 3962], + [1252, 3962], + [1252, 3985], + [1242, 3985], + [1242, 3992], + [1224, 3992], + [1215, 4008], + [1197, 4015], + [1197, 4023], + [1179, 4030], + [1179, 4038], + [1170, 4038], + [1170, 4053], + [1179, 4053], + [1179, 4045], + [1206, 4045], + [1206, 4038], + [1224, 4038], + [1224, 4030], + [1242, 4030], + [1242, 4023], + [1252, 4023], + [1252, 4045], + [1233, 4045], + [1233, 4053], + [1224, 4053], + [1224, 4076], + [1206, 4083], + [1206, 4098], + [1197, 4098], + [1197, 4116], + [771, 4116], + [778, 4113], + [778, 4106], + [769, 4106], + [769, 4068], + [787, 4076], + [796, 4060], + [815, 4060], + [815, 4045], + [833, 4045], + [833, 4038], + [824, 4038], + [824, 4030], + [815, 4030], + [815, 4015], + [806, 4015], + [806, 4008], + [824, 4008], + [824, 3992], + [815, 3992], + [815, 4000], + [806, 4000], + [806, 3985], + [796, 3985], + [796, 4015], + [787, 4015], + [787, 4023], + [778, 4023], + [778, 4015], + [751, 4015], + [751, 4008], + [760, 4008], + [760, 3992], + [769, 3992], + [769, 3985], + [760, 3985], + [760, 3977], + [733, 3977], + [733, 3970], + [715, 3970], + [715, 3962], + [705, 3962], + [705, 3955], + [687, 3955], + [687, 3947], + [660, 3947], + [660, 3939], + [624, 3939], + [624, 3932], + [605, 3932], + [605, 3939], + [587, 3939], + [578, 3955], + [569, 3955], + [569, 3970], + [587, 3970], + [587, 3985], + [569, 3992], + [569, 4000], + [578, 4000], + [578, 3992], + [587, 3992], + [587, 4000], + [605, 4000], + [605, 4030], + [614, 4030], + [614, 4015], + [633, 4015], + [633, 4023], + [660, 4023], + [660, 4030], + [651, 4030], + [651, 4038], + [660, 4038], + [660, 4045], + [669, 4045], + [669, 4023], + [687, 4030], + [687, 4045], + [705, 4038], + [705, 4030], + [733, 4030], + [733, 4038], + [724, 4038], + [724, 4060], + [733, 4060], + [733, 4045], + [742, 4045], + [742, 4060], + [751, 4060], + [751, 4083], + [742, 4083], + [742, 4091], + [760, 4098], + [760, 4116], + [742, 4116], + [742, 4113], + [724, 4106], + [724, 4098], + [705, 4098], + [705, 4091], + [696, 4091], + [696, 4076], + [669, 4076], + [669, 4091], + [660, 4091], + [660, 4083], + [651, 4083], + [651, 4068], + [633, 4068], + [633, 4060], + [624, 4060], + [624, 4053], + [596, 4053], + [596, 4045], + [578, 4045], + [578, 4038], + [542, 4038], + [542, 4045], + [551, 4045], + [551, 4053], + [532, 4053], + [532, 4045], + [523, 4045], + [523, 4038], + [532, 4038], + [532, 4023], + [514, 4023], + [514, 4038], + [505, 4038], + [505, 4030], + [496, 4030], + [496, 4023], + [505, 4023], + [505, 4015], + [469, 4015], + [469, 4000], + [460, 4000], + [460, 4015], + [441, 4015], + [441, 4008], + [414, 4008], + [414, 4000], + [432, 4000], + [432, 3985], + [414, 3977], + [414, 3955], + [405, 3955], + [405, 3939], + [396, 3939], + [396, 3932], + [387, 3932], + [387, 3924], + [378, 3924], + [378, 3909], + [369, 3909], + [369, 3894], + [360, 3894], + [360, 3864], + [341, 3856], + [341, 3818], + [332, 3818], + [332, 3796], + [314, 3788], + [314, 3765], + [278, 3773], + [278, 3765], + [232, 3765], + [232, 3758], + [223, 3758], + [223, 3765], + [214, 3765], + [214, 3773], + [205, 3773], + [205, 3781], + [177, 3781], + [177, 3773], + [168, 3773], + [168, 3758], + [159, 3758], + [159, 3750], + [150, 3750], + [150, 3743], + [141, 3743], + [141, 3735], + [132, 3735], + [132, 3720], + [77, 3720], + [77, 3728], + [59, 3728], + [59, 3750], + [5, 3750], + [5, 3743], + [-5, 3743], + [-5, 3750], + [-20, 3750], + [-20, 3538], + [-14, 3538], + [-14, 3523], + [5, 3523], + [5, 3516], + [14, 3516], + [14, 3500], + [23, 3500], + [23, 3508], + [50, 3508], + [50, 3523], + [41, 3523], + [41, 3531], + [23, 3531], + [23, 3546], + [32, 3546], + [32, 3569], + [41, 3569], + [41, 3576], + [86, 3576], + [86, 3584], + [105, 3584], + [105, 3599], + [114, 3599], + [114, 3607], + [132, 3607], + [132, 3591], + [141, 3591], + [141, 3569], + [150, 3569], + [150, 3561], + [168, 3554], + [168, 3531], + [159, 3531], + [159, 3508], + [141, 3508], + [141, 3516], + [132, 3516], + [132, 3493], + [123, 3493], + [123, 3463], + [132, 3463], + [132, 3432], + [123, 3432], + [123, 3357], + [141, 3357], + [141, 3341], + [159, 3341], + [159, 3326], + [150, 3326], + [150, 3311], + [159, 3311], + [159, 3296], + [168, 3296], + [168, 3288], + [141, 3288], + [141, 3281], + [132, 3281], + [132, 3266], + [96, 3258], + [96, 3235], + [68, 3235], + [68, 3243], + [59, 3243], + [59, 3258], + [50, 3258], + [50, 3266], + [23, 3266], + [23, 3258], + [32, 3258], + [32, 3228], + [23, 3228], + [23, 3220], + [32, 3220], + [32, 3205], + [68, 3197], + [68, 3190], + [59, 3190], + [59, 3175], + [50, 3175], + [50, 3152], + [41, 3152], + [41, 3137], + [32, 3137], + [32, 3106], + [41, 3106], + [41, 3099], + [68, 3099], + [68, 3106], + [123, 3106], + [123, 3091], + [105, 3091], + [105, 3076], + [96, 3076], + [96, 3068], + [114, 3068], + [114, 3061], + [105, 3061], + [105, 3053], + [159, 3046], + [159, 3053], + [150, 3053], + [150, 3076], + [187, 3076], + [187, 3053], + [196, 3053], + [196, 3046], + [232, 3046], + [232, 3023], + [205, 3023], + [205, 3008], + [196, 3008], + [196, 2993], + [187, 2993], + [187, 3023], + [177, 3023], + [177, 3038], + [150, 3038], + [150, 3023], + [123, 3023], + [123, 3008], + [114, 3008], + [114, 2977], + [96, 2970], + [96, 2962], + [86, 2962], + [86, 2955], + [14, 2955], + [14, 2962], + [5, 2962], + [5, 2977], + [-5, 2977], + [-5, 2985], + [-20, 2985], + [-20, 2947], + [-5, 2947], + [-5, 2939], + [32, 2932], + [32, 2924], + [41, 2924], + [41, 2917], + [59, 2917], + [59, 2909], + [14, 2909], + [14, 2894], + [-20, 2894], + [-20, 2119], + [14, 2119], + [14, 2126], + [23, 2126], + [23, 2134], + [32, 2134], + [32, 2126], + [41, 2126], + [41, 2096], + [32, 2096], + [32, 2088], + [23, 2088], + [23, 2081], + [5, 2081], + [5, 2073], + [-14, 2073], + [-14, 2042], + [-5, 2042], + [-5, 2020], + [5, 2020], + [14, 2004], + [41, 2004], + [41, 1997], + [86, 1997], + [86, 2004], + [105, 2004], + [105, 2020], + [114, 2020], + [114, 2027], + [123, 2027], + [123, 2035], + [132, 2035], + [132, 2027], + [150, 2020], + [150, 2004], + [159, 2004], + [159, 1997], + [177, 1997], + [177, 1989], + [196, 1989], + [196, 1982], + [223, 1982], + [223, 1974], + [259, 1974], + [259, 1966], + [278, 1966], + [287, 1982], + [296, 1982], + [296, 1989], + [305, 1989], + [305, 1997], + [314, 1997], + [314, 2020], + [305, 2020], + [305, 2065], + [287, 2073], + [287, 2096], + [269, 2096], + [269, 2111], + [259, 2111], + [259, 2187], + [250, 2187], + [250, 2218], + [259, 2218], + [259, 2324], + [250, 2324], + [250, 2332], + [259, 2332], + [259, 2347], + [250, 2347], + [250, 2400], + [241, 2400], + [241, 2408], + [232, 2408], + [232, 2415], + [223, 2415], + [223, 2423], + [214, 2423], + [214, 2446], + [196, 2453], + [196, 2461], + [187, 2461], + [187, 2468], + [177, 2468], + [177, 2484], + [168, 2484], + [168, 2529], + [177, 2529], + [177, 2537], + [168, 2537], + [168, 2545], + [150, 2545], + [150, 2552], + [132, 2552], + [132, 2560], + [123, 2560], + [123, 2575], + [114, 2575], + [114, 2583], + [123, 2583], + [123, 2651], + [132, 2651], + [132, 2666], + [141, 2666], + [141, 2681], + [150, 2681], + [150, 2696], + [159, 2696], + [159, 2727], + [168, 2727], + [168, 2742], + [177, 2742], + [177, 2757], + [196, 2765], + [196, 2780], + [187, 2780], + [187, 2788], + [196, 2788], + [196, 2810], + [214, 2818], + [214, 2826], + [232, 2826], + [232, 2818], + [250, 2818], + [250, 2810], + [269, 2810], + [269, 2795], + [305, 2795], + [305, 2780], + [323, 2772], + [323, 2757], + [332, 2757], + [332, 2712], + [341, 2712], + [341, 2696], + [350, 2696], + [350, 2681], + [360, 2681], + [360, 2674], + [369, 2674], + [369, 2666], + [378, 2666], + [378, 2658], + [387, 2658], + [387, 2605], + [378, 2605], + [378, 2598], + [387, 2598], + [387, 2583], + [396, 2583], + [396, 2575], + [487, 2575], + [487, 2583], + [496, 2583], + [496, 2575], + [505, 2575], + [505, 2567], + [523, 2560], + [523, 2552], + [560, 2545], + [569, 2529], + [578, 2529], + [578, 2453], + [587, 2453], + [587, 2446], + [605, 2446], + [605, 2438], + [614, 2438], + [614, 2446], + [633, 2446], + [633, 2453], + [642, 2453], + [642, 2468], + [651, 2468], + [651, 2491], + [642, 2491], + [642, 2507], + [633, 2507], + [633, 2522], + [624, 2522], + [624, 2529], + [660, 2545], + [660, 2560], + [669, 2560], + [669, 2567], + [678, 2567], + [678, 2575], + [687, 2575], + [687, 2590], + [696, 2590], + [696, 2605], + [705, 2605], + [705, 2613], + [733, 2613], + [733, 2621], + [724, 2621], + [724, 2666], + [733, 2666], + [733, 2681], + [751, 2689], + [751, 2719], + [769, 2719], + [769, 2712], + [796, 2712], + [796, 2696], + [806, 2696], + [806, 2681], + [815, 2681], + [815, 2674], + [824, 2674], + [824, 2666], + [833, 2666], + [833, 2643], + [842, 2643], + [842, 2636], + [851, 2636], + [851, 2628], + [860, 2628], + [860, 2613], + [869, 2613], + [869, 2605], + [878, 2605], + [878, 2598], + [915, 2605], + [915, 2613], + [933, 2613], + [933, 2605], + [960, 2605], + [960, 2598], + [1015, 2598], + [1015, 2605], + [1024, 2605], + [1024, 2613], + [1042, 2613], + [1042, 2621], + [1060, 2621], + [1060, 2613], + [1079, 2613], + [1079, 2605], + [1170, 2598], + [1170, 2590], + [1188, 2583], + [1188, 2537], + [1206, 2529], + [1206, 2491], + [1215, 2491], + [1215, 2476], + [1233, 2468], + [1233, 2453], + [1242, 2453], + [1242, 2438], + [1270, 2438], + [1270, 2446], + [1288, 2446], + [1288, 2453], + [1324, 2453], + [1324, 2461], + [1343, 2461], + [1343, 2468], + [1361, 2468], + [1361, 2476], + [1379, 2476], + [1379, 2491], + [1397, 2499], + [1397, 2507], + [1434, 2514], + [1434, 2522], + [1452, 2522], + [1452, 2529], + [1461, 2529], + [1461, 2537], + [1488, 2537], + [1488, 2529], + [1497, 2529], + [1497, 2522], + [1516, 2522], + [1516, 2537], + [1506, 2537], + [1506, 2545], + [1525, 2545], + [1525, 2560], + [1561, 2545], + [1561, 2529], + [1570, 2529], + [1570, 2522], + [1607, 2529], + [1607, 2537], + [1625, 2537], + [1625, 2507], + [1652, 2507], + [1652, 2522], + [1661, 2522], + [1661, 2552], + [1652, 2552], + [1652, 2560], + [1670, 2567], + [1670, 2575], + [1688, 2575], + [1688, 2583], + [1698, 2583], + [1698, 2590], + [1725, 2590], + [1725, 2598], + [1743, 2598], + [1743, 2605], + [1789, 2605], + [1789, 2598], + [1798, 2598], + [1798, 2590], + [1852, 2590], + [1852, 2575], + [1871, 2567], + [1871, 2552], + [1889, 2545], + [1889, 2529], + [1898, 2529], + [1898, 2507], + [1916, 2499], + [1916, 2484], + [1925, 2484], + [1925, 2468], + [1943, 2461], + [1943, 2446], + [1952, 2446], + [1952, 2430], + [1962, 2430], + [1962, 2377], + [1943, 2370], + [1943, 2347], + [1934, 2347], + [1934, 2339], + [1925, 2339], + [1925, 2332], + [1907, 2332], + [1907, 2316], + [1898, 2316], + [1898, 2309], + [1907, 2309], + [1907, 2301], + [1898, 2301], + [1898, 2248], + [1907, 2248], + [1907, 2256], + [1925, 2263], + [1925, 2256], + [1934, 2256], + [1934, 2225], + [1925, 2225], + [1925, 2218], + [1907, 2218], + [1907, 2210], + [1898, 2210], + [1898, 2187], + [1889, 2187], + [1889, 2134], + [1880, 2134], + [1880, 2058], + [1871, 2058], + [1871, 2035], + [1861, 2035], + [1861, 2020], + [1871, 2020], + [1871, 2004], + [1880, 2004], + [1880, 1974], + [1889, 1974], + [1889, 1943], + [1898, 1943], + [1898, 1905], + [1907, 1905], + [1907, 1898], + [1989, 1898], + [1989, 1905], + [2007, 1905], + [2016, 1921], + [2053, 1928], + [2053, 1936], + [2071, 1936], + [2071, 1943], + [2080, 1943], + [2080, 1951], + [2089, 1951], + [2089, 1959], + [2098, 1959], + [2098, 1966], + [2116, 1966], + [2116, 1959], + [2134, 1959], + [2134, 1951], + [2153, 1951], + [2153, 1943], + [2162, 1943], + [2162, 1913], + [2171, 1913], + [2171, 1890], + [2189, 1890], + [2189, 1882], + [2216, 1882], + [2216, 1837], + [2207, 1837], + [2207, 1814], + [2198, 1814], + [2198, 1806], + [2180, 1799], + [2180, 1791], + [2171, 1791], + [2171, 1783], + [2153, 1776], + [2153, 1768], + [2144, 1768], + [2144, 1753], + [2125, 1753], + [2125, 1745], + [2107, 1738], + [2098, 1722], + [2080, 1715], + [2080, 1684], + [2071, 1684], + [2071, 1661], + [2062, 1661], + [2062, 1639], + [2053, 1639], + [2053, 1631], + [2034, 1623], + [2034, 1608], + [2043, 1608], + [2043, 1585], + [2053, 1585], + [2053, 1578], + [2043, 1578], + [2043, 1570], + [2053, 1570], + [2053, 1501], + [2062, 1501], + [2062, 1494], + [2071, 1494], + [2071, 1486], + [2080, 1486], + [2080, 1471], + [2071, 1471], + [2071, 1456], + [2053, 1456], + [2053, 1463], + [2043, 1463], + [2043, 1471], + [2034, 1471], + [2034, 1486], + [2025, 1486], + [2025, 1478], + [2007, 1471], + [2007, 1463], + [1989, 1463], + [1989, 1448], + [1980, 1448], + [1980, 1425], + [1971, 1425], + [1971, 1410], + [1952, 1402], + [1952, 1387], + [1943, 1387], + [1943, 1379], + [1925, 1379], + [1925, 1372], + [1861, 1372], + [1861, 1379], + [1852, 1379], + [1852, 1387], + [1834, 1394], + [1834, 1410], + [1816, 1417], + [1816, 1440], + [1807, 1440], + [1807, 1494], + [1816, 1494], + [1816, 1562], + [1825, 1562], + [1825, 1578], + [1816, 1578], + [1816, 1585], + [1807, 1585], + [1807, 1578], + [1789, 1578], + [1789, 1585], + [1779, 1585], + [1779, 1593], + [1770, 1593], + [1770, 1600], + [1752, 1600], + [1752, 1608], + [1734, 1608], + [1734, 1600], + [1707, 1600], + [1698, 1616], + [1688, 1616], + [1688, 1669], + [1698, 1669], + [1698, 1677], + [1688, 1677], + [1688, 1692], + [1698, 1692], + [1698, 1715], + [1707, 1715], + [1707, 1745], + [1698, 1745], + [1698, 1799], + [1688, 1799], + [1688, 1806], + [1679, 1806], + [1679, 1814], + [1670, 1814], + [1670, 1829], + [1652, 1837], + [1652, 1852], + [1634, 1852], + [1634, 1860], + [1625, 1860], + [1625, 1867], + [1588, 1867], + [1588, 1860], + [1579, 1860], + [1579, 1852], + [1570, 1852], + [1570, 1844], + [1552, 1844], + [1552, 1837], + [1543, 1837], + [1543, 1776], + [1534, 1776], + [1534, 1745], + [1525, 1745], + [1525, 1700], + [1543, 1692], + [1543, 1669], + [1525, 1677], + [1525, 1692], + [1516, 1692], + [1516, 1700], + [1497, 1707], + [1497, 1715], + [1479, 1722], + [1479, 1730], + [1470, 1730], + [1470, 1738], + [1461, 1738], + [1461, 1745], + [1424, 1745], + [1424, 1738], + [1415, 1738], + [1415, 1715], + [1424, 1715], + [1424, 1700], + [1434, 1700], + [1434, 1684], + [1443, 1684], + [1443, 1639], + [1452, 1639], + [1452, 1623], + [1470, 1616], + [1479, 1600], + [1497, 1600], + [1497, 1593], + [1543, 1593], + [1543, 1585], + [1570, 1585], + [1570, 1578], + [1588, 1578], + [1588, 1547], + [1597, 1547], + [1597, 1532], + [1616, 1524], + [1616, 1478], + [1607, 1478], + [1607, 1463], + [1597, 1463], + [1597, 1425], + [1588, 1425], + [1588, 1402], + [1579, 1402], + [1579, 1372], + [1597, 1364], + [1597, 1280], + [1607, 1280], + [1607, 1265], + [1625, 1257], + [1625, 1219], + [1634, 1219], + [1634, 1204], + [1670, 1196], + [1670, 1188], + [1679, 1188], + [1679, 1173], + [1698, 1173], + [1698, 1165], + [1734, 1158], + [1734, 1150], + [1743, 1150], + [1743, 1143], + [1789, 1143], + [1789, 1150], + [1816, 1150], + [1816, 1143], + [1852, 1143], + [1852, 1135], + [1889, 1135], + [1889, 1143], + [1925, 1143], + [1925, 1150], + [1980, 1150], + [1980, 1143], + [1989, 1143], + [1989, 1150], + [2025, 1150], + [2025, 1158], + [2043, 1165], + [2043, 1181], + [2062, 1188], + [2062, 1204], + [2071, 1204], + [2071, 1249], + [2080, 1249], + [2080, 1280], + [2107, 1280], + [2107, 1272], + [2171, 1272], + [2171, 1280], + [2235, 1280], + [2235, 1288], + [2289, 1288], + [2289, 1280], + [2298, 1280], + [2298, 1257], + [2280, 1249], + [2280, 1234], + [2262, 1227], + [2253, 1211], + [2235, 1211], + [2235, 1204], + [2225, 1204], + [2225, 1196], + [2216, 1196], + [2216, 1181], + [2225, 1181], + [2225, 1173], + [2216, 1173], + [2216, 1135], + [2225, 1135], + [2225, 1127], + [2235, 1127], + [2235, 1120], + [2271, 1120], + [2271, 1127], + [2280, 1127], + [2280, 1120], + [2298, 1120], + [2298, 1074], + [2317, 1066], + [2317, 1058], + [2326, 1058], + [2326, 1051], + [2335, 1051], + [2335, 1036], + [2344, 1036], + [2344, 1013], + [2362, 1005], + [2362, 997], + [2344, 990], + [2344, 982], + [2326, 982], + [2326, 974], + [2317, 974], + [2317, 967], + [2307, 967], + [2307, 959], + [2298, 959], + [2298, 844], + [2307, 844], + [2307, 829], + [2326, 821], + [2326, 791], + [2335, 791], + [2335, 783], + [2344, 783], + [2344, 776], + [2380, 768], + [2380, 760], + [2453, 760], + [2453, 753], + [2480, 753], + [2480, 745], + [2499, 745], + [2499, 737], + [2508, 737], + [2508, 730], + [2517, 730], + [2517, 722], + [2526, 722], + [2526, 714], + [2535, 714], + [2535, 668], + [2526, 668], + [2526, 646], + [2535, 646], + [2535, 630], + [2553, 630], + [2553, 623], + [2562, 623], + [2562, 615], + [2580, 615], + [2580, 492], + [2571, 492], + [2571, 462], + [2562, 462], + [2562, 446], + [2553, 446], + [2553, 439], + [2535, 439], + [2535, 446], + [2526, 446], + [2526, 546], + [2517, 546], + [2517, 561], + [2508, 561], + [2508, 577], + [2499, 577], + [2499, 592], + [2480, 600], + [2480, 615], + [2471, 615], + [2471, 623], + [2435, 630], + [2435, 638], + [2426, 638], + [2426, 630], + [2326, 630], + [2326, 623], + [2307, 623], + [2307, 615], + [2289, 615], + [2289, 607], + [2262, 607], + [2262, 600], + [2244, 600], + [2244, 592], + [2235, 592], + [2235, 577], + [2225, 577], + [2225, 554], + [2216, 554], + [2216, 500], + [2225, 500], + [2225, 477], + [2235, 477], + [2235, 462], + [2244, 462], + [2244, 446], + [2253, 446], + [2253, 416], + [2262, 416], + [2262, 401], + [2271, 401], + [2271, 385], + [2280, 385], + [2280, 355], + [2289, 355], + [2289, 309], + [2280, 309], + [2280, 286], + [2289, 286], + [2289, 270], + [2298, 270], + [2298, 255], + [2307, 255], + [2307, 247], + [2326, 240], + [2335, 224], + [2380, 224], + [2380, 217], + [2389, 217], + [2389, 209], + [2398, 209], + [2398, 201], + [2417, 209], + [2417, 201], + [2426, 201], + [2426, 194], + [2435, 194], + [2435, 201], + [2471, 201], + [2471, 209], + [2489, 209], + [2489, 217], + [2508, 217], + [2508, 224], + [2535, 224], + [2535, 232], + [2562, 232], + [2562, 240], + [2580, 240], + [2580, 247], + [2590, 247], + [2590, 255], + [2599, 255], + [2599, 263], + [2608, 263], + [2608, 278], + [2626, 278], + [2626, 270], + [2672, 270], + [2672, 263], + [2699, 263], + [2699, 255], + [2717, 263], + [2717, 255], + [2735, 255], + [2735, 247], + [2753, 247], + [2753, 240], + [2763, 240], + [2763, 232], + [2790, 232], + [2790, 224], + [2808, 224], + [2808, 217], + [2926, 224], + [2926, 232], + [2963, 232], + [2963, 240], + [3017, 240], + [3017, 247], + [3045, 247], + [3045, 255], + [3072, 255], + [3072, 247], + [3127, 247], + [3127, 255], + [3172, 255], + [3172, 247], + [3181, 247], + [3181, 240], + [3199, 240], + [3199, 232], + [3236, 232], + [3236, 240], + [3263, 240], + [3263, 247], + [3309, 247], + [3309, 255], + [3318, 255], + [3318, 270], + [3300, 278], + [3300, 301], + [3290, 301], + [3290, 339], + [3300, 339], + [3300, 378], + [3272, 378], + [3272, 393], + [3263, 393], + [3263, 446], + [3272, 446], + [3272, 469], + [3281, 469], + [3281, 485], + [3290, 485], + [3290, 508], + [3300, 508], + [3300, 523], + [3309, 523], + [3309, 531], + [3363, 531], + [3363, 523], + [3409, 523], + [3409, 515], + [3482, 515], + [3482, 508], + [3509, 508], + [3509, 515], + [3527, 515], + [3527, 523], + [3545, 523], + [3545, 531], + [3564, 531], + [3564, 523], + [3582, 523], + [3582, 531], + [3591, 531], + [3591, 538], + [3618, 538], + [3618, 531], + [3627, 531], + [3627, 508], + [3618, 508], + [3618, 500], + [3609, 500], + [3609, 492], + [3600, 492], + [3600, 485], + [3564, 485], + [3564, 462], + [3554, 462], + [3554, 416], + [3564, 416], + [3564, 378], + [3554, 378], + [3554, 362], + [3545, 362], + [3545, 347], + [3536, 347], + [3536, 339], + [3518, 339], + [3518, 332], + [3500, 332], + [3500, 324], + [3454, 324], + [3454, 309], + [3445, 309], + [3445, 293], + [3436, 293], + [3436, 263], + [3427, 263], + [3427, 247], + [3372, 240], + [3372, 224], + [3381, 224], + [3381, 217], + [3372, 217], + [3372, 163], + [3391, 163], + [3391, 171], + [3418, 171], + [3418, 163], + [3427, 163], + [3427, 148], + [3436, 148], + [3436, 125], + [3454, 117], + [3454, 109], + [3463, 109], + [3463, 94], + [3500, 94], + [3500, 102], + [3509, 102], + [3509, 109], + [3527, 109], + [3527, 117], + [3545, 117], + [3545, 109], + [3582, 109], + [3591, 125], + [3609, 132], + [3609, 148], + [3618, 148], + [3618, 171], + [3636, 171], + [3636, 178], + [3645, 178], + [3645, 194], + [3664, 201], + [3664, 209], + [3700, 209], + [3700, 217], + [3736, 224], + [3736, 232], + [3746, 232], + [3746, 240], + [3755, 240], + [3755, 247], + [3764, 247], + [3764, 255], + [3773, 255], + [3773, 263], + [3782, 263], + [3782, 278], + [3791, 278], + [3791, 286], + [3809, 293], + [3809, 316], + [3818, 316], + [3818, 332], + [3827, 332], + [3827, 347], + [3837, 347], + [3837, 355], + [3855, 362], + [3864, 378], + [3873, 378], + [3873, 401], + [3882, 401], + [3882, 424], + [3891, 424], + [3891, 439], + [3900, 439], + [3900, 462], + [3909, 462], + [3909, 477], + [3919, 477], + [3919, 515], + [3928, 515], + [3928, 554], + [3946, 554], + [3946, 561], + [3955, 561], + [3955, 569], + [3982, 569], + [3982, 561], + [4037, 561], + [4037, 546], + [4046, 546], + [4046, 531], + [4064, 523], + [4064, 485], + [4073, 485], + [4073, 469], + [4091, 462], + [4091, 431], + [4101, 431], + [4101, 416], + [4116, 416], + [4116, 676], + [4110, 676], + [4110, 684], + [4101, 684], + [4101, 691], + [4091, 691], + [4091, 684], + [4046, 684], + [4046, 699], + [4037, 699], + [4037, 730], + [4019, 737], + [4019, 753], + [4010, 753], + [4010, 776], + [4000, 776], + [4000, 814], + [3982, 821], + [3973, 837], + [3964, 837], + [3964, 852], + [3955, 852], + [3955, 875], + [3946, 875], + [3946, 929], + [3955, 929], + [3955, 959], + [3964, 959], + [3964, 982], + [4028, 982], + [4028, 974], + [4037, 974], + [4037, 967], + [4073, 967], + [4073, 959], + [4101, 959], + [4101, 967], + [4116, 973], + [4116, 1417], + [4110, 1417], + [4110, 1425], + [4116, 1425], + [4116, 1532], + [4101, 1532], + [4101, 1539], + [4082, 1539], + [4082, 1570], + [4091, 1570], + [4091, 1593], + [4101, 1593], + [4101, 1608], + [4116, 1615], + [4116, 1937], + [4101, 1943], + [4101, 1974], + [4091, 1974], + [4091, 1982], + [4082, 1982], + [4082, 1989], + [4055, 1989], + [4055, 1982], + [4037, 1982], + [4037, 1989], + [4028, 1989], + [4028, 1982], + [4019, 1982], + [4019, 1959], + [4010, 1959], + [4010, 1951], + [4000, 1951], + [4000, 1943], + [3991, 1943], + [3991, 1936], + [3973, 1936], + [3973, 1928], + [3955, 1928], + [3955, 1921], + [3946, 1921], + [3946, 1913], + [3937, 1913], + [3937, 1898], + [3928, 1898], + [3928, 1882], + [3919, 1882], + [3919, 1875], + [3909, 1875], + [3909, 1867], + [3900, 1867], + [3900, 1852], + [3855, 1852], + [3855, 1860], + [3846, 1860], + [3846, 1867], + [3809, 1867], + [3809, 1875], + [3791, 1867], + [3791, 1875], + [3782, 1875], + [3782, 1882], + [3791, 1882], + [3791, 1898], + [3782, 1898], + [3782, 1905], + [3773, 1905], + [3773, 1913], + [3764, 1913], + [3764, 1936], + [3773, 1936], + [3773, 1951], + [3782, 1951], + [3782, 1959], + [3800, 1966], + [3800, 1982], + [3773, 1982], + [3773, 1974], + [3755, 1974] + ], + [ + [3837, 1097], + [3809, 1097], + [3809, 1104], + [3791, 1104], + [3791, 1120], + [3782, 1120], + [3782, 1143], + [3773, 1143], + [3773, 1181], + [3764, 1181], + [3764, 1242], + [3755, 1242], + [3755, 1257], + [3746, 1257], + [3746, 1272], + [3736, 1272], + [3736, 1280], + [3709, 1280], + [3709, 1288], + [3700, 1288], + [3700, 1303], + [3682, 1311], + [3682, 1425], + [3673, 1425], + [3673, 1471], + [3691, 1478], + [3691, 1486], + [3700, 1486], + [3700, 1494], + [3709, 1494], + [3709, 1501], + [3755, 1501], + [3755, 1517], + [3764, 1517], + [3764, 1532], + [3773, 1532], + [3773, 1539], + [3800, 1539], + [3800, 1547], + [3809, 1547], + [3809, 1539], + [3827, 1532], + [3827, 1524], + [3837, 1524], + [3837, 1509], + [3827, 1509], + [3827, 1494], + [3818, 1494], + [3818, 1478], + [3800, 1471], + [3800, 1463], + [3782, 1463], + [3782, 1456], + [3746, 1456], + [3746, 1463], + [3727, 1463], + [3727, 1448], + [3736, 1448], + [3736, 1440], + [3755, 1440], + [3755, 1433], + [3764, 1433], + [3764, 1417], + [3773, 1417], + [3773, 1394], + [3782, 1394], + [3782, 1387], + [3773, 1387], + [3773, 1379], + [3764, 1379], + [3764, 1333], + [3755, 1333], + [3755, 1318], + [3746, 1318], + [3746, 1295], + [3782, 1295], + [3782, 1303], + [3800, 1303], + [3800, 1295], + [3809, 1295], + [3809, 1280], + [3818, 1280], + [3818, 1265], + [3827, 1265], + [3827, 1249], + [3837, 1249], + [3837, 1234], + [3855, 1227], + [3855, 1188], + [3864, 1188], + [3864, 1173], + [3873, 1173], + [3873, 1150], + [3882, 1150], + [3882, 1112], + [3873, 1112], + [3873, 1097], + [3864, 1097], + [3864, 1089], + [3837, 1089], + [3837, 1097] + ], + [ + [3272, 1905], + [3272, 1898], + [3290, 1890], + [3290, 1898], + [3309, 1905], + [3309, 1921], + [3345, 1921], + [3345, 1890], + [3336, 1890], + [3336, 1867], + [3327, 1867], + [3327, 1822], + [3309, 1814], + [3309, 1799], + [3300, 1799], + [3300, 1791], + [3290, 1791], + [3290, 1783], + [3281, 1783], + [3281, 1776], + [3272, 1776], + [3272, 1768], + [3254, 1761], + [3254, 1745], + [3245, 1745], + [3245, 1738], + [3236, 1738], + [3236, 1730], + [3227, 1730], + [3227, 1722], + [3218, 1722], + [3218, 1707], + [3199, 1707], + [3199, 1700], + [3190, 1700], + [3190, 1684], + [3136, 1684], + [3136, 1715], + [3145, 1715], + [3145, 1722], + [3154, 1722], + [3154, 1738], + [3172, 1745], + [3172, 1761], + [3181, 1761], + [3181, 1768], + [3172, 1768], + [3172, 1776], + [3181, 1776], + [3181, 1814], + [3190, 1814], + [3190, 1822], + [3181, 1822], + [3181, 1860], + [3190, 1860], + [3190, 1875], + [3199, 1875], + [3199, 1882], + [3218, 1882], + [3218, 1890], + [3245, 1890], + [3245, 1898], + [3254, 1898], + [3254, 1905], + [3272, 1905] + ], + [ + [3081, 1722], + [3072, 1722], + [3072, 1761], + [3127, 1761], + [3127, 1753], + [3145, 1753], + [3145, 1730], + [3136, 1730], + [3136, 1715], + [3108, 1715], + [3108, 1707], + [3081, 1707], + [3081, 1722] + ], + [ + [3400, 1905], + [3391, 1905], + [3391, 1898], + [3381, 1898], + [3381, 1890], + [3372, 1890], + [3372, 1905], + [3381, 1905], + [3381, 1921], + [3372, 1921], + [3372, 1936], + [3381, 1936], + [3381, 1951], + [3409, 1951], + [3409, 1905], + [3418, 1905], + [3418, 1890], + [3400, 1890], + [3400, 1905] + ], + [[3172, 1959], [3181, 1959], [3181, 1943], [3172, 1943], [3172, 1959]], + [ + [3755, 1974], + [3755, 1966], + [3736, 1959], + [3736, 1966], + [3746, 1966], + [3746, 1974], + [3755, 1974] + ], + [[3837, 1402], [3846, 1402], [3846, 1394], [3837, 1394], [3837, 1402]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/self-touching.json b/packages/melonjs/tests/earcut/fixtures/self-touching.json new file mode 100644 index 000000000..381115761 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/self-touching.json @@ -0,0 +1,133 @@ +[ + [ + [160.40671875, 11.3976701817587], + [160.396875, 11.3935345987524], + [160.39828125, 11.4018057045896], + [160.39265625, 11.4004272036667], + [160.38984375, 11.3811274888866], + [160.3940625, 11.3838846711709], + [160.3771875, 11.3521754635814], + [160.33921875, 11.3590690696413], + [160.35046875, 11.3645838345287], + [160.3575, 11.3645838345287], + [160.3575, 11.3756130442004], + [160.29421875, 11.3507967223837], + [160.2928125, 11.3480392200086], + [160.28859375, 11.3480392200086], + [160.295625, 11.3287359579628], + [160.26328125, 11.3080524456288], + [160.295625, 11.1866791818427], + [160.31671875, 11.1811610026871], + [160.318125, 11.1770222993774], + [160.31390625, 11.1687447155658], + [160.3125, 11.1494294353899], + [160.2703125, 11.1107950268865], + [160.2421875, 11.1149346728405], + [160.23796875, 11.0997556838987], + [160.25625, 11.095615822671], + [160.21828125, 11.0735355725517], + [160.21546875, 11.0652550492086], + [160.2084375, 11.0762956949617], + [160.20140625, 11.0638749392263], + [160.19015625, 11.0528338254202], + [160.18453125, 11.0528338254202], + [160.183125, 11.0486933005675], + [160.24640625, 11.0583544343014], + [160.26890625, 11.0555941428523], + [160.250625, 11.0804358297701], + [160.28015625, 11.0942358558913], + [160.295625, 11.0845759059922], + [160.2928125, 11.0721555015877], + [160.318125, 11.0790557913426], + [160.31953125, 11.0942358558913], + [160.33359375, 11.1038954864431], + [160.34484375, 11.0900959164515], + [160.35609375, 11.1038954864431], + [160.363125, 11.0969957829326], + [160.36453125, 11.1052754075802], + [160.36171875, 11.1121749153987], + [160.37578125, 11.1149346728405], + [160.39828125, 11.1080352302834], + [160.36734375, 11.1756427184796], + [160.48125, 11.1852996469051], + [160.48546875, 11.1825405573266], + [160.5121875, 11.1852996469051], + [160.5459375, 11.1342522433585], + [160.56421875, 11.1301128717933], + [160.55578125, 11.1204541093718], + [160.56140625, 11.1135547973836], + [160.588125, 11.1314926688534], + [160.62328125, 11.1121749153987], + [160.633125, 11.1135547973836], + [160.6471875, 11.1025155587833], + [160.64296875, 11.1176944041669], + [160.63734375, 11.1190742600349], + [160.62328125, 11.1342522433585], + [160.62046875, 11.128733068196], + [160.6078125, 11.1480497233847], + [160.61203125, 11.1480497233847], + [160.6134375, 11.1563278971795], + [160.5909375, 11.1425308098987], + [160.576875, 11.1480497233847], + [160.57125, 11.1549482179223], + [160.57125, 11.1494294353899], + [160.57828125, 11.1452902797332], + [160.57265625, 11.1425308098987], + [160.57125, 11.1494294353899], + [160.54875, 11.1577075698847], + [160.554375, 11.179781441482], + [160.54875, 11.1770222993774], + [160.5628125, 11.2087508469621], + [160.5234375, 11.2059919808933], + [160.52203125, 11.2032330885061], + [160.50515625, 11.2184066708578], + [160.49390625, 11.2032330885061], + [160.46296875, 11.2046125379891], + [160.46296875, 11.201853632445], + [160.4165625, 11.2115096867066], + [160.41796875, 11.2211654184183], + [160.39546875, 11.2266828344767], + [160.35609375, 11.2225447823168], + [160.35328125, 11.2363380587922], + [160.3659375, 11.2473722050633], + [160.351875, 11.2915045605453], + [160.32375, 11.2721974885629], + [160.32234375, 11.2846093266964], + [160.35328125, 11.3080524456288], + [160.351875, 11.3149471157772], + [160.3659375, 11.3204627323768], + [160.36171875, 11.2997786224589], + [160.3828125, 11.3011576095711], + [160.37859375, 11.3080524456288], + [160.38140625, 11.3094313929343], + [160.3828125, 11.3011576095711], + [160.408125, 11.3039155638972], + [160.408125, 11.2997786224589], + [160.425, 11.3094313929343], + [160.41234375, 11.3411453475587], + [160.3996875, 11.3301148056307], + [160.40953125, 11.3700984927314], + [160.39265625, 11.3618264654176], + [160.396875, 11.3797488877286], + [160.4053125, 11.3893989555911], + [160.40953125, 11.3866418267411], + [160.419375, 11.4004272036667], + [160.41515625, 11.4059411672242], + [160.419375, 11.4114550237293], + [160.425, 11.412833471123], + [160.42359375, 11.422482415387], + [160.40671875, 11.3976701817587] + ], + [ + [160.363125, 11.1425308098987], + [160.3603125, 11.1383915560672], + [160.3603125, 11.1439105480884], + [160.363125, 11.1425308098987] + ], + [ + [160.35046875, 11.1397713138873], + [160.34625, 11.1383915560672], + [160.34203125, 11.1480497233847], + [160.35046875, 11.1397713138873] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/shared-points.json b/packages/melonjs/tests/earcut/fixtures/shared-points.json new file mode 100644 index 000000000..98a9508ea --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/shared-points.json @@ -0,0 +1,14 @@ +[ + [ + [4136, 1016], + [4112, 1016], + [4104, 976], + [4136, 1016], + [4144, 984], + [4104, 976], + [4144, 968], + [4144, 984], + [4168, 992], + [4152, 1064] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/simplified-us-border.json b/packages/melonjs/tests/earcut/fixtures/simplified-us-border.json new file mode 100644 index 000000000..135ffc51d --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/simplified-us-border.json @@ -0,0 +1,126 @@ +[ + [ + [1130, 1713], + [1131, 1710], + [1137, 1731], + [1133, 1752], + [1125, 1753], + [1118, 1742], + [1110, 1717], + [1105, 1718], + [1108, 1704], + [1096, 1691], + [1077, 1694], + [1067, 1683], + [1019, 1687], + [1031, 1689], + [1031, 1704], + [1022, 1696], + [1022, 1702], + [1010, 1700], + [1003, 1692], + [998, 1696], + [980, 1690], + [970, 1698], + [966, 1694], + [966, 1702], + [938, 1718], + [943, 1742], + [920, 1736], + [916, 1721], + [894, 1693], + [884, 1691], + [872, 1703], + [837, 1667], + [785, 1672], + [743, 1654], + [715, 1656], + [699, 1636], + [676, 1628], + [654, 1587], + [656, 1583], + [660, 1588], + [657, 1579], + [649, 1580], + [633, 1547], + [637, 1529], + [631, 1507], + [638, 1454], + [647, 1454], + [637, 1452], + [639, 1441], + [635, 1442], + [629, 1417], + [651, 1421], + [647, 1434], + [655, 1428], + [650, 1440], + [656, 1434], + [654, 1423], + [651, 1420], + [653, 1419], + [651, 1407], + [965, 1407], + [966, 1400], + [972, 1411], + [1008, 1423], + [1043, 1419], + [1083, 1442], + [1086, 1450], + [1091, 1448], + [1109, 1468], + [1114, 1496], + [1102, 1520], + [1107, 1525], + [1149, 1508], + [1147, 1498], + [1152, 1495], + [1174, 1495], + [1195, 1474], + [1242, 1470], + [1260, 1433], + [1277, 1440], + [1277, 1462], + [1286, 1476], + [1274, 1484], + [1265, 1480], + [1243, 1503], + [1240, 1516], + [1252, 1526], + [1238, 1529], + [1236, 1523], + [1234, 1530], + [1218, 1531], + [1206, 1540], + [1205, 1554], + [1195, 1567], + [1188, 1556], + [1194, 1574], + [1185, 1590], + [1187, 1581], + [1179, 1567], + [1185, 1557], + [1176, 1562], + [1180, 1579], + [1179, 1585], + [1170, 1577], + [1180, 1593], + [1169, 1590], + [1183, 1596], + [1186, 1607], + [1175, 1605], + [1183, 1613], + [1182, 1618], + [1171, 1615], + [1179, 1624], + [1167, 1626], + [1145, 1650], + [1132, 1659], + [1128, 1656], + [1121, 1675], + [1131, 1708], + [1129, 1710], + [1130, 1713] + ], + [[654, 1419], [653, 1419], [654, 1423], [656, 1425], [654, 1419]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/steiner.json b/packages/melonjs/tests/earcut/fixtures/steiner.json new file mode 100644 index 000000000..076b47bbb --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/steiner.json @@ -0,0 +1,7 @@ +[ + [[0, 0], [100, 0], [100, 100], [0, 100]], + [[50, 50]], + [[30, 40]], + [[70, 60]], + [[20, 70]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/touching-holes.json b/packages/melonjs/tests/earcut/fixtures/touching-holes.json new file mode 100644 index 000000000..7427cf306 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/touching-holes.json @@ -0,0 +1,63 @@ +[ + [ + [3694, 2061], + [3794, 2035], + [3812, 2123], + [3784, 2123], + [3708, 2139], + [3694, 2061] + ], + [ + [3752, 2109], + [3740, 2102], + [3712, 2109], + [3715, 2125], + [3723, 2128], + [3740, 2124], + [3742, 2112], + [3752, 2109] + ], + [[3797, 2101], [3787, 2096], [3780, 2106], [3788, 2114], [3797, 2101]], + [[3734, 2099], [3732, 2091], [3719, 2094], [3721, 2102], [3734, 2099]], + [ + [3777, 2082], + [3774, 2071], + [3772, 2086], + [3765, 2091], + [3748, 2088], + [3749, 2062], + [3738, 2081], + [3745, 2095], + [3761, 2099], + [3777, 2082] + ], + [ + [3719, 2079], + [3712, 2079], + [3706, 2091], + [3712, 2097], + [3721, 2080], + [3719, 2079] + ], + [ + [3773, 2067], + [3761, 2053], + [3753, 2061], + [3753, 2071], + [3756, 2075], + [3773, 2067] + ], + [ + [3708, 2079], + [3712, 2079], + [3714, 2076], + [3719, 2079], + [3722, 2079], + [3718, 2088], + [3723, 2089], + [3734, 2075], + [3730, 2068], + [3717, 2065], + [3708, 2079] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/touching2.json b/packages/melonjs/tests/earcut/fixtures/touching2.json new file mode 100644 index 000000000..0036de7d3 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/touching2.json @@ -0,0 +1,4 @@ +[ + [[120, 2031], [92, 2368], [94, 2200], [33, 2119], [42, 2112], [53, 2068]], + [[44, 2104], [79, 2132], [88, 2115], [44, 2104]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/touching3.json b/packages/melonjs/tests/earcut/fixtures/touching3.json new file mode 100644 index 000000000..fb6a7bca8 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/touching3.json @@ -0,0 +1,16 @@ +[ + [ + [1241, 887], + [1257, 891], + [1248, 904], + [1232, 911], + [1212, 911], + [1207, 911], + [1209, 900], + [1219, 898], + [1225, 907], + [1241, 887] + ], + [[1212, 902], [1212, 911], [1219, 909], [1212, 902]], + [[1248, 891], [1239, 896], [1246, 898], [1248, 891]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/touching4.json b/packages/melonjs/tests/earcut/fixtures/touching4.json new file mode 100644 index 000000000..072fdfb20 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/touching4.json @@ -0,0 +1,7 @@ +[ + [[11, 10], [0, 10], [0, 0], [11, 0]], + [[7, 6], [7, 9], [10, 9]], + [[7, 5], [10, 2], [10, 5]], + [[6, 9], [1, 4], [1, 9]], + [[1, 1], [1, 4], [4, 1]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/water-huge.json b/packages/melonjs/tests/earcut/fixtures/water-huge.json new file mode 100644 index 000000000..c32abb4ef --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/water-huge.json @@ -0,0 +1,5419 @@ +[ + [ + [3116, 3071], + [3118, 3068], + [3108, 3102], + [3100, 3105], + [3096, 3113], + [3099, 3121], + [3091, 3135], + [3099, 3133], + [3105, 3144], + [3113, 3144], + [3105, 3143], + [3117, 3157], + [3129, 3155], + [3137, 3167], + [3152, 3177], + [3160, 3187], + [3172, 3204], + [3174, 3195], + [3179, 3217], + [3197, 3225], + [3189, 3217], + [3203, 3217], + [3199, 3202], + [3186, 3188], + [3186, 3174], + [3174, 3166], + [3165, 3145], + [3168, 3143], + [3159, 3143], + [3151, 3118], + [3154, 3107], + [3165, 3110], + [3174, 3105], + [3175, 3082], + [3186, 3076], + [3178, 3089], + [3183, 3103], + [3196, 3116], + [3181, 3105], + [3180, 3111], + [3155, 3111], + [3173, 3130], + [3179, 3150], + [3197, 3170], + [3199, 3178], + [3216, 3190], + [3214, 3203], + [3235, 3219], + [3243, 3212], + [3244, 3198], + [3246, 3208], + [3244, 3219], + [3236, 3240], + [3237, 3249], + [3248, 3262], + [3263, 3267], + [3327, 3313], + [3338, 3327], + [3340, 3340], + [3351, 3349], + [3353, 3361], + [3345, 3365], + [3355, 3387], + [3363, 3392], + [3364, 3401], + [3375, 3413], + [3382, 3421], + [3394, 3431], + [3404, 3433], + [3398, 3416], + [3406, 3433], + [3409, 3422], + [3428, 3400], + [3423, 3392], + [3446, 3377], + [3461, 3366], + [3495, 3354], + [3506, 3343], + [3506, 3334], + [3495, 3338], + [3505, 3332], + [3503, 3323], + [3511, 3316], + [3512, 3303], + [3502, 3302], + [3513, 3296], + [3509, 3286], + [3517, 3283], + [3525, 3277], + [3528, 3269], + [3526, 3277], + [3526, 3287], + [3517, 3288], + [3518, 3301], + [3515, 3313], + [3508, 3329], + [3517, 3333], + [3522, 3341], + [3534, 3344], + [3547, 3333], + [3549, 3323], + [3561, 3314], + [3565, 3302], + [3576, 3301], + [3573, 3314], + [3568, 3329], + [3559, 3348], + [3543, 3341], + [3547, 3362], + [3563, 3362], + [3573, 3327], + [3576, 3309], + [3583, 3292], + [3594, 3256], + [3611, 3205], + [3599, 3181], + [3585, 3172], + [3574, 3167], + [3583, 3176], + [3597, 3193], + [3583, 3184], + [3583, 3192], + [3583, 3200], + [3576, 3188], + [3575, 3198], + [3573, 3190], + [3557, 3197], + [3565, 3205], + [3564, 3211], + [3564, 3224], + [3563, 3233], + [3565, 3245], + [3555, 3240], + [3564, 3226], + [3558, 3218], + [3558, 3210], + [3549, 3208], + [3557, 3202], + [3540, 3186], + [3539, 3195], + [3540, 3204], + [3532, 3198], + [3530, 3209], + [3528, 3222], + [3516, 3220], + [3515, 3235], + [3503, 3239], + [3503, 3241], + [3495, 3241], + [3497, 3249], + [3489, 3260], + [3478, 3271], + [3477, 3281], + [3478, 3272], + [3482, 3253], + [3470, 3248], + [3481, 3245], + [3488, 3230], + [3496, 3232], + [3509, 3221], + [3515, 3199], + [3502, 3197], + [3493, 3189], + [3488, 3181], + [3478, 3174], + [3470, 3185], + [3474, 3172], + [3470, 3162], + [3461, 3170], + [3452, 3169], + [3449, 3160], + [3464, 3158], + [3456, 3146], + [3464, 3154], + [3476, 3153], + [3470, 3145], + [3488, 3161], + [3504, 3182], + [3511, 3171], + [3522, 3166], + [3533, 3168], + [3541, 3169], + [3537, 3158], + [3545, 3152], + [3544, 3163], + [3553, 3159], + [3578, 3138], + [3570, 3127], + [3561, 3128], + [3561, 3120], + [3552, 3119], + [3518, 3101], + [3509, 3090], + [3508, 3085], + [3517, 3085], + [3508, 3079], + [3506, 3071], + [3512, 3056], + [3495, 3053], + [3481, 3056], + [3478, 3066], + [3491, 3073], + [3497, 3099], + [3493, 3091], + [3467, 3086], + [3470, 3096], + [3476, 3104], + [3484, 3106], + [3474, 3108], + [3484, 3124], + [3472, 3116], + [3464, 3116], + [3468, 3107], + [3464, 3099], + [3452, 3108], + [3448, 3120], + [3448, 3112], + [3440, 3114], + [3449, 3108], + [3440, 3108], + [3457, 3103], + [3461, 3090], + [3453, 3089], + [3452, 3099], + [3437, 3103], + [3453, 3083], + [3435, 3077], + [3432, 3087], + [3424, 3087], + [3425, 3077], + [3413, 3082], + [3407, 3090], + [3413, 3102], + [3405, 3102], + [3406, 3116], + [3403, 3094], + [3392, 3092], + [3386, 3101], + [3382, 3118], + [3385, 3130], + [3380, 3119], + [3354, 3116], + [3378, 3115], + [3377, 3107], + [3367, 3098], + [3376, 3100], + [3378, 3092], + [3386, 3092], + [3375, 3084], + [3374, 3071], + [3381, 3082], + [3397, 3081], + [3398, 3072], + [3407, 3061], + [3398, 3055], + [3406, 3057], + [3411, 3045], + [3402, 3042], + [3397, 3033], + [3383, 3037], + [3375, 3035], + [3367, 3038], + [3358, 3047], + [3348, 3040], + [3356, 3041], + [3359, 3033], + [3372, 3034], + [3368, 3024], + [3375, 3032], + [3385, 3029], + [3383, 3018], + [3379, 3010], + [3389, 3025], + [3397, 3024], + [3419, 3040], + [3419, 3023], + [3427, 3034], + [3431, 3043], + [3436, 3029], + [3422, 3010], + [3435, 3021], + [3436, 3008], + [3414, 2983], + [3417, 2995], + [3413, 3008], + [3406, 3000], + [3407, 2992], + [3384, 2994], + [3378, 3003], + [3378, 2994], + [3367, 2995], + [3348, 2988], + [3373, 2990], + [3383, 2990], + [3387, 2985], + [3397, 2985], + [3395, 2975], + [3390, 2964], + [3368, 2965], + [3328, 2969], + [3326, 2977], + [3324, 2985], + [3326, 3001], + [3319, 2988], + [3314, 2997], + [3319, 2986], + [3311, 2984], + [3321, 2974], + [3313, 2978], + [3305, 2979], + [3295, 2982], + [3289, 2970], + [3297, 2977], + [3321, 2973], + [3285, 2952], + [3264, 2928], + [3239, 2921], + [3203, 2882], + [3194, 2873], + [3190, 2882], + [3184, 2892], + [3184, 2883], + [3189, 2880], + [3179, 2880], + [3191, 2877], + [3152, 2864], + [3160, 2878], + [3164, 2890], + [3166, 2902], + [3158, 2907], + [3163, 2891], + [3151, 2882], + [3151, 2873], + [3151, 2855], + [3137, 2864], + [3129, 2860], + [3119, 2869], + [3128, 2859], + [3142, 2850], + [3153, 2849], + [3158, 2858], + [3155, 2848], + [3133, 2837], + [3114, 2818], + [3094, 2819], + [3071, 2818], + [3079, 2816], + [3108, 2809], + [3081, 2774], + [3072, 2753], + [3050, 2728], + [3044, 2711], + [3043, 2694], + [3028, 2690], + [3024, 2679], + [2993, 2629], + [2965, 2604], + [2950, 2584], + [2919, 2559], + [2909, 2528], + [2896, 2507], + [2894, 2482], + [2883, 2474], + [2837, 2458], + [2831, 2438], + [2835, 2413], + [2846, 2402], + [2867, 2396], + [2871, 2429], + [2879, 2431], + [2893, 2446], + [2908, 2456], + [2916, 2454], + [2915, 2462], + [2921, 2458], + [2921, 2466], + [2933, 2479], + [2948, 2508], + [2953, 2528], + [2969, 2552], + [2977, 2545], + [2983, 2537], + [3002, 2542], + [3006, 2550], + [2997, 2553], + [2989, 2549], + [2985, 2541], + [2987, 2551], + [2985, 2566], + [2992, 2579], + [3001, 2575], + [3009, 2575], + [3018, 2574], + [3010, 2576], + [3000, 2577], + [3000, 2592], + [3016, 2602], + [3028, 2613], + [3038, 2609], + [3040, 2599], + [3040, 2608], + [3050, 2609], + [3048, 2621], + [3061, 2620], + [3053, 2618], + [3047, 2631], + [3058, 2650], + [3073, 2662], + [3098, 2699], + [3105, 2704], + [3113, 2704], + [3121, 2730], + [3129, 2733], + [3141, 2747], + [3142, 2730], + [3151, 2735], + [3143, 2740], + [3145, 2752], + [3143, 2763], + [3167, 2789], + [3162, 2777], + [3185, 2754], + [3174, 2766], + [3182, 2791], + [3188, 2781], + [3189, 2796], + [3199, 2796], + [3213, 2777], + [3205, 2791], + [3193, 2803], + [3191, 2815], + [3196, 2826], + [3197, 2807], + [3208, 2815], + [3205, 2824], + [3213, 2823], + [3203, 2827], + [3212, 2834], + [3224, 2832], + [3218, 2821], + [3226, 2827], + [3226, 2819], + [3225, 2790], + [3230, 2801], + [3233, 2799], + [3233, 2821], + [3227, 2837], + [3226, 2849], + [3239, 2846], + [3247, 2848], + [3259, 2865], + [3269, 2916], + [3305, 2899], + [3302, 2889], + [3293, 2891], + [3295, 2883], + [3296, 2875], + [3297, 2884], + [3307, 2882], + [3306, 2890], + [3316, 2890], + [3321, 2882], + [3329, 2881], + [3328, 2888], + [3343, 2888], + [3329, 2890], + [3317, 2894], + [3305, 2902], + [3318, 2906], + [3327, 2908], + [3367, 2899], + [3388, 2886], + [3386, 2878], + [3378, 2880], + [3367, 2878], + [3368, 2870], + [3379, 2864], + [3383, 2876], + [3391, 2882], + [3401, 2872], + [3401, 2881], + [3430, 2880], + [3438, 2885], + [3439, 2873], + [3427, 2875], + [3417, 2868], + [3441, 2869], + [3442, 2853], + [3437, 2832], + [3424, 2828], + [3438, 2827], + [3427, 2825], + [3431, 2815], + [3420, 2824], + [3415, 2836], + [3415, 2825], + [3425, 2816], + [3414, 2817], + [3422, 2811], + [3433, 2808], + [3426, 2794], + [3408, 2799], + [3425, 2803], + [3395, 2803], + [3389, 2816], + [3394, 2802], + [3380, 2796], + [3381, 2807], + [3370, 2802], + [3365, 2812], + [3370, 2816], + [3362, 2816], + [3368, 2825], + [3359, 2823], + [3350, 2818], + [3348, 2835], + [3356, 2846], + [3345, 2833], + [3336, 2843], + [3328, 2844], + [3318, 2847], + [3329, 2841], + [3338, 2831], + [3336, 2816], + [3327, 2813], + [3319, 2815], + [3328, 2808], + [3337, 2808], + [3355, 2808], + [3359, 2799], + [3343, 2801], + [3352, 2795], + [3346, 2790], + [3356, 2790], + [3367, 2791], + [3353, 2779], + [3349, 2783], + [3340, 2783], + [3331, 2793], + [3319, 2783], + [3295, 2799], + [3299, 2791], + [3319, 2780], + [3315, 2769], + [3306, 2770], + [3310, 2751], + [3300, 2746], + [3301, 2738], + [3313, 2746], + [3317, 2758], + [3317, 2767], + [3323, 2777], + [3331, 2776], + [3345, 2775], + [3336, 2774], + [3343, 2760], + [3351, 2762], + [3356, 2762], + [3356, 2748], + [3363, 2757], + [3363, 2768], + [3367, 2776], + [3375, 2776], + [3370, 2758], + [3381, 2774], + [3391, 2778], + [3399, 2779], + [3407, 2772], + [3400, 2764], + [3398, 2753], + [3402, 2744], + [3385, 2729], + [3373, 2717], + [3358, 2695], + [3357, 2704], + [3360, 2719], + [3350, 2715], + [3352, 2705], + [3338, 2709], + [3335, 2701], + [3327, 2696], + [3317, 2706], + [3309, 2704], + [3294, 2708], + [3303, 2699], + [3295, 2693], + [3297, 2680], + [3301, 2683], + [3301, 2691], + [3306, 2699], + [3319, 2697], + [3322, 2681], + [3324, 2671], + [3328, 2667], + [3328, 2659], + [3327, 2648], + [3315, 2651], + [3312, 2643], + [3300, 2645], + [3292, 2633], + [3278, 2629], + [3289, 2630], + [3285, 2621], + [3284, 2608], + [3294, 2620], + [3307, 2636], + [3316, 2629], + [3320, 2641], + [3329, 2640], + [3337, 2639], + [3341, 2653], + [3350, 2655], + [3349, 2660], + [3349, 2669], + [3381, 2667], + [3390, 2680], + [3401, 2691], + [3411, 2689], + [3408, 2679], + [3397, 2670], + [3399, 2644], + [3391, 2648], + [3394, 2640], + [3385, 2640], + [3389, 2631], + [3397, 2636], + [3401, 2628], + [3399, 2616], + [3375, 2612], + [3364, 2627], + [3371, 2610], + [3353, 2606], + [3329, 2611], + [3346, 2599], + [3334, 2590], + [3347, 2592], + [3346, 2578], + [3338, 2569], + [3350, 2570], + [3354, 2559], + [3344, 2544], + [3359, 2538], + [3360, 2531], + [3370, 2531], + [3367, 2539], + [3356, 2542], + [3361, 2560], + [3364, 2573], + [3354, 2580], + [3360, 2593], + [3377, 2597], + [3384, 2589], + [3394, 2599], + [3405, 2601], + [3418, 2599], + [3399, 2582], + [3407, 2577], + [3400, 2559], + [3409, 2572], + [3410, 2581], + [3421, 2585], + [3426, 2574], + [3420, 2588], + [3432, 2583], + [3429, 2592], + [3425, 2602], + [3428, 2615], + [3436, 2615], + [3428, 2619], + [3427, 2630], + [3437, 2630], + [3434, 2639], + [3434, 2650], + [3442, 2658], + [3452, 2649], + [3444, 2661], + [3453, 2665], + [3457, 2656], + [3454, 2664], + [3465, 2667], + [3468, 2659], + [3466, 2670], + [3470, 2679], + [3482, 2674], + [3480, 2684], + [3489, 2685], + [3498, 2687], + [3491, 2678], + [3501, 2679], + [3505, 2668], + [3507, 2653], + [3500, 2643], + [3493, 2633], + [3485, 2636], + [3494, 2632], + [3485, 2629], + [3488, 2619], + [3496, 2614], + [3493, 2603], + [3478, 2605], + [3479, 2595], + [3470, 2593], + [3472, 2582], + [3470, 2565], + [3479, 2559], + [3482, 2550], + [3474, 2548], + [3482, 2547], + [3490, 2542], + [3487, 2557], + [3478, 2571], + [3477, 2584], + [3484, 2594], + [3492, 2596], + [3500, 2582], + [3497, 2593], + [3501, 2602], + [3512, 2604], + [3516, 2596], + [3520, 2587], + [3530, 2577], + [3523, 2591], + [3523, 2600], + [3514, 2604], + [3516, 2612], + [3500, 2627], + [3512, 2629], + [3511, 2637], + [3519, 2635], + [3518, 2644], + [3533, 2642], + [3519, 2654], + [3532, 2657], + [3524, 2660], + [3526, 2670], + [3518, 2669], + [3518, 2677], + [3516, 2689], + [3514, 2701], + [3525, 2717], + [3533, 2718], + [3538, 2726], + [3540, 2737], + [3549, 2734], + [3560, 2720], + [3567, 2728], + [3556, 2732], + [3559, 2742], + [3551, 2739], + [3558, 2764], + [3570, 2767], + [3570, 2759], + [3579, 2759], + [3571, 2766], + [3583, 2774], + [3594, 2769], + [3594, 2783], + [3603, 2800], + [3609, 2787], + [3610, 2762], + [3601, 2769], + [3598, 2765], + [3598, 2754], + [3596, 2738], + [3597, 2748], + [3609, 2748], + [3606, 2732], + [3598, 2725], + [3609, 2718], + [3600, 2719], + [3599, 2709], + [3589, 2706], + [3579, 2715], + [3581, 2704], + [3577, 2704], + [3569, 2704], + [3563, 2690], + [3553, 2693], + [3544, 2679], + [3554, 2690], + [3562, 2689], + [3570, 2697], + [3580, 2698], + [3592, 2702], + [3604, 2698], + [3607, 2688], + [3608, 2700], + [3621, 2697], + [3619, 2711], + [3632, 2698], + [3629, 2685], + [3631, 2677], + [3619, 2676], + [3610, 2682], + [3605, 2673], + [3593, 2678], + [3585, 2668], + [3601, 2672], + [3599, 2660], + [3608, 2672], + [3609, 2657], + [3600, 2652], + [3613, 2660], + [3622, 2669], + [3630, 2671], + [3642, 2673], + [3633, 2684], + [3644, 2679], + [3645, 2653], + [3637, 2654], + [3620, 2651], + [3615, 2641], + [3627, 2650], + [3635, 2650], + [3630, 2638], + [3632, 2623], + [3642, 2619], + [3635, 2561], + [3624, 2537], + [3622, 2551], + [3620, 2541], + [3615, 2550], + [3608, 2558], + [3607, 2528], + [3617, 2529], + [3600, 2513], + [3595, 2527], + [3601, 2539], + [3589, 2554], + [3590, 2542], + [3589, 2534], + [3586, 2522], + [3563, 2523], + [3562, 2531], + [3554, 2543], + [3554, 2531], + [3561, 2522], + [3550, 2519], + [3544, 2527], + [3548, 2517], + [3560, 2518], + [3568, 2519], + [3581, 2516], + [3585, 2503], + [3598, 2501], + [3573, 2481], + [3565, 2490], + [3554, 2492], + [3563, 2484], + [3568, 2474], + [3547, 2476], + [3526, 2474], + [3517, 2477], + [3507, 2479], + [3493, 2475], + [3484, 2471], + [3495, 2474], + [3508, 2477], + [3508, 2468], + [3517, 2474], + [3523, 2466], + [3518, 2443], + [3497, 2443], + [3489, 2439], + [3480, 2421], + [3481, 2410], + [3467, 2413], + [3459, 2408], + [3447, 2407], + [3437, 2399], + [3424, 2400], + [3428, 2409], + [3430, 2421], + [3427, 2413], + [3419, 2411], + [3418, 2396], + [3411, 2409], + [3414, 2422], + [3402, 2436], + [3387, 2439], + [3376, 2431], + [3361, 2432], + [3347, 2423], + [3317, 2429], + [3334, 2417], + [3329, 2401], + [3311, 2404], + [3301, 2397], + [3301, 2387], + [3293, 2389], + [3283, 2383], + [3271, 2387], + [3268, 2395], + [3272, 2377], + [3260, 2365], + [3249, 2364], + [3240, 2366], + [3231, 2347], + [3222, 2347], + [3209, 2346], + [3212, 2334], + [3204, 2330], + [3200, 2350], + [3190, 2349], + [3184, 2339], + [3170, 2340], + [3166, 2332], + [3155, 2322], + [3161, 2311], + [3147, 2306], + [3142, 2291], + [3149, 2303], + [3166, 2307], + [3174, 2317], + [3169, 2327], + [3182, 2330], + [3196, 2339], + [3195, 2331], + [3201, 2325], + [3211, 2325], + [3218, 2331], + [3218, 2339], + [3233, 2339], + [3243, 2357], + [3256, 2355], + [3254, 2340], + [3262, 2343], + [3268, 2359], + [3277, 2353], + [3278, 2366], + [3280, 2378], + [3291, 2381], + [3308, 2374], + [3319, 2387], + [3335, 2392], + [3342, 2407], + [3350, 2407], + [3359, 2413], + [3359, 2404], + [3369, 2396], + [3380, 2397], + [3385, 2406], + [3390, 2428], + [3402, 2421], + [3397, 2410], + [3400, 2382], + [3401, 2384], + [3401, 2407], + [3402, 2412], + [3402, 2398], + [3411, 2376], + [3422, 2375], + [3434, 2386], + [3430, 2378], + [3432, 2369], + [3444, 2362], + [3432, 2371], + [3435, 2379], + [3464, 2378], + [3479, 2387], + [3491, 2382], + [3502, 2383], + [3510, 2380], + [3513, 2371], + [3522, 2373], + [3524, 2403], + [3528, 2369], + [3517, 2371], + [3509, 2367], + [3509, 2357], + [3515, 2366], + [3524, 2364], + [3518, 2353], + [3531, 2364], + [3533, 2352], + [3537, 2363], + [3546, 2366], + [3554, 2363], + [3554, 2355], + [3566, 2354], + [3571, 2344], + [3598, 2233], + [3579, 2200], + [3566, 2194], + [3546, 2192], + [3554, 2193], + [3554, 2207], + [3543, 2208], + [3541, 2217], + [3520, 2210], + [3488, 2216], + [3485, 2205], + [3477, 2200], + [3467, 2190], + [3481, 2203], + [3496, 2201], + [3499, 2209], + [3511, 2200], + [3522, 2207], + [3520, 2190], + [3520, 2178], + [3511, 2168], + [3505, 2180], + [3505, 2172], + [3492, 2171], + [3473, 2167], + [3486, 2168], + [3498, 2168], + [3510, 2164], + [3517, 2152], + [3514, 2147], + [3506, 2147], + [3500, 2156], + [3506, 2143], + [3495, 2141], + [3488, 2153], + [3487, 2145], + [3494, 2137], + [3485, 2140], + [3485, 2133], + [3476, 2133], + [3486, 2128], + [3475, 2121], + [3471, 2117], + [3460, 2117], + [3472, 2115], + [3472, 2106], + [3473, 2119], + [3482, 2117], + [3484, 2125], + [3496, 2124], + [3497, 2132], + [3505, 2134], + [3503, 2123], + [3509, 2134], + [3513, 2126], + [3518, 2128], + [3518, 2137], + [3526, 2132], + [3519, 2115], + [3509, 2110], + [3498, 2108], + [3498, 2096], + [3492, 2101], + [3481, 2101], + [3491, 2098], + [3496, 2087], + [3487, 2088], + [3495, 2081], + [3482, 2070], + [3496, 2080], + [3500, 2065], + [3490, 2056], + [3500, 2056], + [3508, 2059], + [3506, 2067], + [3498, 2076], + [3498, 2091], + [3507, 2088], + [3505, 2097], + [3517, 2100], + [3519, 2092], + [3518, 2103], + [3527, 2108], + [3526, 2093], + [3538, 2092], + [3534, 2100], + [3542, 2105], + [3550, 2110], + [3544, 2102], + [3549, 2090], + [3540, 2077], + [3549, 2082], + [3552, 2090], + [3557, 2103], + [3566, 2086], + [3561, 2073], + [3556, 2064], + [3552, 2066], + [3552, 2051], + [3542, 2053], + [3533, 2049], + [3543, 2051], + [3537, 2042], + [3540, 2034], + [3531, 2029], + [3522, 2028], + [3513, 2035], + [3525, 2023], + [3536, 2025], + [3526, 2013], + [3512, 2006], + [3508, 2017], + [3500, 2020], + [3508, 2012], + [3516, 2003], + [3502, 1994], + [3514, 1989], + [3517, 1983], + [3517, 1975], + [3516, 1967], + [3508, 1962], + [3517, 1962], + [3519, 1973], + [3516, 1997], + [3527, 2002], + [3536, 2003], + [3534, 2011], + [3549, 2017], + [3558, 2026], + [3556, 2007], + [3548, 2004], + [3545, 1994], + [3553, 1978], + [3544, 1966], + [3535, 1967], + [3531, 1959], + [3539, 1959], + [3555, 1966], + [3555, 1944], + [3542, 1942], + [3560, 1943], + [3571, 1931], + [3581, 1927], + [3586, 1940], + [3590, 1931], + [3574, 1929], + [3560, 1921], + [3555, 1932], + [3539, 1935], + [3546, 1927], + [3538, 1924], + [3544, 1916], + [3530, 1914], + [3520, 1913], + [3512, 1913], + [3508, 1903], + [3496, 1897], + [3485, 1904], + [3490, 1895], + [3503, 1892], + [3512, 1906], + [3527, 1911], + [3541, 1909], + [3551, 1914], + [3552, 1905], + [3538, 1895], + [3556, 1904], + [3558, 1878], + [3548, 1878], + [3539, 1878], + [3528, 1875], + [3518, 1870], + [3529, 1872], + [3525, 1861], + [3541, 1869], + [3551, 1872], + [3559, 1857], + [3543, 1861], + [3539, 1851], + [3534, 1838], + [3521, 1847], + [3531, 1841], + [3522, 1837], + [3532, 1837], + [3525, 1826], + [3528, 1818], + [3518, 1812], + [3505, 1820], + [3497, 1818], + [3510, 1825], + [3502, 1840], + [3504, 1829], + [3491, 1826], + [3490, 1814], + [3483, 1826], + [3471, 1841], + [3473, 1833], + [3473, 1823], + [3481, 1813], + [3472, 1818], + [3459, 1816], + [3453, 1810], + [3453, 1818], + [3445, 1815], + [3436, 1822], + [3432, 1812], + [3454, 1807], + [3465, 1806], + [3460, 1795], + [3454, 1784], + [3445, 1790], + [3443, 1781], + [3434, 1784], + [3423, 1781], + [3431, 1775], + [3418, 1777], + [3400, 1769], + [3402, 1777], + [3390, 1773], + [3379, 1765], + [3370, 1766], + [3364, 1753], + [3375, 1755], + [3386, 1766], + [3395, 1767], + [3408, 1765], + [3418, 1770], + [3434, 1766], + [3437, 1758], + [3443, 1767], + [3439, 1776], + [3448, 1779], + [3458, 1777], + [3469, 1784], + [3472, 1779], + [3472, 1764], + [3473, 1774], + [3472, 1782], + [3473, 1800], + [3472, 1809], + [3480, 1797], + [3503, 1806], + [3499, 1791], + [3509, 1789], + [3506, 1802], + [3527, 1796], + [3532, 1808], + [3543, 1798], + [3551, 1795], + [3540, 1804], + [3548, 1807], + [3541, 1825], + [3547, 1827], + [3547, 1842], + [3547, 1823], + [3559, 1807], + [3555, 1819], + [3553, 1829], + [3554, 1837], + [3564, 1837], + [3568, 1825], + [3572, 1834], + [3580, 1837], + [3575, 1839], + [3575, 1849], + [3583, 1859], + [3593, 1858], + [3593, 1842], + [3597, 1834], + [3589, 1831], + [3582, 1821], + [3590, 1826], + [3593, 1810], + [3585, 1807], + [3584, 1796], + [3593, 1793], + [3591, 1801], + [3605, 1804], + [3595, 1812], + [3597, 1821], + [3598, 1829], + [3606, 1819], + [3615, 1815], + [3611, 1825], + [3619, 1822], + [3614, 1831], + [3605, 1826], + [3612, 1836], + [3604, 1831], + [3602, 1839], + [3607, 1854], + [3603, 1864], + [3595, 1865], + [3597, 1875], + [3606, 1874], + [3619, 1866], + [3616, 1855], + [3624, 1858], + [3621, 1847], + [3623, 1839], + [3628, 1848], + [3639, 1835], + [3641, 1811], + [3632, 1816], + [3642, 1807], + [3626, 1806], + [3634, 1802], + [3644, 1801], + [3660, 1733], + [3651, 1755], + [3640, 1770], + [3643, 1762], + [3646, 1752], + [3644, 1740], + [3638, 1751], + [3630, 1748], + [3637, 1744], + [3637, 1734], + [3626, 1738], + [3605, 1744], + [3608, 1756], + [3619, 1757], + [3618, 1767], + [3608, 1758], + [3609, 1770], + [3605, 1754], + [3600, 1771], + [3592, 1766], + [3596, 1758], + [3600, 1737], + [3588, 1746], + [3591, 1736], + [3579, 1738], + [3565, 1734], + [3573, 1729], + [3561, 1717], + [3552, 1723], + [3559, 1714], + [3555, 1704], + [3547, 1696], + [3538, 1694], + [3548, 1694], + [3553, 1685], + [3550, 1694], + [3556, 1702], + [3567, 1698], + [3559, 1708], + [3563, 1717], + [3576, 1713], + [3577, 1722], + [3583, 1732], + [3600, 1729], + [3592, 1713], + [3597, 1722], + [3605, 1734], + [3615, 1732], + [3618, 1724], + [3604, 1710], + [3599, 1702], + [3613, 1714], + [3621, 1712], + [3620, 1721], + [3631, 1723], + [3640, 1723], + [3648, 1728], + [3661, 1732], + [3640, 1721], + [3619, 1694], + [3516, 1632], + [3453, 1610], + [3456, 1619], + [3458, 1628], + [3449, 1613], + [3446, 1622], + [3441, 1634], + [3455, 1642], + [3446, 1647], + [3449, 1661], + [3438, 1671], + [3449, 1673], + [3456, 1682], + [3444, 1688], + [3453, 1680], + [3440, 1676], + [3430, 1676], + [3446, 1660], + [3440, 1652], + [3438, 1642], + [3430, 1645], + [3438, 1641], + [3422, 1639], + [3422, 1631], + [3442, 1621], + [3426, 1621], + [3428, 1616], + [3436, 1616], + [3445, 1610], + [3421, 1602], + [3420, 1611], + [3420, 1601], + [3403, 1594], + [3406, 1602], + [3404, 1611], + [3396, 1622], + [3403, 1632], + [3398, 1624], + [3387, 1616], + [3395, 1616], + [3397, 1608], + [3389, 1608], + [3389, 1599], + [3403, 1593], + [3385, 1573], + [3377, 1568], + [3373, 1581], + [3377, 1589], + [3374, 1593], + [3374, 1585], + [3372, 1576], + [3363, 1572], + [3356, 1582], + [3358, 1573], + [3366, 1567], + [3359, 1554], + [3350, 1562], + [3334, 1554], + [3341, 1563], + [3341, 1588], + [3323, 1598], + [3317, 1588], + [3307, 1601], + [3315, 1612], + [3305, 1605], + [3305, 1615], + [3300, 1624], + [3305, 1626], + [3305, 1644], + [3296, 1645], + [3286, 1656], + [3295, 1648], + [3301, 1638], + [3297, 1627], + [3299, 1612], + [3287, 1608], + [3275, 1617], + [3290, 1604], + [3303, 1608], + [3304, 1598], + [3315, 1583], + [3303, 1587], + [3313, 1579], + [3325, 1582], + [3331, 1566], + [3315, 1569], + [3318, 1558], + [3310, 1561], + [3312, 1552], + [3300, 1550], + [3296, 1562], + [3292, 1552], + [3281, 1551], + [3282, 1562], + [3274, 1565], + [3269, 1575], + [3272, 1565], + [3263, 1568], + [3264, 1565], + [3255, 1565], + [3269, 1563], + [3277, 1562], + [3275, 1546], + [3265, 1547], + [3264, 1537], + [3274, 1542], + [3284, 1546], + [3288, 1536], + [3293, 1547], + [3297, 1537], + [3308, 1543], + [3318, 1541], + [3298, 1531], + [3306, 1526], + [3301, 1514], + [3313, 1516], + [3311, 1527], + [3322, 1526], + [3327, 1535], + [3331, 1535], + [3331, 1520], + [3323, 1520], + [3314, 1511], + [3306, 1510], + [3320, 1504], + [3276, 1492], + [3255, 1480], + [3224, 1481], + [3240, 1492], + [3224, 1490], + [3224, 1499], + [3222, 1507], + [3231, 1504], + [3231, 1516], + [3223, 1522], + [3239, 1524], + [3230, 1526], + [3222, 1526], + [3218, 1537], + [3220, 1545], + [3224, 1555], + [3225, 1569], + [3217, 1558], + [3215, 1549], + [3219, 1541], + [3206, 1544], + [3212, 1535], + [3211, 1527], + [3218, 1517], + [3205, 1514], + [3198, 1522], + [3186, 1524], + [3176, 1531], + [3182, 1522], + [3185, 1516], + [3193, 1516], + [3204, 1509], + [3202, 1501], + [3214, 1507], + [3211, 1491], + [3199, 1493], + [3190, 1503], + [3193, 1495], + [3196, 1484], + [3188, 1481], + [3180, 1486], + [3173, 1482], + [3173, 1498], + [3160, 1504], + [3156, 1514], + [3143, 1524], + [3154, 1514], + [3158, 1505], + [3170, 1495], + [3167, 1483], + [3161, 1481], + [3169, 1481], + [3168, 1473], + [3158, 1468], + [3150, 1466], + [3158, 1465], + [3171, 1475], + [3181, 1477], + [3177, 1469], + [3186, 1476], + [3194, 1476], + [3205, 1475], + [3202, 1457], + [3194, 1451], + [3190, 1460], + [3192, 1450], + [3184, 1454], + [3183, 1446], + [3171, 1440], + [3185, 1439], + [3193, 1446], + [3190, 1436], + [3188, 1426], + [3190, 1414], + [3194, 1425], + [3199, 1436], + [3204, 1448], + [3208, 1457], + [3220, 1459], + [3217, 1447], + [3235, 1444], + [3244, 1445], + [3227, 1412], + [3223, 1389], + [3186, 1367], + [3158, 1353], + [3158, 1372], + [3147, 1369], + [3145, 1383], + [3143, 1375], + [3150, 1363], + [3158, 1350], + [3136, 1332], + [3138, 1340], + [3132, 1337], + [3132, 1346], + [3128, 1336], + [3117, 1348], + [3118, 1340], + [3127, 1336], + [3135, 1332], + [3126, 1320], + [3109, 1322], + [3109, 1331], + [3105, 1319], + [3106, 1311], + [3108, 1321], + [3120, 1317], + [3116, 1308], + [3126, 1318], + [3126, 1309], + [3130, 1320], + [3125, 1288], + [3113, 1271], + [3115, 1255], + [3090, 1247], + [3072, 1252], + [3071, 1265], + [3084, 1266], + [3084, 1297], + [3074, 1305], + [3083, 1300], + [3083, 1308], + [3080, 1324], + [3078, 1335], + [3066, 1334], + [3063, 1342], + [3065, 1357], + [3059, 1348], + [3047, 1347], + [3046, 1355], + [3046, 1344], + [3023, 1344], + [3034, 1343], + [3052, 1344], + [3049, 1336], + [3061, 1333], + [3069, 1328], + [3071, 1320], + [3071, 1303], + [3066, 1293], + [3056, 1295], + [3057, 1306], + [3043, 1309], + [3054, 1297], + [3042, 1300], + [3055, 1292], + [3057, 1286], + [3043, 1286], + [3056, 1282], + [3048, 1278], + [3036, 1255], + [3025, 1249], + [3008, 1240], + [3003, 1234], + [2984, 1234], + [2981, 1253], + [2954, 1274], + [2977, 1258], + [2984, 1267], + [2971, 1269], + [2980, 1273], + [2975, 1286], + [2988, 1280], + [2990, 1289], + [3007, 1293], + [2995, 1291], + [2993, 1302], + [2992, 1293], + [2982, 1289], + [2984, 1297], + [2970, 1288], + [2968, 1277], + [2965, 1291], + [2964, 1300], + [2976, 1304], + [2975, 1319], + [2971, 1331], + [2965, 1340], + [2957, 1342], + [2942, 1338], + [2938, 1353], + [2949, 1368], + [2953, 1376], + [2962, 1390], + [2972, 1389], + [2983, 1398], + [2986, 1407], + [2994, 1410], + [2983, 1409], + [2975, 1396], + [2950, 1384], + [2939, 1386], + [2950, 1380], + [2934, 1360], + [2931, 1351], + [2932, 1343], + [2921, 1341], + [2906, 1338], + [2937, 1337], + [2942, 1329], + [2953, 1332], + [2959, 1323], + [2948, 1315], + [2961, 1320], + [2952, 1311], + [2953, 1294], + [2930, 1282], + [2923, 1291], + [2929, 1281], + [2920, 1277], + [2917, 1265], + [2909, 1258], + [2898, 1255], + [2889, 1265], + [2898, 1246], + [2885, 1237], + [2883, 1246], + [2875, 1243], + [2879, 1246], + [2879, 1238], + [2876, 1222], + [2840, 1217], + [2804, 1226], + [2783, 1227], + [2760, 1220], + [2754, 1212], + [2728, 1209], + [2688, 1174], + [2681, 1194], + [2673, 1197], + [2666, 1212], + [2663, 1197], + [2669, 1197], + [2669, 1189], + [2675, 1178], + [2684, 1170], + [2670, 1160], + [2640, 1155], + [2619, 1142], + [2609, 1149], + [2596, 1150], + [2587, 1147], + [2583, 1137], + [2576, 1144], + [2576, 1153], + [2568, 1157], + [2561, 1149], + [2544, 1154], + [2534, 1161], + [2525, 1161], + [2538, 1160], + [2539, 1150], + [2558, 1148], + [2567, 1145], + [2572, 1136], + [2585, 1123], + [2602, 1137], + [2603, 1126], + [2597, 1111], + [2598, 1102], + [2589, 1101], + [2590, 1093], + [2591, 1082], + [2593, 1069], + [2585, 1072], + [2583, 1080], + [2574, 1074], + [2583, 1076], + [2591, 1062], + [2601, 1074], + [2601, 1082], + [2602, 1093], + [2600, 1104], + [2609, 1098], + [2611, 1080], + [2604, 1054], + [2578, 1023], + [2544, 1023], + [2530, 1027], + [2529, 1033], + [2505, 1033], + [2526, 1027], + [2535, 1019], + [2537, 1012], + [2546, 1012], + [2523, 975], + [2515, 980], + [2511, 969], + [2506, 953], + [2486, 957], + [2472, 945], + [2457, 942], + [2456, 933], + [2465, 935], + [2463, 918], + [2463, 902], + [2474, 931], + [2486, 931], + [2492, 938], + [2502, 938], + [2515, 931], + [2518, 918], + [2527, 912], + [2524, 896], + [2528, 864], + [2525, 842], + [2488, 787], + [2467, 794], + [2447, 827], + [2432, 843], + [2412, 850], + [2395, 845], + [2373, 849], + [2348, 848], + [2317, 884], + [2289, 897], + [2251, 898], + [2196, 916], + [2162, 913], + [2141, 901], + [2129, 864], + [2117, 844], + [2086, 819], + [2090, 808], + [2087, 796], + [2095, 793], + [2084, 755], + [2078, 716], + [2073, 707], + [2079, 661], + [2097, 610], + [2112, 596], + [2108, 580], + [2133, 565], + [2136, 550], + [2127, 550], + [2142, 539], + [2146, 514], + [2174, 488], + [2166, 472], + [2162, 452], + [2165, 443], + [2173, 447], + [2190, 428], + [2257, 380], + [2270, 380], + [2282, 415], + [2269, 444], + [2243, 473], + [2247, 483], + [2256, 486], + [2277, 475], + [2272, 467], + [2281, 454], + [2288, 462], + [2299, 446], + [2312, 443], + [2314, 434], + [2326, 435], + [2337, 425], + [2345, 427], + [2350, 438], + [2341, 439], + [2334, 447], + [2325, 442], + [2315, 455], + [2301, 455], + [2305, 466], + [2299, 480], + [2285, 473], + [2286, 484], + [2274, 492], + [2266, 487], + [2260, 498], + [2234, 498], + [2205, 503], + [2190, 534], + [2196, 523], + [2209, 514], + [2217, 518], + [2217, 509], + [2220, 518], + [2210, 523], + [2215, 533], + [2201, 541], + [2191, 547], + [2177, 554], + [2174, 569], + [2165, 580], + [2149, 636], + [2162, 651], + [2163, 659], + [2155, 668], + [2166, 690], + [2162, 707], + [2175, 728], + [2162, 757], + [2188, 823], + [2234, 856], + [2250, 861], + [2278, 852], + [2296, 836], + [2308, 833], + [2320, 821], + [2351, 803], + [2364, 785], + [2368, 768], + [2395, 776], + [2415, 773], + [2437, 742], + [2447, 739], + [2487, 706], + [2485, 697], + [2471, 699], + [2468, 696], + [2468, 704], + [2457, 708], + [2463, 700], + [2464, 692], + [2474, 691], + [2483, 685], + [2490, 664], + [2486, 650], + [2490, 639], + [2506, 627], + [2512, 612], + [2510, 592], + [2517, 611], + [2513, 636], + [2509, 647], + [2501, 645], + [2503, 656], + [2504, 671], + [2511, 685], + [2520, 693], + [2546, 745], + [2550, 768], + [2559, 790], + [2568, 799], + [2568, 813], + [2573, 857], + [2585, 874], + [2585, 886], + [2580, 896], + [2596, 896], + [2625, 914], + [2618, 901], + [2635, 906], + [2648, 901], + [2637, 910], + [2634, 919], + [2651, 931], + [2658, 943], + [2677, 950], + [2686, 930], + [2680, 950], + [2685, 960], + [2703, 960], + [2688, 962], + [2704, 982], + [2694, 977], + [2680, 969], + [2678, 960], + [2662, 950], + [2656, 983], + [2659, 992], + [2683, 994], + [2731, 1023], + [2717, 1013], + [2716, 994], + [2718, 1012], + [2730, 1020], + [2738, 1019], + [2748, 1027], + [2744, 1019], + [2753, 1024], + [2767, 1036], + [2778, 1035], + [2841, 1066], + [2856, 1060], + [2849, 1045], + [2856, 1034], + [2855, 1056], + [2872, 1068], + [2855, 1063], + [2860, 1074], + [2869, 1074], + [2876, 1093], + [2870, 1104], + [2878, 1109], + [2887, 1109], + [2902, 1110], + [2911, 1118], + [2920, 1108], + [2922, 1100], + [2909, 1094], + [2898, 1094], + [2894, 1086], + [2892, 1073], + [2897, 1084], + [2903, 1083], + [2903, 1092], + [2913, 1090], + [2922, 1095], + [2942, 1065], + [2934, 1069], + [2940, 1061], + [2933, 1051], + [2925, 1050], + [2915, 1046], + [2924, 1041], + [2933, 1044], + [2946, 1044], + [2947, 1059], + [2955, 1058], + [2955, 1046], + [2967, 1037], + [2959, 1030], + [2941, 1025], + [2958, 1028], + [2956, 1017], + [2948, 1014], + [2960, 1013], + [2961, 999], + [2947, 988], + [2932, 989], + [2938, 981], + [2948, 984], + [2952, 976], + [2952, 966], + [2942, 953], + [2943, 938], + [2948, 940], + [2948, 950], + [2959, 959], + [2962, 973], + [2964, 983], + [2975, 985], + [2975, 994], + [2978, 1001], + [2987, 1001], + [2979, 1002], + [2978, 1016], + [2972, 1025], + [2980, 1031], + [2984, 1042], + [2976, 1052], + [2979, 1063], + [2953, 1082], + [2957, 1097], + [2979, 1096], + [2988, 1084], + [2989, 1071], + [2991, 1055], + [2986, 1047], + [2997, 1046], + [3014, 1049], + [3014, 1040], + [3010, 1036], + [3019, 1036], + [3022, 1045], + [3037, 1051], + [3052, 1042], + [3054, 1033], + [3069, 1031], + [3077, 1024], + [3084, 1012], + [3072, 1007], + [3064, 1006], + [3056, 995], + [3061, 998], + [3071, 998], + [3083, 999], + [3092, 1002], + [3096, 1011], + [3087, 1025], + [3088, 1046], + [3083, 1037], + [3073, 1037], + [3068, 1046], + [3056, 1068], + [3036, 1075], + [3028, 1075], + [3004, 1085], + [3006, 1097], + [3031, 1096], + [3057, 1110], + [3073, 1112], + [3073, 1112], + [3088, 1112], + [3145, 1132], + [3142, 1129], + [3160, 1129], + [3147, 1133], + [3172, 1154], + [3196, 1139], + [3183, 1148], + [3174, 1155], + [3199, 1181], + [3204, 1202], + [3208, 1200], + [3208, 1190], + [3204, 1181], + [3213, 1189], + [3215, 1179], + [3218, 1193], + [3231, 1192], + [3228, 1175], + [3234, 1192], + [3244, 1178], + [3238, 1191], + [3251, 1194], + [3225, 1199], + [3231, 1211], + [3223, 1218], + [3227, 1210], + [3213, 1201], + [3205, 1203], + [3225, 1257], + [3230, 1249], + [3231, 1239], + [3231, 1257], + [3240, 1255], + [3233, 1264], + [3252, 1264], + [3237, 1271], + [3229, 1257], + [3233, 1282], + [3251, 1268], + [3262, 1268], + [3277, 1275], + [3270, 1264], + [3268, 1256], + [3258, 1251], + [3263, 1242], + [3252, 1232], + [3238, 1219], + [3244, 1212], + [3244, 1220], + [3250, 1215], + [3250, 1223], + [3255, 1217], + [3255, 1226], + [3266, 1222], + [3275, 1223], + [3259, 1230], + [3271, 1236], + [3289, 1233], + [3279, 1239], + [3279, 1250], + [3296, 1252], + [3306, 1255], + [3287, 1259], + [3315, 1281], + [3311, 1270], + [3326, 1274], + [3325, 1291], + [3333, 1271], + [3323, 1253], + [3316, 1233], + [3308, 1234], + [3310, 1215], + [3314, 1230], + [3323, 1230], + [3324, 1243], + [3349, 1236], + [3335, 1219], + [3326, 1211], + [3334, 1213], + [3348, 1207], + [3346, 1198], + [3358, 1187], + [3361, 1175], + [3353, 1177], + [3342, 1172], + [3346, 1159], + [3333, 1155], + [3329, 1147], + [3312, 1138], + [3309, 1130], + [3306, 1121], + [3296, 1116], + [3310, 1116], + [3317, 1126], + [3333, 1115], + [3322, 1128], + [3330, 1137], + [3341, 1135], + [3343, 1144], + [3356, 1148], + [3354, 1165], + [3371, 1160], + [3380, 1170], + [3375, 1179], + [3374, 1198], + [3359, 1216], + [3366, 1231], + [3379, 1232], + [3372, 1219], + [3381, 1228], + [3383, 1210], + [3386, 1220], + [3404, 1208], + [3399, 1217], + [3415, 1228], + [3404, 1226], + [3386, 1228], + [3384, 1239], + [3392, 1245], + [3381, 1237], + [3362, 1250], + [3371, 1258], + [3368, 1280], + [3381, 1300], + [3391, 1325], + [3391, 1333], + [3403, 1331], + [3399, 1320], + [3407, 1312], + [3404, 1302], + [3395, 1300], + [3396, 1292], + [3394, 1274], + [3405, 1267], + [3402, 1286], + [3410, 1286], + [3407, 1297], + [3419, 1303], + [3417, 1311], + [3425, 1308], + [3422, 1296], + [3421, 1273], + [3434, 1274], + [3431, 1289], + [3427, 1294], + [3435, 1294], + [3430, 1303], + [3443, 1299], + [3445, 1308], + [3430, 1307], + [3431, 1320], + [3420, 1315], + [3413, 1326], + [3425, 1336], + [3433, 1338], + [3439, 1326], + [3449, 1327], + [3435, 1338], + [3437, 1356], + [3446, 1355], + [3449, 1347], + [3445, 1359], + [3460, 1373], + [3473, 1408], + [3490, 1430], + [3512, 1430], + [3526, 1434], + [3516, 1430], + [3497, 1427], + [3487, 1423], + [3490, 1409], + [3498, 1421], + [3506, 1426], + [3505, 1414], + [3514, 1425], + [3519, 1417], + [3529, 1415], + [3512, 1397], + [3525, 1400], + [3522, 1346], + [3507, 1307], + [3538, 1272], + [3530, 1256], + [3529, 1265], + [3527, 1254], + [3521, 1241], + [3508, 1239], + [3520, 1239], + [3487, 1196], + [3474, 1166], + [3443, 1123], + [3424, 1056], + [3427, 1023], + [3433, 1011], + [3461, 975], + [3422, 956], + [3410, 965], + [3390, 964], + [3395, 930], + [3441, 860], + [3436, 833], + [3449, 814], + [3428, 807], + [3419, 799], + [3400, 761], + [3384, 746], + [3371, 726], + [3348, 709], + [3343, 700], + [3330, 679], + [3319, 668], + [3296, 646], + [3276, 611], + [3251, 537], + [3253, 432], + [3261, 387], + [3255, 379], + [3238, 317], + [3229, 246], + [3211, 256], + [3197, 264], + [3206, 261], + [3207, 252], + [3223, 243], + [3239, 184], + [3217, 176], + [3214, 186], + [3216, 176], + [3204, 169], + [3194, 149], + [3194, 140], + [3185, 139], + [3194, 137], + [3191, 121], + [3190, 103], + [3180, 101], + [3185, 74], + [3185, 89], + [3194, 70], + [3195, 61], + [3188, 42], + [3198, 61], + [3188, 91], + [3197, 99], + [3208, 91], + [3219, 89], + [3206, 84], + [3209, 71], + [3219, 74], + [3216, 83], + [3226, 79], + [3239, 67], + [3223, 69], + [3220, 59], + [3226, 67], + [3236, 66], + [3236, 55], + [3221, 49], + [3234, 50], + [3236, 42], + [3240, 53], + [3262, 40], + [3268, 32], + [3267, 24], + [3280, 14], + [3282, 3], + [3285, -18], + [3292, -32], + [3282, -57], + [3276, -53], + [3276, -45], + [3264, -42], + [3255, -43], + [3267, -47], + [3258, -53], + [3244, -48], + [3235, -52], + [3229, -34], + [3238, -28], + [3254, -20], + [3236, -19], + [3242, -6], + [3233, -10], + [3229, -18], + [3221, -21], + [3211, -17], + [3214, -9], + [3206, -7], + [3202, -16], + [3201, -25], + [3211, -21], + [3199, -38], + [3210, -36], + [3215, -28], + [3222, -40], + [3214, -49], + [3212, -59], + [3223, -48], + [3223, -67], + [3213, -66], + [3214, -75], + [3227, -75], + [3223, -87], + [3232, -75], + [3242, -81], + [3237, -94], + [3244, -74], + [3249, -86], + [3239, -98], + [3242, -111], + [3231, -105], + [3223, -109], + [3218, -100], + [3212, -108], + [3209, -98], + [3201, -98], + [3198, -112], + [3201, -103], + [3213, -112], + [3220, -122], + [3230, -128], + [3238, -121], + [3250, -118], + [3252, -110], + [3257, -122], + [3261, -110], + [3252, -101], + [3263, -87], + [3290, -117], + [3289, -128], + [4224, -128], + [4224, -128], + [3474, -128], + [3475, -116], + [3486, -120], + [3475, -115], + [3473, -89], + [3458, -49], + [3458, -31], + [3469, -26], + [3476, -53], + [3493, -64], + [3507, -62], + [3502, -77], + [3504, -95], + [3507, -75], + [3510, -85], + [3509, -67], + [3523, -78], + [3513, -128], + [3509, -119], + [3509, -128], + [3717, -128], + [3705, -60], + [3718, -44], + [3721, -21], + [3735, -16], + [3727, -13], + [3724, -3], + [3716, 18], + [3714, 38], + [3723, 41], + [3719, 29], + [3727, 30], + [3736, 24], + [3739, 15], + [3754, 13], + [3761, -1], + [3771, -9], + [3765, -1], + [3763, 10], + [3755, 14], + [3764, 18], + [3739, 25], + [3742, 35], + [3725, 50], + [3735, 54], + [3734, 72], + [3742, 70], + [3752, 54], + [3760, 51], + [3768, 50], + [3779, 46], + [3764, 53], + [3748, 66], + [3758, 80], + [3768, 73], + [3758, 88], + [3782, 84], + [3785, 75], + [3794, 67], + [3794, 59], + [3807, 50], + [3815, 56], + [3825, 47], + [3819, 43], + [3819, 25], + [3819, 1], + [3812, -11], + [3821, -7], + [3833, -17], + [3846, -36], + [3859, -51], + [3854, -41], + [3844, -33], + [3837, -19], + [3823, -5], + [3826, 12], + [3835, 8], + [3826, 15], + [3823, 26], + [3829, 39], + [3841, 30], + [3841, 22], + [3850, 20], + [3865, 19], + [3842, 32], + [3831, 46], + [3871, 49], + [3850, 53], + [3840, 53], + [3830, 56], + [3818, 62], + [3827, 67], + [3822, 78], + [3815, 66], + [3807, 66], + [3812, 77], + [3805, 69], + [3796, 77], + [3799, 88], + [3788, 93], + [3793, 101], + [3787, 94], + [3779, 94], + [3779, 106], + [3768, 106], + [3765, 116], + [3777, 114], + [3765, 119], + [3752, 134], + [3751, 142], + [3760, 149], + [3745, 148], + [3750, 137], + [3735, 120], + [3733, 103], + [3724, 99], + [3716, 89], + [3713, 103], + [3706, 91], + [3703, 79], + [3690, 67], + [3681, 69], + [3681, 58], + [3693, 51], + [3685, 49], + [3684, 41], + [3680, 31], + [3692, 40], + [3674, 6], + [3672, 16], + [3667, 5], + [3658, 5], + [3662, 13], + [3651, 19], + [3645, 11], + [3643, -1], + [3641, -14], + [3633, -18], + [3634, -9], + [3623, -8], + [3622, -18], + [3632, -24], + [3630, -34], + [3620, -36], + [3617, -20], + [3614, -28], + [3612, -41], + [3618, -40], + [3618, -55], + [3638, -65], + [3636, -74], + [3598, -35], + [3602, -16], + [3593, -15], + [3587, -5], + [3576, -6], + [3565, 1], + [3557, 13], + [3554, 48], + [3541, 66], + [3542, 74], + [3536, 92], + [3526, 90], + [3531, 104], + [3529, 112], + [3525, 122], + [3521, 114], + [3510, 126], + [3509, 169], + [3513, 178], + [3519, 162], + [3518, 174], + [3518, 191], + [3510, 190], + [3503, 218], + [3506, 231], + [3501, 245], + [3504, 270], + [3511, 284], + [3510, 265], + [3506, 265], + [3506, 254], + [3516, 260], + [3515, 250], + [3524, 263], + [3534, 268], + [3536, 250], + [3528, 245], + [3518, 224], + [3521, 211], + [3527, 200], + [3527, 191], + [3541, 170], + [3549, 171], + [3547, 159], + [3539, 162], + [3530, 160], + [3531, 147], + [3539, 149], + [3539, 138], + [3543, 147], + [3548, 125], + [3542, 117], + [3540, 101], + [3548, 101], + [3549, 81], + [3558, 94], + [3568, 101], + [3574, 92], + [3563, 79], + [3569, 87], + [3581, 89], + [3570, 75], + [3568, 65], + [3568, 55], + [3573, 69], + [3582, 80], + [3582, 71], + [3585, 71], + [3585, 60], + [3588, 73], + [3593, 64], + [3591, 73], + [3588, 82], + [3589, 91], + [3601, 86], + [3602, 72], + [3603, 51], + [3595, 41], + [3586, 42], + [3582, 16], + [3588, 25], + [3590, 38], + [3598, 36], + [3610, 53], + [3610, 42], + [3618, 39], + [3611, 24], + [3626, 20], + [3625, 11], + [3631, 19], + [3618, 30], + [3621, 38], + [3614, 59], + [3616, 74], + [3609, 85], + [3612, 93], + [3602, 99], + [3592, 103], + [3577, 110], + [3569, 125], + [3572, 138], + [3573, 160], + [3576, 162], + [3576, 171], + [3574, 182], + [3570, 193], + [3578, 184], + [3585, 193], + [3594, 199], + [3610, 212], + [3610, 197], + [3603, 199], + [3603, 187], + [3590, 181], + [3582, 172], + [3594, 169], + [3597, 175], + [3597, 166], + [3601, 176], + [3611, 183], + [3616, 173], + [3610, 164], + [3621, 173], + [3634, 162], + [3630, 151], + [3619, 161], + [3611, 159], + [3598, 153], + [3587, 160], + [3594, 148], + [3590, 139], + [3581, 139], + [3583, 119], + [3588, 135], + [3596, 137], + [3597, 128], + [3599, 143], + [3607, 118], + [3605, 147], + [3610, 136], + [3617, 146], + [3619, 138], + [3627, 127], + [3617, 121], + [3614, 111], + [3635, 120], + [3637, 130], + [3633, 137], + [3649, 137], + [3646, 124], + [3644, 114], + [3625, 105], + [3623, 91], + [3623, 78], + [3626, 69], + [3630, 42], + [3636, 54], + [3649, 40], + [3655, 29], + [3656, 45], + [3643, 51], + [3642, 59], + [3633, 62], + [3631, 70], + [3631, 78], + [3646, 71], + [3634, 88], + [3643, 93], + [3642, 102], + [3655, 101], + [3663, 112], + [3669, 97], + [3654, 96], + [3666, 94], + [3662, 80], + [3672, 81], + [3674, 97], + [3683, 88], + [3692, 96], + [3682, 98], + [3687, 111], + [3681, 103], + [3672, 112], + [3682, 122], + [3679, 135], + [3690, 141], + [3695, 150], + [3695, 129], + [3705, 147], + [3715, 161], + [3714, 141], + [3707, 129], + [3715, 126], + [3712, 135], + [3718, 146], + [3720, 136], + [3729, 140], + [3726, 151], + [3725, 173], + [3726, 159], + [3738, 154], + [3730, 162], + [3733, 178], + [3738, 170], + [3733, 185], + [3722, 182], + [3711, 176], + [3708, 186], + [3706, 175], + [3689, 178], + [3689, 186], + [3682, 178], + [3679, 168], + [3671, 156], + [3659, 161], + [3668, 170], + [3669, 186], + [3661, 185], + [3657, 195], + [3658, 206], + [3664, 217], + [3675, 233], + [3675, 209], + [3673, 199], + [3689, 214], + [3695, 203], + [3699, 216], + [3712, 220], + [3710, 204], + [3714, 215], + [3715, 230], + [3707, 229], + [3697, 225], + [3689, 223], + [3696, 233], + [3687, 231], + [3696, 245], + [3692, 253], + [3696, 263], + [3712, 281], + [3642, 370], + [3642, 391], + [3631, 389], + [3633, 400], + [3625, 383], + [3622, 397], + [3613, 397], + [3600, 392], + [3601, 383], + [3589, 367], + [3599, 394], + [3606, 411], + [3627, 407], + [3624, 415], + [3620, 424], + [3609, 432], + [3619, 429], + [3624, 437], + [3616, 436], + [3616, 446], + [3601, 455], + [3596, 473], + [3592, 462], + [3583, 457], + [3585, 448], + [3574, 458], + [3561, 466], + [3570, 472], + [3585, 475], + [3599, 492], + [3605, 507], + [3603, 519], + [3614, 517], + [3617, 509], + [3609, 506], + [3607, 497], + [3604, 483], + [3612, 479], + [3610, 468], + [3610, 458], + [3618, 465], + [3615, 487], + [3622, 489], + [3622, 503], + [3625, 513], + [3633, 513], + [3634, 525], + [3643, 529], + [3641, 517], + [3642, 506], + [3632, 506], + [3642, 498], + [3640, 491], + [3632, 491], + [3628, 482], + [3637, 484], + [3645, 475], + [3637, 470], + [3638, 461], + [3646, 463], + [3635, 427], + [3641, 435], + [3654, 431], + [3652, 420], + [3658, 412], + [3669, 419], + [3659, 417], + [3661, 425], + [3656, 435], + [3645, 439], + [3653, 451], + [3650, 473], + [3660, 475], + [3647, 484], + [3648, 513], + [3652, 510], + [3652, 489], + [3660, 485], + [3657, 493], + [3658, 507], + [3653, 516], + [3661, 512], + [3671, 507], + [3682, 507], + [3681, 498], + [3677, 485], + [3687, 483], + [3680, 473], + [3668, 473], + [3670, 464], + [3667, 454], + [3674, 449], + [3684, 449], + [3684, 436], + [3692, 436], + [3686, 451], + [3675, 456], + [3678, 464], + [3675, 466], + [3687, 466], + [3687, 474], + [3698, 478], + [3702, 474], + [3702, 464], + [3706, 465], + [3706, 457], + [3710, 458], + [3710, 431], + [3713, 446], + [3706, 475], + [3700, 492], + [3708, 487], + [3719, 488], + [3721, 478], + [3723, 487], + [3732, 484], + [3736, 475], + [3745, 469], + [3744, 461], + [3736, 451], + [3737, 436], + [3740, 446], + [3747, 462], + [3759, 449], + [3761, 459], + [3770, 463], + [3786, 462], + [3768, 467], + [3757, 463], + [3747, 485], + [3755, 488], + [3757, 499], + [3752, 491], + [3743, 514], + [3738, 496], + [3729, 499], + [3718, 504], + [3706, 504], + [3694, 514], + [3709, 525], + [3705, 535], + [3713, 536], + [3716, 545], + [3731, 543], + [3746, 546], + [3740, 537], + [3748, 542], + [3747, 534], + [3758, 542], + [3762, 531], + [3761, 539], + [3771, 538], + [3780, 538], + [3781, 530], + [3787, 540], + [3792, 536], + [3792, 525], + [3808, 524], + [3820, 512], + [3810, 527], + [3794, 529], + [3795, 540], + [3796, 548], + [3806, 544], + [3817, 551], + [3826, 549], + [3816, 555], + [3801, 547], + [3798, 568], + [3793, 558], + [3792, 542], + [3775, 547], + [3779, 561], + [3772, 541], + [3764, 548], + [3751, 546], + [3747, 557], + [3760, 559], + [3749, 571], + [3749, 579], + [3754, 588], + [3765, 589], + [3777, 598], + [3768, 595], + [3750, 594], + [3747, 586], + [3737, 591], + [3746, 582], + [3746, 563], + [3742, 551], + [3724, 557], + [3727, 565], + [3721, 555], + [3709, 559], + [3707, 546], + [3697, 548], + [3689, 529], + [3681, 528], + [3685, 543], + [3695, 554], + [3692, 565], + [3698, 577], + [3683, 579], + [3681, 588], + [3677, 569], + [3674, 556], + [3666, 553], + [3659, 562], + [3660, 592], + [3649, 570], + [3652, 561], + [3644, 559], + [3623, 595], + [3633, 616], + [3625, 618], + [3619, 607], + [3606, 612], + [3593, 631], + [3584, 658], + [3592, 673], + [3579, 669], + [3578, 658], + [3570, 657], + [3560, 639], + [3572, 653], + [3580, 650], + [3578, 642], + [3581, 629], + [3582, 640], + [3595, 611], + [3585, 612], + [3583, 604], + [3589, 596], + [3568, 600], + [3553, 608], + [3553, 617], + [3544, 607], + [3527, 604], + [3535, 618], + [3532, 637], + [3521, 626], + [3520, 636], + [3524, 652], + [3538, 675], + [3549, 683], + [3551, 694], + [3565, 709], + [3580, 741], + [3594, 757], + [3599, 778], + [3594, 803], + [3601, 820], + [3609, 833], + [3630, 848], + [3638, 850], + [3649, 873], + [3661, 887], + [3674, 878], + [3666, 852], + [3668, 829], + [3676, 823], + [3667, 805], + [3672, 797], + [3681, 798], + [3690, 807], + [3695, 827], + [3693, 838], + [3688, 853], + [3699, 851], + [3709, 842], + [3720, 856], + [3739, 865], + [3757, 897], + [3755, 905], + [3762, 914], + [3774, 932], + [3761, 933], + [3755, 925], + [3766, 944], + [3775, 945], + [3793, 954], + [3814, 957], + [3813, 970], + [3802, 973], + [3802, 988], + [3788, 1002], + [3788, 1025], + [3766, 1025], + [3789, 1026], + [3839, 1025], + [3789, 1025], + [3791, 1015], + [3804, 1008], + [3826, 1009], + [3814, 998], + [3815, 970], + [3827, 976], + [3834, 964], + [3842, 977], + [3851, 980], + [3837, 988], + [3844, 998], + [3859, 988], + [3864, 999], + [3861, 1008], + [3872, 1009], + [3887, 1009], + [3880, 1024], + [3888, 1023], + [3891, 1034], + [3877, 1045], + [3868, 1043], + [3859, 1052], + [3851, 1046], + [3860, 1059], + [3896, 1062], + [3902, 1080], + [3921, 1107], + [3956, 1127], + [3952, 1100], + [3941, 1079], + [3940, 1068], + [3949, 1033], + [3948, 1025], + [3958, 1019], + [3965, 1008], + [3960, 995], + [3932, 966], + [3917, 964], + [3929, 957], + [3943, 933], + [3979, 912], + [3987, 877], + [3995, 871], + [3988, 862], + [4002, 835], + [4013, 843], + [4043, 850], + [4061, 902], + [4059, 919], + [4058, 928], + [4038, 944], + [3979, 955], + [3992, 967], + [4029, 1023], + [4029, 1023], + [4029, 1037], + [4059, 1062], + [4065, 1076], + [4064, 1087], + [4060, 1076], + [4049, 1096], + [4079, 1089], + [4090, 1072], + [4097, 1072], + [4139, 1072], + [4155, 1105], + [4174, 1105], + [4166, 1086], + [4176, 1075], + [4174, 1065], + [4185, 1057], + [4193, 1052], + [4195, 1064], + [4191, 1078], + [4208, 1098], + [4208, 1106], + [4222, 1110], + [4224, 1109], + [4224, 1144], + [4202, 1158], + [4177, 1161], + [4182, 1181], + [4169, 1152], + [4140, 1163], + [4117, 1177], + [4134, 1177], + [4126, 1181], + [4124, 1189], + [4115, 1194], + [4115, 1178], + [4096, 1179], + [4075, 1201], + [4081, 1215], + [4086, 1216], + [4086, 1205], + [4087, 1214], + [4095, 1216], + [4109, 1227], + [4102, 1242], + [4100, 1231], + [4096, 1234], + [4096, 1244], + [4103, 1254], + [4115, 1249], + [4127, 1259], + [4131, 1250], + [4133, 1258], + [4140, 1245], + [4138, 1256], + [4141, 1275], + [4150, 1271], + [4142, 1271], + [4159, 1255], + [4169, 1255], + [4168, 1246], + [4177, 1245], + [4180, 1259], + [4190, 1271], + [4182, 1272], + [4196, 1281], + [4192, 1267], + [4209, 1270], + [4218, 1267], + [4221, 1249], + [4214, 1230], + [4215, 1215], + [4221, 1223], + [4219, 1231], + [4224, 1243], + [4224, 1257], + [4224, 1262], + [4224, 1345], + [4224, 1339], + [4224, 1328], + [4215, 1335], + [4213, 1346], + [4203, 1355], + [4213, 1357], + [4215, 1369], + [4224, 1363], + [4215, 1377], + [4208, 1387], + [4217, 1401], + [4224, 1403], + [4224, 1520], + [4219, 1535], + [4221, 1544], + [4217, 1553], + [4209, 1549], + [4215, 1558], + [4206, 1559], + [4207, 1580], + [4199, 1593], + [4205, 1605], + [4215, 1604], + [4223, 1595], + [4221, 1611], + [4212, 1608], + [4211, 1618], + [4206, 1626], + [4214, 1625], + [4219, 1637], + [4214, 1648], + [4224, 1645], + [4224, 1640], + [4224, 2108], + [4220, 2125], + [4224, 2125], + [4224, 2143], + [4205, 2141], + [4180, 2159], + [4188, 2155], + [4195, 2165], + [4207, 2164], + [4196, 2172], + [4201, 2182], + [4187, 2168], + [4170, 2169], + [4171, 2181], + [4163, 2189], + [4173, 2188], + [4163, 2194], + [4164, 2202], + [4173, 2196], + [4179, 2205], + [4186, 2196], + [4185, 2205], + [4174, 2208], + [4176, 2229], + [4192, 2223], + [4199, 2211], + [4210, 2218], + [4212, 2210], + [4223, 2214], + [4224, 2207], + [4224, 2216], + [4217, 2225], + [4221, 2233], + [4215, 2224], + [4203, 2227], + [4199, 2238], + [4209, 2248], + [4197, 2242], + [4185, 2240], + [4186, 2254], + [4198, 2276], + [4187, 2260], + [4178, 2259], + [4161, 2258], + [4153, 2249], + [4150, 2238], + [4150, 2228], + [4136, 2231], + [4144, 2218], + [4114, 2274], + [4123, 2272], + [4133, 2270], + [4117, 2280], + [4139, 2273], + [4152, 2274], + [4140, 2276], + [4133, 2284], + [4141, 2288], + [4147, 2303], + [4157, 2311], + [4171, 2308], + [4163, 2310], + [4158, 2319], + [4144, 2315], + [4135, 2305], + [4125, 2299], + [4108, 2303], + [4097, 2318], + [4091, 2343], + [4096, 2347], + [4096, 2339], + [4112, 2344], + [4110, 2332], + [4119, 2332], + [4121, 2347], + [4131, 2344], + [4146, 2338], + [4155, 2337], + [4164, 2350], + [4180, 2355], + [4195, 2352], + [4200, 2342], + [4201, 2354], + [4213, 2352], + [4224, 2348], + [4224, 2356], + [4207, 2361], + [4184, 2358], + [4176, 2367], + [4162, 2364], + [4155, 2354], + [4141, 2357], + [4119, 2361], + [4115, 2355], + [4106, 2355], + [4101, 2364], + [4105, 2372], + [4108, 2386], + [4096, 2372], + [4091, 2388], + [4078, 2409], + [4067, 2446], + [4059, 2493], + [4073, 2495], + [4074, 2478], + [4073, 2490], + [4087, 2492], + [4084, 2484], + [4089, 2481], + [4097, 2481], + [4099, 2473], + [4088, 2474], + [4092, 2464], + [4103, 2465], + [4102, 2473], + [4118, 2470], + [4118, 2459], + [4129, 2458], + [4129, 2449], + [4121, 2447], + [4126, 2439], + [4135, 2447], + [4143, 2440], + [4142, 2426], + [4148, 2416], + [4156, 2414], + [4159, 2406], + [4161, 2417], + [4153, 2419], + [4144, 2434], + [4154, 2440], + [4152, 2449], + [4163, 2459], + [4171, 2453], + [4166, 2461], + [4153, 2458], + [4136, 2458], + [4121, 2480], + [4141, 2472], + [4157, 2483], + [4168, 2487], + [4160, 2482], + [4149, 2480], + [4140, 2480], + [4128, 2487], + [4112, 2483], + [4102, 2487], + [4097, 2499], + [4098, 2510], + [4108, 2514], + [4117, 2522], + [4140, 2526], + [4126, 2524], + [4114, 2523], + [4100, 2524], + [4091, 2519], + [4084, 2528], + [4093, 2511], + [4089, 2501], + [4079, 2509], + [4065, 2508], + [4057, 2516], + [4050, 2536], + [4067, 2544], + [4057, 2546], + [4057, 2558], + [4050, 2538], + [4037, 2561], + [4029, 2589], + [4033, 2579], + [4030, 2604], + [4034, 2629], + [4035, 2614], + [4034, 2601], + [4038, 2593], + [4043, 2610], + [4048, 2598], + [4063, 2585], + [4076, 2582], + [4080, 2573], + [4089, 2570], + [4097, 2562], + [4095, 2571], + [4075, 2586], + [4084, 2597], + [4097, 2592], + [4108, 2591], + [4095, 2596], + [4103, 2601], + [4095, 2605], + [4087, 2606], + [4066, 2597], + [4063, 2606], + [4073, 2606], + [4048, 2618], + [4052, 2632], + [4052, 2642], + [4064, 2646], + [4082, 2654], + [4091, 2645], + [4084, 2654], + [4097, 2656], + [4094, 2667], + [4085, 2664], + [4086, 2672], + [4080, 2656], + [4068, 2654], + [4060, 2654], + [4042, 2652], + [4053, 2661], + [4045, 2660], + [4035, 2665], + [4025, 2666], + [4026, 2684], + [4032, 2697], + [4046, 2699], + [4037, 2714], + [4039, 2702], + [4031, 2709], + [4027, 2691], + [3983, 2765], + [3974, 2811], + [3974, 2820], + [3977, 2809], + [3985, 2796], + [3995, 2794], + [3998, 2785], + [4007, 2786], + [4004, 2776], + [4012, 2775], + [4015, 2755], + [4022, 2763], + [4038, 2761], + [4020, 2771], + [4035, 2784], + [4044, 2783], + [4034, 2789], + [4024, 2793], + [4024, 2798], + [4013, 2798], + [4017, 2810], + [4013, 2802], + [4001, 2803], + [4002, 2818], + [4013, 2823], + [4003, 2819], + [3991, 2818], + [3982, 2835], + [3983, 2846], + [3993, 2848], + [4005, 2853], + [4017, 2855], + [4028, 2846], + [4019, 2853], + [4027, 2861], + [4010, 2854], + [4000, 2854], + [3992, 2861], + [3992, 2851], + [3973, 2866], + [3968, 2877], + [3984, 2880], + [3967, 2885], + [3970, 2902], + [3983, 2931], + [3987, 2920], + [3988, 2931], + [4002, 2936], + [4010, 2917], + [4008, 2903], + [4016, 2893], + [4021, 2901], + [4012, 2913], + [4026, 2916], + [4014, 2921], + [4015, 2934], + [4032, 2937], + [4018, 2934], + [4014, 2944], + [4024, 2948], + [4015, 2950], + [4006, 2943], + [3992, 2946], + [3986, 2988], + [3992, 3004], + [4017, 3037], + [4023, 3053], + [4022, 3063], + [4031, 3065], + [4036, 3073], + [4050, 3135], + [4050, 3151], + [4091, 3119], + [4083, 3115], + [4076, 3096], + [4087, 3101], + [4086, 3072], + [4087, 3061], + [4087, 3046], + [4094, 3022], + [4092, 3012], + [4091, 3001], + [4097, 2989], + [4097, 3013], + [4098, 2945], + [4101, 2937], + [4097, 2920], + [4105, 2913], + [4113, 2856], + [4122, 2844], + [4112, 2840], + [4123, 2834], + [4124, 2817], + [4129, 2791], + [4136, 2775], + [4140, 2760], + [4130, 2754], + [4145, 2754], + [4154, 2742], + [4150, 2733], + [4139, 2720], + [4154, 2722], + [4159, 2707], + [4183, 2662], + [4182, 2654], + [4183, 2640], + [4189, 2644], + [4189, 2653], + [4197, 2632], + [4209, 2634], + [4205, 2624], + [4213, 2607], + [4203, 2605], + [4209, 2589], + [4211, 2600], + [4219, 2599], + [4224, 2592], + [4224, 2574], + [4223, 2566], + [4224, 2562], + [4224, 2553], + [4224, 2552], + [4224, -128], + [4224, 4224], + [4205, 4224], + [4183, 4096], + [4158, 4018], + [4122, 3935], + [4097, 3854], + [4092, 3841], + [4075, 3785], + [4050, 3675], + [4045, 3686], + [4047, 3676], + [4031, 3585], + [4015, 3513], + [3993, 3494], + [3963, 3488], + [3945, 3491], + [3919, 3515], + [3880, 3525], + [3873, 3533], + [3887, 3539], + [3897, 3536], + [3924, 3532], + [3923, 3524], + [3925, 3533], + [3936, 3526], + [3950, 3529], + [3962, 3536], + [3976, 3555], + [3981, 3567], + [4002, 3574], + [4018, 3572], + [4003, 3575], + [4018, 3580], + [4022, 3593], + [4014, 3591], + [4009, 3579], + [3992, 3572], + [3992, 3585], + [3993, 3598], + [4002, 3596], + [4007, 3594], + [4007, 3603], + [4010, 3613], + [4027, 3623], + [4012, 3619], + [4004, 3619], + [4005, 3609], + [3995, 3606], + [3986, 3604], + [3995, 3609], + [3990, 3617], + [3998, 3617], + [3999, 3627], + [3987, 3633], + [3991, 3622], + [3978, 3621], + [3985, 3610], + [3981, 3600], + [3981, 3590], + [3986, 3598], + [3986, 3585], + [3976, 3587], + [3984, 3581], + [3983, 3571], + [3975, 3572], + [3967, 3566], + [3948, 3558], + [3955, 3583], + [3946, 3559], + [3936, 3547], + [3882, 3539], + [3879, 3548], + [3887, 3553], + [3893, 3543], + [3891, 3556], + [3899, 3562], + [3898, 3554], + [3907, 3558], + [3909, 3544], + [3913, 3557], + [3915, 3566], + [3907, 3567], + [3905, 3577], + [3916, 3574], + [3911, 3584], + [3914, 3592], + [3916, 3583], + [3920, 3598], + [3909, 3596], + [3901, 3596], + [3907, 3604], + [3913, 3612], + [3908, 3625], + [3917, 3622], + [3923, 3631], + [3914, 3628], + [3919, 3647], + [3922, 3656], + [3917, 3666], + [3922, 3655], + [3913, 3650], + [3916, 3641], + [3915, 3632], + [3906, 3639], + [3907, 3647], + [3898, 3647], + [3908, 3632], + [3899, 3631], + [3905, 3623], + [3903, 3615], + [3895, 3624], + [3897, 3632], + [3894, 3622], + [3883, 3622], + [3891, 3625], + [3888, 3614], + [3898, 3617], + [3901, 3607], + [3890, 3610], + [3891, 3600], + [3892, 3588], + [3903, 3590], + [3893, 3583], + [3890, 3574], + [3877, 3572], + [3880, 3581], + [3872, 3589], + [3869, 3574], + [3869, 3563], + [3858, 3561], + [3860, 3573], + [3851, 3572], + [3851, 3583], + [3847, 3591], + [3855, 3588], + [3854, 3601], + [3865, 3597], + [3861, 3605], + [3869, 3605], + [3858, 3605], + [3850, 3599], + [3841, 3611], + [3842, 3622], + [3852, 3623], + [3843, 3624], + [3843, 3634], + [3840, 3625], + [3823, 3628], + [3821, 3638], + [3813, 3642], + [3822, 3625], + [3836, 3616], + [3828, 3615], + [3830, 3606], + [3840, 3605], + [3847, 3596], + [3839, 3591], + [3849, 3584], + [3837, 3581], + [3825, 3591], + [3831, 3583], + [3830, 3571], + [3839, 3577], + [3832, 3566], + [3844, 3568], + [3841, 3558], + [3851, 3557], + [3851, 3542], + [3842, 3535], + [3863, 3543], + [3865, 3534], + [3802, 3504], + [3749, 3491], + [3749, 3507], + [3764, 3505], + [3750, 3513], + [3767, 3518], + [3742, 3522], + [3734, 3526], + [3739, 3508], + [3729, 3507], + [3745, 3506], + [3745, 3489], + [3684, 3476], + [3607, 3424], + [3585, 3422], + [3573, 3420], + [3569, 3428], + [3583, 3430], + [3583, 3430], + [3608, 3430], + [3619, 3435], + [3609, 3433], + [3607, 3452], + [3588, 3459], + [3587, 3468], + [3578, 3464], + [3568, 3455], + [3567, 3445], + [3555, 3447], + [3546, 3446], + [3536, 3439], + [3523, 3438], + [3528, 3447], + [3520, 3446], + [3528, 3448], + [3520, 3453], + [3526, 3463], + [3518, 3472], + [3531, 3476], + [3520, 3478], + [3518, 3482], + [3526, 3482], + [3519, 3486], + [3532, 3486], + [3519, 3488], + [3527, 3514], + [3530, 3540], + [3541, 3520], + [3550, 3529], + [3560, 3533], + [3562, 3524], + [3570, 3520], + [3565, 3530], + [3573, 3524], + [3571, 3534], + [3583, 3538], + [3583, 3536], + [3583, 3526], + [3594, 3523], + [3592, 3532], + [3586, 3545], + [3585, 3554], + [3584, 3563], + [3590, 3551], + [3591, 3561], + [3600, 3565], + [3605, 3551], + [3608, 3543], + [3621, 3543], + [3629, 3551], + [3613, 3549], + [3619, 3559], + [3631, 3564], + [3618, 3563], + [3614, 3553], + [3611, 3563], + [3606, 3576], + [3613, 3584], + [3608, 3593], + [3615, 3604], + [3628, 3611], + [3605, 3600], + [3607, 3586], + [3601, 3572], + [3591, 3575], + [3593, 3567], + [3583, 3566], + [3577, 3577], + [3580, 3564], + [3567, 3568], + [3576, 3561], + [3573, 3553], + [3566, 3540], + [3556, 3544], + [3558, 3553], + [3552, 3539], + [3543, 3573], + [3534, 3578], + [3522, 3584], + [3530, 3585], + [3522, 3589], + [3527, 3597], + [3542, 3604], + [3542, 3612], + [3550, 3612], + [3557, 3622], + [3568, 3634], + [3566, 3623], + [3569, 3627], + [3577, 3627], + [3575, 3638], + [3585, 3650], + [3605, 3655], + [3626, 3651], + [3649, 3657], + [3658, 3656], + [3655, 3648], + [3661, 3657], + [3671, 3657], + [3674, 3649], + [3669, 3640], + [3669, 3628], + [3679, 3631], + [3679, 3643], + [3684, 3651], + [3695, 3648], + [3679, 3653], + [3686, 3663], + [3694, 3658], + [3693, 3670], + [3703, 3667], + [3706, 3659], + [3704, 3668], + [3718, 3655], + [3712, 3676], + [3722, 3674], + [3722, 3681], + [3714, 3681], + [3699, 3671], + [3696, 3683], + [3692, 3694], + [3691, 3685], + [3693, 3673], + [3682, 3668], + [3679, 3679], + [3681, 3663], + [3671, 3670], + [3675, 3662], + [3666, 3662], + [3657, 3664], + [3671, 3676], + [3672, 3687], + [3661, 3687], + [3652, 3702], + [3651, 3692], + [3664, 3682], + [3654, 3671], + [3647, 3663], + [3636, 3663], + [3631, 3678], + [3633, 3662], + [3617, 3660], + [3610, 3669], + [3605, 3659], + [3596, 3657], + [3583, 3656], + [3578, 3672], + [3584, 3680], + [3589, 3689], + [3585, 3691], + [3594, 3691], + [3585, 3692], + [3584, 3694], + [3584, 3703], + [3587, 3713], + [3600, 3711], + [3589, 3713], + [3583, 3719], + [3583, 3739], + [3566, 3748], + [3566, 3759], + [3558, 3766], + [3574, 3769], + [3585, 3759], + [3576, 3770], + [3578, 3778], + [3578, 3788], + [3573, 3802], + [3583, 3804], + [3575, 3804], + [3579, 3812], + [3574, 3823], + [3572, 3835], + [3585, 3846], + [3605, 3855], + [3614, 3851], + [3637, 3864], + [3650, 3861], + [3660, 3867], + [3651, 3869], + [3642, 3864], + [3633, 3865], + [3624, 3870], + [3615, 3855], + [3603, 3857], + [3589, 3857], + [3579, 3850], + [3571, 3846], + [3567, 3837], + [3571, 3829], + [3573, 3811], + [3563, 3805], + [3550, 3802], + [3560, 3798], + [3564, 3784], + [3561, 3797], + [3574, 3775], + [3554, 3769], + [3547, 3778], + [3553, 3769], + [3543, 3759], + [3534, 3759], + [3522, 3759], + [3533, 3757], + [3541, 3757], + [3554, 3764], + [3560, 3745], + [3575, 3738], + [3566, 3733], + [3543, 3711], + [3568, 3731], + [3579, 3726], + [3580, 3718], + [3579, 3708], + [3567, 3708], + [3571, 3700], + [3580, 3691], + [3573, 3672], + [3574, 3655], + [3564, 3655], + [3563, 3640], + [3548, 3640], + [3537, 3646], + [3537, 3659], + [3537, 3648], + [3529, 3648], + [3540, 3640], + [3551, 3634], + [3543, 3628], + [3522, 3626], + [3507, 3629], + [3508, 3641], + [3496, 3636], + [3493, 3644], + [3496, 3653], + [3490, 3645], + [3491, 3654], + [3482, 3653], + [3486, 3667], + [3474, 3666], + [3474, 3676], + [3485, 3689], + [3474, 3681], + [3472, 3668], + [3463, 3666], + [3460, 3677], + [3456, 3662], + [3441, 3668], + [3438, 3682], + [3428, 3684], + [3424, 3692], + [3418, 3705], + [3423, 3717], + [3416, 3725], + [3416, 3702], + [3420, 3692], + [3428, 3671], + [3438, 3669], + [3443, 3660], + [3439, 3649], + [3431, 3650], + [3439, 3646], + [3441, 3636], + [3446, 3656], + [3465, 3656], + [3473, 3652], + [3474, 3644], + [3483, 3633], + [3475, 3630], + [3472, 3622], + [3465, 3630], + [3461, 3621], + [3472, 3619], + [3468, 3608], + [3474, 3620], + [3484, 3623], + [3507, 3621], + [3506, 3612], + [3514, 3608], + [3505, 3611], + [3490, 3607], + [3500, 3606], + [3493, 3583], + [3492, 3575], + [3472, 3576], + [3463, 3574], + [3481, 3569], + [3491, 3567], + [3508, 3577], + [3511, 3559], + [3496, 3556], + [3487, 3503], + [3447, 3502], + [3440, 3554], + [3411, 3553], + [3385, 3540], + [3361, 3536], + [3349, 3543], + [3344, 3560], + [3343, 3575], + [3329, 3577], + [3329, 3578], + [3320, 3578], + [3312, 3580], + [3304, 3591], + [3317, 3587], + [3309, 3591], + [3312, 3599], + [3307, 3619], + [3304, 3630], + [3300, 3621], + [3307, 3617], + [3307, 3608], + [3300, 3596], + [3301, 3587], + [3293, 3581], + [3274, 3583], + [3283, 3583], + [3290, 3595], + [3278, 3605], + [3264, 3607], + [3268, 3617], + [3259, 3627], + [3246, 3628], + [3254, 3637], + [3267, 3635], + [3271, 3644], + [3263, 3643], + [3253, 3644], + [3230, 3654], + [3226, 3668], + [3216, 3667], + [3212, 3671], + [3197, 3671], + [3206, 3694], + [3203, 3703], + [3193, 3709], + [3192, 3725], + [3196, 3738], + [3187, 3749], + [3192, 3764], + [3208, 3762], + [3210, 3775], + [3197, 3781], + [3186, 3780], + [3184, 3788], + [3185, 3780], + [3199, 3779], + [3209, 3773], + [3207, 3763], + [3190, 3765], + [3184, 3749], + [3184, 3729], + [3190, 3719], + [3182, 3710], + [3195, 3699], + [3185, 3690], + [3181, 3672], + [3188, 3658], + [3204, 3659], + [3210, 3649], + [3217, 3637], + [3231, 3638], + [3240, 3610], + [3234, 3601], + [3253, 3597], + [3257, 3586], + [3262, 3565], + [3272, 3560], + [3287, 3563], + [3295, 3557], + [3306, 3521], + [3292, 3508], + [3289, 3516], + [3280, 3520], + [3274, 3533], + [3260, 3531], + [3248, 3540], + [3236, 3553], + [3229, 3565], + [3219, 3564], + [3216, 3574], + [3201, 3577], + [3192, 3578], + [3202, 3576], + [3215, 3573], + [3218, 3562], + [3227, 3564], + [3242, 3541], + [3236, 3518], + [3228, 3519], + [3237, 3517], + [3241, 3532], + [3252, 3524], + [3250, 3513], + [3260, 3519], + [3274, 3520], + [3263, 3509], + [3271, 3507], + [3280, 3507], + [3278, 3478], + [3270, 3458], + [3261, 3455], + [3272, 3458], + [3280, 3462], + [3284, 3471], + [3298, 3477], + [3294, 3456], + [3297, 3444], + [3286, 3430], + [3257, 3423], + [3241, 3406], + [3239, 3394], + [3220, 3388], + [3201, 3366], + [3183, 3358], + [3175, 3364], + [3184, 3374], + [3175, 3367], + [3149, 3375], + [3134, 3374], + [3121, 3376], + [3113, 3380], + [3098, 3378], + [3105, 3388], + [3100, 3405], + [3108, 3409], + [3107, 3418], + [3098, 3405], + [3100, 3397], + [3089, 3395], + [3101, 3394], + [3095, 3375], + [3105, 3369], + [3115, 3348], + [3123, 3357], + [3134, 3357], + [3137, 3366], + [3160, 3369], + [3158, 3357], + [3167, 3337], + [3164, 3324], + [3151, 3311], + [3117, 3300], + [3073, 3300], + [3058, 3297], + [3046, 3288], + [3030, 3260], + [3031, 3236], + [3049, 3183], + [3048, 3164], + [3037, 3143], + [3038, 3124], + [3034, 3109], + [3026, 3107], + [3030, 3089], + [3026, 3072], + [3016, 3062], + [3013, 3047], + [3024, 3051], + [3032, 3048], + [3032, 3056], + [3038, 3046], + [3029, 3028], + [3017, 3020], + [3006, 3004], + [2998, 3016], + [2993, 3040], + [2982, 3053], + [2991, 3061], + [2981, 3054], + [2975, 3071], + [2966, 3091], + [2970, 3100], + [2973, 3109], + [2981, 3120], + [2973, 3133], + [2962, 3130], + [2955, 3128], + [2967, 3128], + [2976, 3119], + [2968, 3110], + [2969, 3102], + [2967, 3094], + [2941, 3099], + [2925, 3096], + [2916, 3089], + [2905, 3073], + [2894, 3056], + [2866, 3042], + [2862, 3029], + [2847, 3019], + [2834, 3024], + [2836, 3038], + [2829, 3047], + [2813, 3051], + [2803, 3052], + [2794, 3061], + [2776, 3065], + [2778, 3061], + [2769, 3061], + [2794, 3053], + [2803, 3040], + [2814, 3045], + [2822, 3037], + [2824, 3024], + [2832, 3014], + [2838, 2988], + [2812, 2990], + [2745, 2984], + [2713, 3000], + [2693, 3001], + [2656, 2970], + [2639, 2961], + [2623, 2943], + [2613, 2942], + [2582, 2927], + [2571, 2929], + [2565, 2941], + [2553, 2936], + [2539, 2944], + [2529, 2945], + [2538, 2938], + [2550, 2923], + [2556, 2923], + [2564, 2923], + [2567, 2895], + [2560, 2885], + [2559, 2868], + [2549, 2856], + [2547, 2842], + [2551, 2832], + [2542, 2828], + [2558, 2826], + [2538, 2811], + [2529, 2811], + [2532, 2822], + [2523, 2822], + [2496, 2840], + [2472, 2883], + [2454, 2888], + [2452, 2896], + [2461, 2901], + [2451, 2897], + [2451, 2885], + [2433, 2868], + [2423, 2869], + [2419, 2844], + [2413, 2802], + [2398, 2818], + [2383, 2818], + [2375, 2824], + [2356, 2820], + [2346, 2822], + [2331, 2817], + [2325, 2826], + [2309, 2833], + [2309, 2840], + [2309, 2832], + [2315, 2821], + [2288, 2841], + [2266, 2843], + [2255, 2836], + [2250, 2809], + [2238, 2810], + [2224, 2792], + [2221, 2813], + [2191, 2823], + [2170, 2839], + [2182, 2825], + [2163, 2809], + [2155, 2799], + [2150, 2786], + [2142, 2794], + [2133, 2801], + [2121, 2797], + [2119, 2783], + [2121, 2769], + [2143, 2760], + [2155, 2743], + [2156, 2733], + [2146, 2721], + [2130, 2721], + [2105, 2709], + [2096, 2695], + [2097, 2680], + [2115, 2648], + [2114, 2621], + [2119, 2643], + [2103, 2682], + [2102, 2693], + [2112, 2709], + [2149, 2716], + [2168, 2738], + [2165, 2748], + [2173, 2759], + [2164, 2751], + [2165, 2764], + [2167, 2778], + [2177, 2781], + [2190, 2775], + [2204, 2774], + [2222, 2772], + [2251, 2770], + [2275, 2782], + [2285, 2773], + [2275, 2783], + [2278, 2791], + [2313, 2799], + [2350, 2796], + [2339, 2793], + [2343, 2778], + [2334, 2780], + [2338, 2772], + [2347, 2793], + [2362, 2799], + [2371, 2794], + [2389, 2783], + [2405, 2786], + [2423, 2781], + [2435, 2771], + [2425, 2773], + [2447, 2765], + [2442, 2775], + [2433, 2779], + [2440, 2792], + [2441, 2805], + [2432, 2851], + [2441, 2866], + [2454, 2851], + [2473, 2839], + [2496, 2816], + [2487, 2811], + [2475, 2823], + [2464, 2822], + [2455, 2821], + [2475, 2819], + [2485, 2810], + [2497, 2814], + [2514, 2807], + [2527, 2793], + [2540, 2804], + [2566, 2808], + [2563, 2818], + [2569, 2826], + [2571, 2859], + [2608, 2909], + [2634, 2931], + [2651, 2930], + [2670, 2938], + [2668, 2928], + [2674, 2920], + [2684, 2922], + [2698, 2917], + [2697, 2908], + [2682, 2898], + [2699, 2907], + [2715, 2903], + [2725, 2893], + [2724, 2884], + [2715, 2876], + [2716, 2861], + [2706, 2839], + [2698, 2834], + [2702, 2825], + [2700, 2840], + [2710, 2849], + [2718, 2853], + [2715, 2835], + [2728, 2829], + [2726, 2817], + [2715, 2810], + [2709, 2795], + [2725, 2785], + [2727, 2750], + [2731, 2736], + [2722, 2729], + [2706, 2728], + [2721, 2728], + [2722, 2717], + [2712, 2713], + [2722, 2716], + [2731, 2700], + [2726, 2691], + [2708, 2707], + [2696, 2710], + [2689, 2725], + [2679, 2729], + [2676, 2695], + [2693, 2682], + [2685, 2680], + [2665, 2662], + [2668, 2653], + [2685, 2646], + [2686, 2625], + [2680, 2638], + [2669, 2644], + [2653, 2636], + [2653, 2652], + [2649, 2660], + [2635, 2666], + [2627, 2666], + [2626, 2651], + [2627, 2643], + [2631, 2645], + [2631, 2662], + [2646, 2654], + [2652, 2634], + [2672, 2640], + [2677, 2627], + [2688, 2623], + [2689, 2642], + [2686, 2650], + [2678, 2655], + [2670, 2654], + [2687, 2669], + [2695, 2658], + [2691, 2667], + [2702, 2677], + [2694, 2694], + [2682, 2699], + [2688, 2707], + [2696, 2701], + [2705, 2701], + [2716, 2689], + [2728, 2687], + [2732, 2695], + [2735, 2704], + [2745, 2693], + [2724, 2724], + [2736, 2740], + [2744, 2740], + [2743, 2732], + [2746, 2745], + [2753, 2732], + [2753, 2740], + [2773, 2748], + [2771, 2740], + [2778, 2751], + [2792, 2742], + [2782, 2746], + [2782, 2757], + [2782, 2767], + [2768, 2768], + [2765, 2783], + [2761, 2791], + [2766, 2791], + [2766, 2783], + [2759, 2795], + [2760, 2805], + [2748, 2798], + [2754, 2786], + [2740, 2784], + [2748, 2798], + [2733, 2806], + [2746, 2821], + [2758, 2826], + [2765, 2812], + [2763, 2825], + [2760, 2839], + [2738, 2845], + [2727, 2840], + [2728, 2849], + [2739, 2849], + [2743, 2861], + [2759, 2855], + [2764, 2842], + [2772, 2843], + [2783, 2856], + [2774, 2881], + [2753, 2881], + [2729, 2871], + [2733, 2882], + [2744, 2893], + [2743, 2902], + [2732, 2908], + [2740, 2922], + [2768, 2925], + [2807, 2919], + [2823, 2928], + [2848, 2940], + [2864, 2973], + [2864, 2959], + [2873, 2954], + [2881, 2943], + [2900, 2942], + [2891, 2941], + [2904, 2939], + [2874, 2956], + [2873, 2967], + [2884, 2967], + [2895, 2970], + [2938, 2977], + [2982, 2968], + [2993, 2960], + [2984, 2966], + [2969, 2964], + [2970, 2953], + [2973, 2943], + [2985, 2947], + [2981, 2957], + [2993, 2949], + [3044, 2957], + [3061, 2963], + [3071, 2970], + [3074, 2958], + [3084, 2960], + [3075, 2973], + [3098, 3002], + [3114, 3055], + [3123, 3051], + [3118, 3030], + [3121, 3019], + [3119, 3031], + [3126, 3040], + [3139, 3033], + [3153, 3035], + [3145, 3033], + [3139, 3041], + [3130, 3047], + [3139, 3054], + [3128, 3051], + [3118, 3060], + [3116, 3071], + [3116, 3071] + ], + [[3585, 3686], [3585, 3686]], + [[3585, 3683], [3585, 3683]], + [[3583, 3682], [3585, 3682]], + [[3840, 3591], [3834, 3595]], + [[3898, 3585], [3897, 3585]], + [[3583, 3560], [3583, 3559]], + [[3585, 3552], [3585, 3552]], + [[3871, 3583], [3872, 3584]], + [[3585, 3523], [3585, 3528]], + [[3583, 2711], [3583, 2711]], + [[3329, 2659], [3329, 2659]], + [[4095, 2657], [4099, 2657]], + [[4097, 2339], [4097, 2340]], + [[4206, 1537], [4204, 1535]], + [[3313, 1535], [3316, 1535]], + [[4095, 1312], [4095, 1312]], + [[4095, 1278], [4095, 1278]], + [[4096, 1276], [4096, 1276]], + [[4096, 1275], [4095, 1275]], + [[4095, 1273], [4095, 1273]], + [[4095, 1268], [4096, 1268]], + [[4095, 1262], [4095, 1262]], + [[4096, 1260], [4096, 1260]], + [[4095, 1238], [4095, 1236]], + [[3399, 2667], [3399, 2667], [3399, 2667]], + [[3645, 2653], [3645, 2653], [3645, 2653]], + [[3645, 2651], [3645, 2638], [3645, 2651], [3645, 2651]], + [[3529, 1415], [3532, 1422], [3529, 1415], [3529, 1415]], + [ + [3532, 1422], + [3526, 1436], + [3536, 1459], + [3537, 1437], + [3532, 1422], + [3532, 1422] + ], + [[3742, 70], [3742, 70], [3742, 70]], + [[3986, 2932], [3986, 2932], [3986, 2932]], + [[3989, 2934], [3989, 2934], [3989, 2934]], + [[3531, 3432], [3531, 3432], [3523, 3430], [3531, 3432], [3531, 3432]], + [[3419, 3718], [3419, 3718], [3419, 3718]], + [[3306, 3602], [3306, 3602], [3306, 3602]], + [[3242, 3400], [3242, 3400], [3242, 3400]], + [[3116, 3071], [3116, 3071], [3116, 3071]], + [[3565, 3391], [3565, 3391], [3565, 3391]], + [[3565, 3391], [3565, 3391], [3565, 3391]], + [[4174, 1692], [4174, 1692], [4174, 1692]], + [[4172, 1690], [4172, 1690], [4172, 1690]], + [[4172, 1690], [4169, 1684], [4161, 1680], [4172, 1690], [4172, 1690]], + [[4016, 1878], [4016, 1879], [4033, 1889], [4016, 1878], [4016, 1878]], + [ + [4016, 1878], + [4016, 1864], + [4029, 1859], + [4024, 1850], + [4008, 1839], + [4006, 1863], + [4016, 1878], + [4016, 1878] + ], + [ + [3315, 1339], + [3327, 1332], + [3331, 1324], + [3323, 1329], + [3311, 1313], + [3325, 1327], + [3321, 1308], + [3312, 1308], + [3290, 1293], + [3305, 1315], + [3315, 1339], + [3315, 1339] + ], + [[3290, 1293], [3278, 1276], [3290, 1293], [3290, 1293]], + [[3635, 3864], [3623, 3858], [3623, 3867], [3635, 3864], [3635, 3864]], + [[3305, 3591], [3305, 3591], [3305, 3591]], + [ + [4097, 3131], + [4102, 3126], + [4062, 3147], + [4084, 3142], + [4097, 3131], + [4097, 3131] + ], + [ + [4136, 3071], + [4136, 3071], + [4136, 3080], + [4139, 3072], + [4139, 3057], + [4139, 3036], + [4143, 3020], + [4137, 3036], + [4136, 3071], + [4136, 3071] + ], + [[4193, 3071], [4206, 3071], [4193, 3071], [4193, 3071]], + [ + [4218, 3073], + [4212, 3077], + [4203, 3078], + [4206, 3087], + [4188, 3104], + [4183, 3114], + [4171, 3114], + [4172, 3122], + [4164, 3122], + [4143, 3131], + [4125, 3156], + [4117, 3157], + [4128, 3161], + [4159, 3147], + [4223, 3071], + [4224, 3071], + [4224, 3063], + [4218, 3073], + [4218, 3073] + ], + [[4113, 3121], [4113, 3111], [4102, 3117], [4113, 3121], [4113, 3121]], + [[4176, 3076], [4176, 3076], [4176, 3076]], + [[4200, 3077], [4200, 3077], [4200, 3077]], + [[3617, 3544], [3614, 3548], [3617, 3544], [3617, 3544]], + [ + [3912, 3542], + [3924, 3541], + [3934, 3536], + [3942, 3535], + [3955, 3536], + [3939, 3532], + [3949, 3533], + [3937, 3527], + [3929, 3534], + [3900, 3540], + [3912, 3542], + [3912, 3542] + ], + [[3882, 3558], [3882, 3558], [3882, 3558]], + [[3876, 3557], [3876, 3557], [3876, 3557]], + [[3867, 3549], [3867, 3549], [3867, 3549]], + [[3542, 3361], [3542, 3361], [3542, 3361]], + [[3562, 3323], [3562, 3323], [3562, 3323]], + [[3566, 3315], [3569, 3318], [3566, 3315], [3566, 3315]], + [[4061, 3204], [4063, 3200], [4056, 3190], [4061, 3204], [4061, 3204]], + [ + [4050, 3172], + [4049, 3161], + [4044, 3170], + [4047, 3190], + [4039, 3183], + [4044, 3171], + [4033, 3187], + [4034, 3197], + [4043, 3210], + [4063, 3214], + [4085, 3209], + [4092, 3193], + [4090, 3179], + [4068, 3166], + [4068, 3174], + [4080, 3181], + [4081, 3192], + [4077, 3205], + [4064, 3206], + [4051, 3200], + [4050, 3172], + [4050, 3172] + ], + [[4123, 2945], [4123, 2945], [4123, 2945]], + [[4158, 2943], [4160, 2943], [4160, 2935], [4158, 2943], [4158, 2943]], + [[4163, 3063], [4163, 3063], [4163, 3063]], + [[4167, 3060], [4167, 3060], [4167, 3060]], + [[4145, 3018], [4147, 3005], [4145, 3018], [4145, 3018]], + [ + [4151, 2998], + [4158, 2977], + [4155, 2967], + [4159, 2946], + [4150, 2976], + [4147, 2988], + [4151, 2985], + [4151, 2998], + [4151, 2998] + ], + [[4176, 3066], [4176, 3066], [4176, 3066]], + [[4185, 3071], [4189, 3067], [4185, 3071], [4185, 3071]], + [ + [3460, 3072], + [3462, 3080], + [3477, 3083], + [3477, 3075], + [3479, 3067], + [3460, 3072], + [3460, 3072] + ], + [[3433, 2796], [3432, 2792], [3422, 2793], [3433, 2796], [3433, 2796]], + [[3475, 2876], [3482, 2867], [3475, 2876], [3475, 2876]], + [[3438, 2804], [3438, 2804], [3438, 2804]], + [[3440, 2953], [3440, 2953], [3440, 2953]], + [[3444, 2825], [3444, 2825], [3444, 2825]], + [[3490, 2860], [3490, 2860], [3490, 2860]], + [[3418, 2748], [3407, 2743], [3404, 2735], [3418, 2748], [3418, 2748]], + [[3457, 2870], [3457, 2870], [3457, 2870]], + [ + [3417, 2974], + [3419, 2958], + [3400, 2957], + [3407, 2969], + [3417, 2974], + [3417, 2974] + ], + [[3379, 2902], [3391, 2899], [3379, 2902], [3379, 2902]], + [[4209, 2617], [4209, 2617], [4209, 2617]], + [[2174, 2799], [2174, 2799], [2174, 2799]], + [ + [2762, 2876], + [2769, 2873], + [2752, 2869], + [2738, 2867], + [2738, 2869], + [2751, 2869], + [2762, 2876], + [2762, 2876] + ], + [ + [2754, 2782], + [2764, 2779], + [2766, 2769], + [2739, 2775], + [2754, 2782], + [2754, 2782] + ], + [[2735, 2862], [2735, 2862], [2735, 2862]], + [ + [2745, 2763], + [2752, 2758], + [2752, 2754], + [2732, 2754], + [2745, 2763], + [2745, 2763] + ], + [[2679, 2726], [2688, 2709], [2682, 2701], [2679, 2726], [2679, 2726]], + [ + [2920, 3005], + [2935, 2994], + [2914, 2986], + [2896, 2981], + [2884, 2974], + [2864, 2973], + [2868, 2983], + [2886, 2997], + [2905, 3016], + [2916, 3016], + [2920, 3005], + [2920, 3005] + ], + [[4096, 2494], [4096, 2494], [4096, 2494]], + [ + [3571, 2424], + [3572, 2433], + [3567, 2446], + [3545, 2469], + [3553, 2469], + [3559, 2457], + [3576, 2461], + [3578, 2451], + [3577, 2467], + [3587, 2474], + [3594, 2467], + [3594, 2475], + [3608, 2480], + [3610, 2469], + [3596, 2434], + [3580, 2421], + [3571, 2424], + [3571, 2424] + ], + [[3637, 2553], [3628, 2527], [3637, 2553], [3637, 2553]], + [[4064, 2507], [4064, 2507], [4064, 2507]], + [[3622, 2504], [3622, 2504], [3622, 2504]], + [[3620, 2493], [3618, 2484], [3620, 2493], [3620, 2493]], + [ + [3730, 1024], + [3735, 1040], + [3748, 1056], + [3748, 1040], + [3730, 1024], + [3730, 1024] + ], + [ + [3740, 1025], + [3738, 1026], + [3735, 993], + [3728, 984], + [3725, 995], + [3732, 1009], + [3733, 1001], + [3740, 1025], + [3740, 1025] + ], + [ + [4095, 1229], + [4093, 1228], + [4081, 1217], + [4073, 1234], + [4071, 1253], + [4064, 1278], + [4076, 1293], + [4087, 1283], + [4097, 1285], + [4110, 1286], + [4101, 1291], + [4121, 1285], + [4119, 1276], + [4104, 1258], + [4096, 1258], + [4093, 1268], + [4094, 1258], + [4096, 1245], + [4095, 1229], + [4095, 1229] + ], + [ + [4173, 1536], + [4167, 1554], + [4153, 1576], + [4166, 1585], + [4154, 1576], + [4163, 1574], + [4172, 1578], + [4183, 1582], + [4186, 1574], + [4198, 1571], + [4190, 1562], + [4191, 1551], + [4199, 1547], + [4196, 1538], + [4196, 1532], + [4188, 1532], + [4196, 1532], + [4204, 1527], + [4201, 1535], + [4207, 1535], + [4207, 1527], + [4213, 1535], + [4224, 1512], + [4224, 1511], + [4209, 1511], + [4198, 1506], + [4190, 1517], + [4194, 1509], + [4192, 1499], + [4200, 1496], + [4202, 1504], + [4224, 1510], + [4224, 1488], + [4215, 1486], + [4216, 1478], + [4224, 1472], + [4224, 1464], + [4207, 1458], + [4193, 1464], + [4189, 1476], + [4197, 1465], + [4203, 1476], + [4204, 1464], + [4212, 1469], + [4204, 1480], + [4195, 1477], + [4198, 1491], + [4207, 1488], + [4196, 1493], + [4173, 1536], + [4173, 1536] + ], + [ + [3934, 1537], + [3932, 1553], + [3936, 1580], + [3944, 1579], + [3950, 1595], + [3960, 1604], + [3968, 1630], + [3964, 1639], + [3963, 1650], + [3960, 1666], + [3968, 1673], + [3968, 1664], + [3983, 1662], + [3975, 1640], + [3981, 1627], + [3980, 1618], + [3970, 1606], + [3959, 1589], + [3973, 1578], + [3975, 1562], + [3971, 1570], + [3972, 1556], + [3964, 1540], + [3959, 1537], + [3943, 1537], + [3934, 1537], + [3934, 1537] + ], + [[3959, 1535], [3959, 1535], [3959, 1535]], + [[4163, 1915], [4161, 1880], [4156, 1894], [4163, 1915], [4163, 1915]], + [[4151, 1726], [4153, 1719], [4145, 1717], [4151, 1726], [4151, 1726]], + [[4147, 1710], [4150, 1702], [4147, 1710], [4147, 1710]], + [ + [4182, 1653], + [4177, 1649], + [4187, 1648], + [4195, 1643], + [4189, 1635], + [4198, 1632], + [4196, 1624], + [4186, 1624], + [4175, 1638], + [4167, 1647], + [4169, 1657], + [4164, 1646], + [4165, 1632], + [4175, 1633], + [4178, 1633], + [4178, 1625], + [4168, 1619], + [4166, 1622], + [4166, 1614], + [4161, 1661], + [4157, 1674], + [4171, 1676], + [4169, 1666], + [4163, 1656], + [4176, 1673], + [4180, 1665], + [4180, 1674], + [4189, 1682], + [4209, 1678], + [4193, 1677], + [4192, 1666], + [4200, 1669], + [4209, 1673], + [4216, 1671], + [4216, 1655], + [4205, 1653], + [4197, 1647], + [4182, 1653], + [4182, 1653] + ], + [ + [4200, 1619], + [4196, 1620], + [4200, 1632], + [4195, 1642], + [4207, 1648], + [4211, 1636], + [4205, 1627], + [4203, 1636], + [4200, 1619], + [4200, 1619] + ], + [ + [4170, 1684], + [4172, 1689], + [4184, 1683], + [4177, 1675], + [4170, 1684], + [4170, 1684] + ], + [ + [4026, 1835], + [4025, 1830], + [4020, 1821], + [4016, 1808], + [4007, 1836], + [4019, 1836], + [4011, 1832], + [4009, 1822], + [4020, 1830], + [4016, 1820], + [4026, 1835], + [4026, 1835] + ], + [[4003, 1782], [3999, 1779], [4003, 1782], [4003, 1782]], + [[4020, 1840], [4020, 1840], [4020, 1840]], + [[4037, 1849], [4044, 1837], [4036, 1833], [4037, 1849], [4037, 1849]], + [[3982, 1555], [3982, 1555], [3982, 1555]], + [ + [3971, 1555], + [3975, 1554], + [3973, 1545], + [3965, 1537], + [3971, 1555], + [3971, 1555] + ], + [[4005, 1781], [4001, 1770], [3993, 1764], [4005, 1781], [4005, 1781]], + [[3941, 1613], [3944, 1598], [3941, 1613], [3941, 1613]], + [[3976, 1591], [3978, 1588], [3976, 1591], [3976, 1591]], + [ + [4095, 1317], + [4095, 1317], + [4097, 1291], + [4088, 1298], + [4081, 1309], + [4088, 1322], + [4092, 1304], + [4095, 1317], + [4095, 1317] + ], + [[4130, 1263], [4130, 1263], [4130, 1263]], + [[4203, 1352], [4201, 1345], [4203, 1352], [4203, 1352]], + [ + [4216, 1371], + [4205, 1369], + [4203, 1363], + [4191, 1363], + [4200, 1366], + [4206, 1385], + [4216, 1371], + [4216, 1371] + ], + [ + [4199, 1384], + [4192, 1379], + [4182, 1389], + [4190, 1393], + [4192, 1402], + [4206, 1412], + [4216, 1401], + [4208, 1401], + [4209, 1393], + [4199, 1384], + [4199, 1384] + ], + [ + [4196, 1408], + [4190, 1407], + [4189, 1417], + [4199, 1420], + [4200, 1410], + [4196, 1410], + [4196, 1418], + [4196, 1408], + [4196, 1408] + ], + [[3308, 1121], [3308, 1121], [3308, 1121]], + [[3911, 1297], [3911, 1297], [3911, 1297]], + [ + [3797, 1096], + [3798, 1084], + [3802, 1090], + [3802, 1081], + [3801, 1072], + [3795, 1082], + [3797, 1096], + [3797, 1096] + ], + [ + [3760, 1062], + [3759, 1054], + [3749, 1051], + [3752, 1061], + [3760, 1062], + [3760, 1062] + ], + [[3939, 1523], [3944, 1517], [3939, 1523], [3939, 1523]], + [ + [3874, 1315], + [3881, 1311], + [3880, 1298], + [3877, 1307], + [3874, 1315], + [3874, 1315] + ], + [ + [3926, 1251], + [3930, 1256], + [3948, 1251], + [3959, 1255], + [3963, 1243], + [3953, 1235], + [3950, 1224], + [3940, 1222], + [3953, 1218], + [3963, 1218], + [3969, 1206], + [3964, 1188], + [3954, 1185], + [3944, 1188], + [3952, 1172], + [3933, 1150], + [3924, 1154], + [3913, 1149], + [3902, 1153], + [3924, 1164], + [3923, 1173], + [3908, 1181], + [3887, 1180], + [3878, 1173], + [3888, 1210], + [3874, 1211], + [3876, 1229], + [3882, 1239], + [3884, 1231], + [3897, 1235], + [3893, 1227], + [3880, 1218], + [3896, 1229], + [3904, 1227], + [3892, 1217], + [3903, 1221], + [3904, 1206], + [3894, 1207], + [3898, 1205], + [3898, 1197], + [3912, 1213], + [3929, 1205], + [3921, 1216], + [3926, 1251], + [3926, 1251] + ], + [ + [3926, 1354], + [3922, 1360], + [3958, 1389], + [3953, 1374], + [3962, 1375], + [3972, 1373], + [3984, 1390], + [3992, 1388], + [3989, 1384], + [3997, 1384], + [3991, 1352], + [3982, 1338], + [3968, 1332], + [3960, 1322], + [3955, 1299], + [3954, 1307], + [3943, 1311], + [3946, 1321], + [3935, 1329], + [3946, 1335], + [3956, 1338], + [3959, 1348], + [3956, 1361], + [3964, 1362], + [3955, 1370], + [3952, 1360], + [3951, 1368], + [3940, 1363], + [3926, 1354], + [3926, 1354] + ], + [ + [3964, 1319], + [3977, 1297], + [3965, 1319], + [3974, 1329], + [3974, 1313], + [3983, 1297], + [3980, 1307], + [3984, 1285], + [3975, 1284], + [3971, 1299], + [3963, 1301], + [3964, 1311], + [3964, 1319], + [3964, 1319] + ], + [ + [3880, 1273], + [3882, 1260], + [3874, 1251], + [3873, 1262], + [3880, 1273], + [3880, 1273] + ], + [[3899, 1252], [3899, 1252], [3899, 1252]], + [[2850, 1094], [2856, 1086], [2850, 1094], [2850, 1094]], + [[2827, 1062], [2827, 1062], [2827, 1062]], + [[2920, 1145], [2924, 1142], [2917, 1130], [2920, 1145], [2920, 1145]], + [ + [2928, 1260], + [2930, 1254], + [2922, 1241], + [2899, 1222], + [2922, 1242], + [2928, 1260], + [2928, 1260] + ], + [ + [2778, 1057], + [2785, 1044], + [2770, 1042], + [2746, 1030], + [2778, 1057], + [2778, 1057] + ], + [[2115, 589], [2115, 589], [2115, 589]], + [ + [3687, 959], + [3682, 948], + [3672, 941], + [3669, 928], + [3681, 942], + [3680, 927], + [3678, 908], + [3689, 908], + [3698, 920], + [3686, 901], + [3696, 903], + [3684, 896], + [3678, 885], + [3666, 890], + [3664, 908], + [3670, 921], + [3665, 930], + [3671, 947], + [3678, 959], + [3687, 959], + [3687, 959] + ], + [[3606, 543], [3602, 537], [3602, 524], [3606, 543], [3606, 543]], + [[3631, 900], [3631, 900], [3631, 900]], + [[3512, 596], [3514, 583], [3512, 596], [3512, 596]], + [[3628, 906], [3629, 897], [3619, 900], [3628, 906], [3628, 906]], + [ + [3630, 928], + [3639, 923], + [3632, 913], + [3630, 914], + [3630, 928], + [3630, 928] + ], + [[3514, 576], [3514, 576], [3514, 576]], + [ + [3452, 79], + [3436, 104], + [3437, 124], + [3448, 146], + [3456, 149], + [3476, 141], + [3460, 133], + [3459, 125], + [3452, 116], + [3450, 107], + [3467, 85], + [3460, 75], + [3452, 79], + [3452, 79] + ], + [ + [3751, 927], + [3754, 924], + [3746, 910], + [3738, 906], + [3729, 914], + [3737, 921], + [3720, 923], + [3719, 942], + [3739, 929], + [3751, 927], + [3751, 927] + ], + [[3464, 131], [3475, 136], [3475, 128], [3464, 131], [3464, 131]], + [[3754, 98], [3750, 80], [3754, 98], [3754, 98]], + [[3221, -111], [3221, -111], [3221, -111]], + [[3538, 1694], [3526, 1695], [3538, 1694], [3538, 1694]], + [[4182, 1653], [4182, 1653], [4182, 1653]], + [[4186, 1574], [4186, 1574], [4186, 1574]], + [[4204, 1527], [4204, 1527], [4204, 1527]], + [[4196, 1493], [4196, 1493], [4196, 1493]], + [[4202, 1495], [4202, 1495], [4202, 1495]], + [[4202, 1495], [4213, 1492], [4202, 1495], [4202, 1495]], + [[4211, 1491], [4211, 1491], [4211, 1491]], + [[4214, 1488], [4214, 1488], [4214, 1488]], + [[4211, 1491], [4211, 1491], [4211, 1491]], + [[4089, 1275], [4089, 1275], [4089, 1275]], + [[4099, 1265], [4102, 1266], [4101, 1276], [4099, 1265], [4099, 1265]], + [[4072, 1259], [4072, 1259], [4072, 1259]], + [[4072, 1259], [4072, 1259], [4072, 1259]], + [[4099, 1265], [4099, 1265], [4099, 1265]], + [[3792, 525], [3792, 525], [3792, 525]], + [[3792, 525], [3792, 517], [3792, 525], [3792, 525]], + [[2897, 3001], [2897, 3001], [2897, 3001]], + [[2918, 3005], [2918, 3005], [2918, 3005]], + [[2920, 3005], [2920, 3005], [2920, 3005]], + [[2918, 3005], [2918, 3005], [2918, 3005]], + [ + [2906, 3002], + [2916, 3001], + [2906, 3002], + [2897, 3001], + [2906, 3002], + [2906, 3002] + ], + [[2748, 2798], [2748, 2798], [2748, 2798]], + [[3570, 2759], [3570, 2759], [3570, 2759]], + [[3300, 2746], [3300, 2746], [3300, 2746]], + [[3114, 2710], [3114, 2710], [3114, 2710]], + [[3114, 2710], [3118, 2703], [3114, 2710], [3114, 2710]], + [[4095, 2569], [4098, 2560], [4106, 2555], [4095, 2569], [4095, 2569]], + [[4048, 2598], [4048, 2598], [4048, 2598]], + [[4048, 2598], [4044, 2590], [4048, 2590], [4048, 2598], [4048, 2598]], + [[3605, 3551], [3605, 3551], [3605, 3551]], + [[3897, 3536], [3893, 3537], [3897, 3536], [3897, 3536]], + [[3938, 3532], [3938, 3532], [3938, 3532]], + [[3938, 3532], [3938, 3532], [3938, 3532]], + [[3656, 3693], [3656, 3693], [3656, 3693]], + [[3654, 3671], [3654, 3671], [3654, 3671]], + [[3300, 3621], [3300, 3621], [3300, 3621]], + [[3306, 3594], [3306, 3594], [3306, 3594]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/water-huge2.json b/packages/melonjs/tests/earcut/fixtures/water-huge2.json new file mode 100644 index 000000000..5be5c7379 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/water-huge2.json @@ -0,0 +1,4885 @@ +[ + [ + [-128, 4224], + [-128, 2734], + [-116, 2736], + [-109, 2749], + [-99, 2750], + [-101, 2734], + [-96, 2724], + [-90, 2708], + [-76, 2704], + [-61, 2690], + [-51, 2691], + [-40, 2674], + [-40, 2660], + [-29, 2647], + [-19, 2647], + [-11, 2643], + [-13, 2652], + [-15, 2671], + [-15, 2679], + [-23, 2679], + [-27, 2696], + [-37, 2706], + [-36, 2715], + [-45, 2708], + [-45, 2720], + [-43, 2732], + [-46, 2745], + [-34, 2757], + [-54, 2764], + [-62, 2769], + [-62, 2786], + [-69, 2800], + [-72, 2824], + [-77, 2838], + [-82, 2867], + [-86, 2884], + [-108, 2908], + [-101, 2919], + [-85, 2911], + [-72, 2897], + [-70, 2880], + [-60, 2880], + [-59, 2873], + [-48, 2873], + [-46, 2859], + [-37, 2860], + [-28, 2850], + [-17, 2842], + [-17, 2834], + [-4, 2825], + [8, 2825], + [10, 2817], + [12, 2799], + [4, 2800], + [8, 2797], + [8, 2787], + [22, 2796], + [32, 2788], + [52, 2801], + [67, 2781], + [78, 2747], + [95, 2732], + [97, 2720], + [119, 2709], + [109, 2695], + [117, 2701], + [114, 2689], + [123, 2680], + [128, 2670], + [117, 2666], + [120, 2654], + [122, 2669], + [131, 2668], + [141, 2666], + [143, 2676], + [149, 2684], + [148, 2692], + [160, 2698], + [152, 2698], + [130, 2699], + [133, 2717], + [127, 2722], + [118, 2722], + [119, 2743], + [102, 2760], + [93, 2761], + [83, 2772], + [96, 2790], + [116, 2800], + [104, 2800], + [85, 2802], + [76, 2799], + [80, 2809], + [47, 2819], + [31, 2818], + [19, 2846], + [21, 2851], + [41, 2851], + [61, 2850], + [74, 2856], + [77, 2865], + [93, 2877], + [100, 2895], + [115, 2898], + [138, 2890], + [139, 2882], + [139, 2890], + [148, 2891], + [170, 2891], + [182, 2885], + [197, 2894], + [217, 2897], + [193, 2896], + [182, 2889], + [152, 2899], + [136, 2894], + [113, 2905], + [127, 2910], + [137, 2919], + [158, 2924], + [167, 2932], + [155, 2927], + [143, 2927], + [133, 2926], + [123, 2914], + [101, 2909], + [94, 2896], + [83, 2909], + [91, 2914], + [89, 2929], + [81, 2939], + [84, 2926], + [89, 2915], + [82, 2904], + [92, 2893], + [76, 2887], + [74, 2877], + [63, 2878], + [54, 2880], + [63, 2877], + [49, 2869], + [40, 2879], + [40, 2887], + [30, 2887], + [22, 2892], + [16, 2873], + [1, 2873], + [-13, 2873], + [-27, 2891], + [-20, 2901], + [-1, 2907], + [-10, 2918], + [-19, 2910], + [-33, 2903], + [-43, 2895], + [-57, 2922], + [-60, 2940], + [-69, 2949], + [-85, 2954], + [-95, 2970], + [-99, 2987], + [-88, 2988], + [-75, 2988], + [-79, 2998], + [-93, 2998], + [-94, 2990], + [-101, 2998], + [-106, 2989], + [-128, 3002], + [-128, 4224], + [-128, 4224], + [1249, 4224], + [1247, 4199], + [1231, 4132], + [1221, 4130], + [1230, 4148], + [1214, 4165], + [1198, 4171], + [1162, 4169], + [1134, 4155], + [1091, 4128], + [1068, 4096], + [1025, 4052], + [989, 4001], + [924, 3927], + [909, 3902], + [904, 3882], + [908, 3871], + [909, 3858], + [911, 3830], + [905, 3799], + [868, 3727], + [827, 3685], + [799, 3668], + [787, 3655], + [784, 3642], + [782, 3582], + [771, 3537], + [765, 3481], + [767, 3441], + [786, 3409], + [789, 3381], + [785, 3371], + [786, 3361], + [776, 3339], + [777, 3314], + [770, 3305], + [775, 3278], + [734, 3220], + [728, 3203], + [729, 3178], + [708, 3167], + [695, 3147], + [667, 3134], + [666, 3126], + [651, 3121], + [645, 3113], + [650, 3104], + [630, 3089], + [616, 3074], + [615, 3053], + [607, 3047], + [607, 3035], + [599, 3034], + [603, 3026], + [575, 2980], + [532, 2939], + [524, 2926], + [509, 2903], + [501, 2865], + [509, 2844], + [509, 2831], + [526, 2809], + [531, 2794], + [540, 2718], + [552, 2713], + [543, 2711], + [551, 2705], + [537, 2701], + [512, 2675], + [503, 2708], + [492, 2717], + [502, 2705], + [510, 2671], + [493, 2656], + [463, 2663], + [485, 2654], + [471, 2627], + [474, 2614], + [470, 2603], + [475, 2588], + [483, 2583], + [486, 2573], + [511, 2538], + [550, 2523], + [553, 2514], + [561, 2507], + [582, 2472], + [595, 2460], + [597, 2452], + [605, 2447], + [622, 2409], + [638, 2357], + [654, 2337], + [663, 2311], + [687, 2278], + [718, 2256], + [729, 2254], + [739, 2249], + [760, 2240], + [776, 2227], + [789, 2219], + [786, 2213], + [797, 2213], + [819, 2191], + [855, 2170], + [865, 2163], + [884, 2150], + [897, 2147], + [889, 2134], + [898, 2146], + [906, 2143], + [907, 2126], + [909, 2137], + [917, 2138], + [934, 2145], + [958, 2142], + [989, 2146], + [996, 2166], + [971, 2170], + [967, 2181], + [953, 2181], + [933, 2170], + [900, 2180], + [888, 2187], + [883, 2196], + [868, 2204], + [859, 2204], + [872, 2219], + [873, 2234], + [884, 2226], + [874, 2236], + [876, 2244], + [867, 2229], + [870, 2221], + [861, 2209], + [842, 2213], + [833, 2218], + [812, 2228], + [811, 2242], + [796, 2258], + [760, 2272], + [740, 2289], + [726, 2295], + [704, 2319], + [693, 2326], + [689, 2349], + [672, 2382], + [671, 2415], + [653, 2417], + [643, 2443], + [629, 2448], + [623, 2457], + [624, 2473], + [613, 2512], + [588, 2545], + [576, 2549], + [567, 2563], + [534, 2585], + [534, 2596], + [547, 2625], + [556, 2624], + [571, 2640], + [589, 2624], + [573, 2642], + [581, 2642], + [584, 2651], + [607, 2634], + [615, 2638], + [602, 2645], + [596, 2658], + [602, 2665], + [610, 2665], + [621, 2679], + [620, 2695], + [609, 2721], + [589, 2747], + [598, 2758], + [594, 2808], + [600, 2837], + [583, 2842], + [579, 2818], + [575, 2830], + [575, 2880], + [584, 2898], + [626, 2901], + [630, 2912], + [639, 2919], + [653, 2920], + [672, 2937], + [683, 2934], + [700, 2968], + [706, 2979], + [705, 2970], + [711, 2986], + [740, 3032], + [748, 3038], + [757, 3034], + [769, 3035], + [773, 3044], + [788, 3053], + [798, 3089], + [824, 3100], + [833, 3112], + [844, 3105], + [830, 3099], + [837, 3087], + [847, 3084], + [845, 3072], + [856, 3070], + [858, 3062], + [848, 3056], + [851, 3048], + [833, 3037], + [852, 3047], + [860, 3043], + [877, 3052], + [877, 3042], + [881, 3028], + [893, 3034], + [893, 3046], + [901, 3029], + [914, 3030], + [921, 3045], + [938, 3041], + [942, 3054], + [948, 3043], + [962, 3052], + [962, 3043], + [973, 3041], + [974, 3050], + [984, 3045], + [988, 3056], + [996, 3049], + [1004, 3055], + [1014, 3049], + [1023, 3049], + [1034, 3045], + [1032, 3033], + [1034, 3013], + [1025, 3007], + [1025, 2977], + [1030, 2990], + [1029, 3006], + [1037, 3003], + [1037, 3012], + [1035, 3042], + [1043, 3045], + [1023, 3053], + [1000, 3061], + [997, 3053], + [984, 3057], + [982, 3047], + [973, 3052], + [967, 3040], + [965, 3053], + [950, 3048], + [958, 3062], + [947, 3057], + [933, 3059], + [929, 3047], + [916, 3045], + [915, 3034], + [901, 3032], + [902, 3040], + [897, 3048], + [881, 3038], + [885, 3049], + [880, 3055], + [871, 3055], + [860, 3046], + [857, 3055], + [857, 3074], + [847, 3073], + [850, 3086], + [834, 3096], + [846, 3101], + [846, 3110], + [858, 3106], + [868, 3108], + [890, 3123], + [899, 3119], + [910, 3120], + [915, 3130], + [901, 3128], + [904, 3137], + [917, 3140], + [909, 3145], + [901, 3139], + [894, 3130], + [892, 3139], + [909, 3182], + [946, 3217], + [952, 3207], + [947, 3195], + [961, 3188], + [954, 3175], + [957, 3156], + [949, 3157], + [933, 3163], + [923, 3153], + [930, 3143], + [934, 3156], + [943, 3148], + [943, 3140], + [949, 3156], + [957, 3155], + [959, 3141], + [968, 3139], + [961, 3121], + [973, 3118], + [971, 3094], + [973, 3104], + [987, 3095], + [974, 3106], + [976, 3115], + [988, 3104], + [997, 3103], + [989, 3107], + [988, 3116], + [976, 3116], + [966, 3131], + [987, 3135], + [979, 3132], + [984, 3124], + [993, 3137], + [1001, 3135], + [971, 3133], + [971, 3141], + [961, 3146], + [960, 3155], + [961, 3169], + [966, 3181], + [953, 3195], + [976, 3193], + [1004, 3203], + [1001, 3194], + [1014, 3189], + [1007, 3197], + [997, 3208], + [1012, 3227], + [1020, 3227], + [1023, 3218], + [1032, 3203], + [1026, 3219], + [1027, 3228], + [1024, 3218], + [1023, 3227], + [1011, 3241], + [1014, 3249], + [1025, 3254], + [1057, 3270], + [1068, 3271], + [1077, 3284], + [1088, 3304], + [1100, 3300], + [1098, 3292], + [1100, 3302], + [1125, 3305], + [1133, 3310], + [1122, 3306], + [1107, 3308], + [1116, 3320], + [1122, 3353], + [1129, 3361], + [1137, 3357], + [1153, 3350], + [1144, 3353], + [1139, 3362], + [1122, 3377], + [1132, 3387], + [1146, 3408], + [1161, 3413], + [1166, 3423], + [1170, 3412], + [1179, 3406], + [1177, 3395], + [1166, 3396], + [1155, 3397], + [1166, 3394], + [1157, 3387], + [1170, 3377], + [1169, 3391], + [1177, 3391], + [1193, 3374], + [1188, 3366], + [1196, 3367], + [1210, 3360], + [1203, 3350], + [1195, 3347], + [1196, 3338], + [1205, 3338], + [1198, 3329], + [1207, 3336], + [1207, 3353], + [1221, 3357], + [1219, 3348], + [1220, 3362], + [1233, 3367], + [1243, 3364], + [1257, 3363], + [1260, 3360], + [1276, 3360], + [1268, 3344], + [1270, 3327], + [1282, 3329], + [1270, 3327], + [1269, 3339], + [1281, 3339], + [1269, 3339], + [1274, 3354], + [1282, 3349], + [1280, 3360], + [1290, 3360], + [1287, 3348], + [1287, 3356], + [1296, 3343], + [1291, 3359], + [1304, 3348], + [1320, 3351], + [1311, 3339], + [1321, 3322], + [1331, 3318], + [1343, 3325], + [1330, 3300], + [1338, 3305], + [1336, 3287], + [1344, 3285], + [1342, 3294], + [1350, 3273], + [1355, 3276], + [1355, 3288], + [1359, 3280], + [1358, 3270], + [1345, 3270], + [1360, 3269], + [1352, 3255], + [1365, 3245], + [1373, 3248], + [1376, 3238], + [1380, 3221], + [1386, 3209], + [1372, 3201], + [1375, 3196], + [1367, 3196], + [1376, 3196], + [1367, 3191], + [1377, 3193], + [1380, 3188], + [1365, 3188], + [1361, 3177], + [1368, 3167], + [1357, 3164], + [1353, 3155], + [1361, 3152], + [1346, 3149], + [1341, 3141], + [1342, 3133], + [1334, 3128], + [1335, 3119], + [1322, 3112], + [1330, 3109], + [1320, 3099], + [1319, 3091], + [1310, 3073], + [1321, 3073], + [1312, 3075], + [1321, 3074], + [1317, 3082], + [1326, 3081], + [1330, 3094], + [1334, 3102], + [1341, 3110], + [1345, 3121], + [1337, 3128], + [1345, 3130], + [1347, 3122], + [1357, 3117], + [1359, 3111], + [1359, 3103], + [1363, 3093], + [1363, 3102], + [1360, 3113], + [1350, 3129], + [1364, 3150], + [1358, 3160], + [1368, 3164], + [1373, 3176], + [1381, 3183], + [1389, 3176], + [1381, 3184], + [1381, 3200], + [1391, 3198], + [1398, 3206], + [1413, 3186], + [1391, 3215], + [1379, 3228], + [1382, 3238], + [1384, 3230], + [1397, 3226], + [1395, 3228], + [1407, 3228], + [1394, 3229], + [1397, 3248], + [1391, 3258], + [1380, 3260], + [1377, 3283], + [1361, 3291], + [1359, 3303], + [1343, 3303], + [1352, 3317], + [1350, 3326], + [1341, 3328], + [1330, 3322], + [1320, 3331], + [1332, 3325], + [1354, 3334], + [1357, 3343], + [1347, 3347], + [1335, 3349], + [1346, 3351], + [1337, 3357], + [1345, 3360], + [1337, 3361], + [1338, 3369], + [1328, 3363], + [1334, 3382], + [1325, 3398], + [1345, 3401], + [1346, 3388], + [1347, 3397], + [1358, 3402], + [1361, 3393], + [1370, 3383], + [1371, 3394], + [1362, 3399], + [1387, 3402], + [1374, 3401], + [1388, 3398], + [1376, 3392], + [1388, 3396], + [1375, 3389], + [1387, 3391], + [1375, 3383], + [1388, 3391], + [1404, 3390], + [1387, 3377], + [1396, 3379], + [1413, 3374], + [1411, 3386], + [1407, 3400], + [1435, 3408], + [1436, 3399], + [1419, 3387], + [1427, 3376], + [1420, 3366], + [1429, 3370], + [1427, 3378], + [1422, 3389], + [1430, 3387], + [1430, 3395], + [1435, 3409], + [1453, 3416], + [1445, 3406], + [1443, 3399], + [1443, 3386], + [1454, 3397], + [1462, 3391], + [1465, 3382], + [1473, 3390], + [1474, 3382], + [1458, 3364], + [1477, 3383], + [1473, 3394], + [1482, 3395], + [1478, 3410], + [1494, 3408], + [1494, 3416], + [1493, 3426], + [1502, 3427], + [1510, 3436], + [1514, 3428], + [1505, 3420], + [1514, 3428], + [1513, 3419], + [1522, 3417], + [1507, 3411], + [1520, 3412], + [1518, 3401], + [1526, 3394], + [1522, 3403], + [1523, 3411], + [1532, 3426], + [1543, 3438], + [1548, 3429], + [1554, 3443], + [1568, 3435], + [1570, 3456], + [1579, 3457], + [1588, 3465], + [1580, 3459], + [1579, 3469], + [1580, 3459], + [1569, 3457], + [1563, 3441], + [1555, 3444], + [1546, 3438], + [1537, 3442], + [1528, 3440], + [1526, 3453], + [1537, 3458], + [1542, 3450], + [1537, 3460], + [1526, 3461], + [1532, 3486], + [1528, 3502], + [1527, 3523], + [1536, 3528], + [1522, 3525], + [1522, 3557], + [1513, 3583], + [1511, 3591], + [1509, 3602], + [1509, 3593], + [1473, 3664], + [1450, 3709], + [1429, 3764], + [1417, 3824], + [1458, 3825], + [1491, 3840], + [1504, 3850], + [1522, 3849], + [1526, 3834], + [1518, 3833], + [1530, 3834], + [1532, 3826], + [1527, 3823], + [1535, 3823], + [1535, 3820], + [1544, 3820], + [1560, 3816], + [1571, 3811], + [1563, 3799], + [1554, 3800], + [1543, 3811], + [1552, 3804], + [1551, 3796], + [1559, 3802], + [1556, 3787], + [1547, 3790], + [1556, 3786], + [1564, 3784], + [1560, 3776], + [1552, 3778], + [1564, 3775], + [1570, 3788], + [1586, 3800], + [1574, 3783], + [1588, 3799], + [1582, 3787], + [1597, 3787], + [1595, 3778], + [1580, 3769], + [1579, 3780], + [1579, 3769], + [1581, 3747], + [1589, 3731], + [1604, 3729], + [1603, 3720], + [1605, 3730], + [1596, 3733], + [1608, 3738], + [1609, 3747], + [1617, 3731], + [1633, 3721], + [1631, 3710], + [1615, 3710], + [1614, 3723], + [1610, 3715], + [1616, 3708], + [1632, 3708], + [1642, 3702], + [1651, 3702], + [1635, 3681], + [1625, 3681], + [1616, 3693], + [1621, 3685], + [1615, 3662], + [1625, 3660], + [1635, 3637], + [1644, 3637], + [1655, 3630], + [1648, 3615], + [1680, 3638], + [1678, 3599], + [1664, 3598], + [1661, 3590], + [1672, 3572], + [1687, 3560], + [1701, 3556], + [1711, 3562], + [1716, 3571], + [1724, 3570], + [1735, 3561], + [1753, 3559], + [1762, 3547], + [1740, 3551], + [1727, 3545], + [1716, 3531], + [1714, 3517], + [1723, 3512], + [1734, 3526], + [1744, 3530], + [1752, 3525], + [1780, 3522], + [1774, 3507], + [1749, 3508], + [1742, 3494], + [1729, 3488], + [1751, 3468], + [1764, 3474], + [1777, 3478], + [1798, 3472], + [1807, 3473], + [1796, 3475], + [1794, 3495], + [1782, 3507], + [1779, 3540], + [1792, 3530], + [1810, 3485], + [1843, 3426], + [1872, 3393], + [1873, 3383], + [1860, 3397], + [1841, 3405], + [1845, 3413], + [1835, 3420], + [1835, 3429], + [1824, 3449], + [1803, 3448], + [1807, 3459], + [1809, 3470], + [1798, 3472], + [1803, 3453], + [1794, 3449], + [1796, 3439], + [1788, 3432], + [1787, 3418], + [1802, 3409], + [1815, 3391], + [1844, 3380], + [1847, 3372], + [1844, 3359], + [1854, 3349], + [1853, 3337], + [1876, 3335], + [1880, 3313], + [1901, 3306], + [1908, 3298], + [1880, 3315], + [1882, 3333], + [1868, 3337], + [1884, 3336], + [1872, 3344], + [1882, 3351], + [1870, 3345], + [1870, 3355], + [1881, 3360], + [1874, 3370], + [1949, 3282], + [1971, 3261], + [2006, 3241], + [2018, 3223], + [2016, 3204], + [2004, 3208], + [2001, 3216], + [1979, 3235], + [1962, 3244], + [1960, 3252], + [1951, 3245], + [1956, 3256], + [1947, 3245], + [1944, 3253], + [1953, 3258], + [1943, 3254], + [1933, 3264], + [1925, 3279], + [1912, 3281], + [1908, 3291], + [1904, 3281], + [1909, 3250], + [1915, 3238], + [1924, 3238], + [1917, 3224], + [1904, 3222], + [1899, 3187], + [1905, 3178], + [1902, 3165], + [1912, 3166], + [1913, 3150], + [1911, 3160], + [1907, 3170], + [1918, 3194], + [1927, 3194], + [1936, 3184], + [1951, 3187], + [1966, 3178], + [1964, 3169], + [1973, 3167], + [1982, 3159], + [1995, 3160], + [1984, 3168], + [1970, 3169], + [1975, 3181], + [1992, 3194], + [2006, 3176], + [1992, 3168], + [1995, 3160], + [1995, 3151], + [1992, 3143], + [2004, 3136], + [2005, 3122], + [2015, 3113], + [2029, 3111], + [2027, 3099], + [2030, 3111], + [2032, 3122], + [2033, 3131], + [2040, 3117], + [2034, 3104], + [2028, 3084], + [2038, 3099], + [2049, 3097], + [2049, 3111], + [2050, 3091], + [2063, 3095], + [2055, 3091], + [2067, 3083], + [2063, 3072], + [2056, 3062], + [2061, 3048], + [2070, 3041], + [2089, 3046], + [2100, 3055], + [2102, 3063], + [2112, 3053], + [2117, 3067], + [2135, 3066], + [2157, 3075], + [2168, 3085], + [2170, 3073], + [2159, 3071], + [2151, 3057], + [2162, 3052], + [2161, 3042], + [2167, 3033], + [2160, 3042], + [2166, 3033], + [2153, 3047], + [2145, 3049], + [2139, 3058], + [2149, 3057], + [2145, 3066], + [2146, 3058], + [2135, 3053], + [2141, 3044], + [2133, 3044], + [2120, 3039], + [2130, 3043], + [2143, 3039], + [2130, 3031], + [2120, 3031], + [2128, 3029], + [2139, 3034], + [2131, 3029], + [2144, 3026], + [2149, 3016], + [2139, 3014], + [2136, 3023], + [2128, 3024], + [2111, 3022], + [2105, 3013], + [2112, 3005], + [2112, 2997], + [2101, 2994], + [2113, 2997], + [2110, 2989], + [2117, 2980], + [2121, 2969], + [2123, 2959], + [2122, 2972], + [2143, 2972], + [2146, 2953], + [2134, 2950], + [2146, 2952], + [2128, 2948], + [2148, 2944], + [2138, 2937], + [2151, 2942], + [2151, 2925], + [2169, 2922], + [2169, 2913], + [2164, 2901], + [2172, 2905], + [2164, 2899], + [2172, 2904], + [2173, 2896], + [2182, 2898], + [2171, 2891], + [2197, 2906], + [2222, 2930], + [2233, 2910], + [2223, 2900], + [2214, 2891], + [2224, 2898], + [2222, 2890], + [2238, 2893], + [2247, 2903], + [2243, 2890], + [2234, 2890], + [2243, 2890], + [2240, 2879], + [2231, 2875], + [2222, 2879], + [2230, 2874], + [2218, 2869], + [2204, 2876], + [2212, 2882], + [2189, 2864], + [2202, 2860], + [2215, 2861], + [2225, 2864], + [2223, 2850], + [2235, 2849], + [2247, 2857], + [2249, 2849], + [2247, 2858], + [2254, 2857], + [2254, 2869], + [2265, 2863], + [2266, 2852], + [2258, 2849], + [2247, 2840], + [2239, 2847], + [2245, 2836], + [2227, 2821], + [2224, 2811], + [2224, 2798], + [2213, 2786], + [2201, 2782], + [2183, 2795], + [2185, 2785], + [2169, 2795], + [2182, 2791], + [2189, 2777], + [2187, 2789], + [2194, 2781], + [2202, 2779], + [2201, 2767], + [2206, 2783], + [2221, 2785], + [2219, 2769], + [2225, 2753], + [2215, 2742], + [2205, 2729], + [2197, 2729], + [2194, 2738], + [2194, 2739], + [2194, 2755], + [2182, 2752], + [2174, 2747], + [2173, 2755], + [2160, 2752], + [2156, 2760], + [2143, 2768], + [2147, 2758], + [2156, 2753], + [2171, 2755], + [2173, 2743], + [2169, 2731], + [2174, 2719], + [2166, 2716], + [2166, 2734], + [2153, 2737], + [2147, 2719], + [2131, 2733], + [2122, 2729], + [2120, 2717], + [2111, 2721], + [2109, 2729], + [2101, 2738], + [2102, 2728], + [2096, 2720], + [2089, 2733], + [2089, 2725], + [2095, 2716], + [2094, 2708], + [2085, 2712], + [2085, 2696], + [2076, 2696], + [2072, 2685], + [2059, 2697], + [2049, 2692], + [2032, 2681], + [2025, 2666], + [2003, 2662], + [2024, 2665], + [2013, 2642], + [1998, 2644], + [1987, 2638], + [1978, 2642], + [1967, 2625], + [1964, 2614], + [1951, 2608], + [1930, 2593], + [1918, 2595], + [1926, 2593], + [1915, 2589], + [1904, 2598], + [1900, 2594], + [1900, 2584], + [1890, 2593], + [1895, 2584], + [1905, 2596], + [1911, 2585], + [1956, 2606], + [1967, 2613], + [1969, 2624], + [1978, 2628], + [2004, 2639], + [2012, 2632], + [2026, 2655], + [2049, 2671], + [2059, 2679], + [2058, 2691], + [2072, 2682], + [2078, 2690], + [2094, 2662], + [2087, 2688], + [2094, 2698], + [2110, 2698], + [2114, 2706], + [2106, 2713], + [2119, 2709], + [2130, 2706], + [2123, 2698], + [2117, 2680], + [2108, 2678], + [2116, 2679], + [2113, 2655], + [2117, 2647], + [2105, 2636], + [2099, 2604], + [2094, 2591], + [2088, 2575], + [2088, 2564], + [2098, 2578], + [2089, 2586], + [2096, 2588], + [2096, 2598], + [2105, 2606], + [2103, 2616], + [2107, 2625], + [2110, 2637], + [2118, 2641], + [2131, 2626], + [2121, 2635], + [2125, 2648], + [2116, 2655], + [2115, 2668], + [2123, 2673], + [2123, 2681], + [2131, 2676], + [2123, 2681], + [2122, 2673], + [2122, 2689], + [2131, 2689], + [2124, 2697], + [2131, 2705], + [2125, 2716], + [2140, 2715], + [2141, 2707], + [2145, 2698], + [2140, 2690], + [2130, 2684], + [2140, 2689], + [2141, 2697], + [2152, 2697], + [2145, 2714], + [2158, 2732], + [2160, 2716], + [2166, 2704], + [2175, 2712], + [2189, 2715], + [2198, 2718], + [2218, 2708], + [2211, 2697], + [2214, 2686], + [2206, 2689], + [2196, 2694], + [2199, 2685], + [2209, 2684], + [2219, 2687], + [2232, 2692], + [2234, 2683], + [2231, 2693], + [2219, 2691], + [2219, 2705], + [2222, 2713], + [2229, 2703], + [2223, 2714], + [2219, 2728], + [2228, 2711], + [2236, 2709], + [2230, 2717], + [2239, 2719], + [2239, 2727], + [2230, 2728], + [2243, 2727], + [2243, 2739], + [2249, 2751], + [2259, 2749], + [2267, 2747], + [2258, 2739], + [2268, 2742], + [2263, 2733], + [2268, 2745], + [2281, 2736], + [2290, 2737], + [2289, 2729], + [2280, 2735], + [2272, 2737], + [2277, 2727], + [2285, 2730], + [2269, 2715], + [2268, 2724], + [2262, 2715], + [2264, 2707], + [2276, 2711], + [2276, 2719], + [2284, 2718], + [2291, 2709], + [2299, 2706], + [2308, 2710], + [2316, 2713], + [2319, 2705], + [2330, 2694], + [2326, 2667], + [2325, 2656], + [2326, 2666], + [2328, 2676], + [2339, 2679], + [2347, 2680], + [2348, 2668], + [2340, 2674], + [2350, 2664], + [2335, 2670], + [2347, 2664], + [2334, 2668], + [2350, 2663], + [2361, 2659], + [2363, 2647], + [2352, 2640], + [2360, 2639], + [2369, 2642], + [2363, 2632], + [2376, 2630], + [2385, 2623], + [2398, 2630], + [2394, 2617], + [2378, 2613], + [2368, 2596], + [2379, 2613], + [2390, 2618], + [2407, 2612], + [2418, 2613], + [2433, 2625], + [2441, 2618], + [2439, 2607], + [2429, 2605], + [2426, 2597], + [2418, 2593], + [2405, 2582], + [2392, 2577], + [2405, 2581], + [2414, 2590], + [2427, 2595], + [2437, 2600], + [2438, 2584], + [2439, 2570], + [2436, 2559], + [2441, 2569], + [2436, 2581], + [2445, 2591], + [2453, 2584], + [2452, 2569], + [2456, 2573], + [2456, 2561], + [2450, 2541], + [2438, 2517], + [2453, 2536], + [2453, 2547], + [2464, 2553], + [2473, 2550], + [2479, 2542], + [2493, 2550], + [2489, 2535], + [2493, 2547], + [2503, 2550], + [2499, 2534], + [2487, 2519], + [2494, 2527], + [2500, 2519], + [2494, 2508], + [2502, 2516], + [2492, 2498], + [2508, 2510], + [2503, 2491], + [2493, 2482], + [2505, 2492], + [2507, 2501], + [2521, 2474], + [2519, 2466], + [2533, 2460], + [2551, 2454], + [2550, 2439], + [2538, 2436], + [2534, 2424], + [2550, 2433], + [2561, 2435], + [2577, 2440], + [2569, 2426], + [2560, 2429], + [2548, 2429], + [2558, 2427], + [2575, 2420], + [2567, 2416], + [2550, 2402], + [2540, 2404], + [2532, 2403], + [2541, 2397], + [2551, 2401], + [2559, 2401], + [2569, 2400], + [2580, 2407], + [2573, 2392], + [2576, 2381], + [2567, 2381], + [2579, 2375], + [2561, 2368], + [2552, 2365], + [2547, 2357], + [2554, 2368], + [2550, 2377], + [2548, 2377], + [2548, 2368], + [2539, 2363], + [2545, 2375], + [2547, 2385], + [2541, 2390], + [2533, 2390], + [2546, 2385], + [2543, 2374], + [2532, 2359], + [2528, 2350], + [2528, 2340], + [2533, 2327], + [2535, 2337], + [2535, 2328], + [2536, 2337], + [2537, 2329], + [2529, 2341], + [2529, 2349], + [2529, 2358], + [2537, 2358], + [2546, 2349], + [2541, 2324], + [2533, 2326], + [2529, 2317], + [2537, 2316], + [2541, 2324], + [2546, 2313], + [2551, 2305], + [2542, 2300], + [2551, 2305], + [2549, 2297], + [2553, 2286], + [2545, 2278], + [2555, 2280], + [2557, 2268], + [2543, 2268], + [2553, 2267], + [2553, 2257], + [2561, 2256], + [2574, 2239], + [2565, 2238], + [2556, 2242], + [2538, 2236], + [2546, 2233], + [2560, 2237], + [2573, 2235], + [2583, 2225], + [2565, 2226], + [2573, 2223], + [2578, 2212], + [2567, 2215], + [2578, 2212], + [2580, 2224], + [2588, 2213], + [2576, 2211], + [2568, 2210], + [2560, 2215], + [2524, 2219], + [2518, 2229], + [2522, 2219], + [2561, 2205], + [2585, 2205], + [2613, 2180], + [2602, 2186], + [2609, 2177], + [2600, 2185], + [2607, 2177], + [2599, 2184], + [2590, 2182], + [2608, 2176], + [2587, 2173], + [2568, 2165], + [2588, 2171], + [2604, 2169], + [2614, 2167], + [2624, 2153], + [2621, 2142], + [2629, 2151], + [2634, 2142], + [2592, 2140], + [2617, 2140], + [2602, 2139], + [2613, 2137], + [2626, 2141], + [2625, 2126], + [2621, 2134], + [2609, 2133], + [2583, 2127], + [2578, 2122], + [2586, 2122], + [2610, 2122], + [2631, 2118], + [2623, 2116], + [2622, 2106], + [2614, 2104], + [2621, 2100], + [2611, 2100], + [2619, 2100], + [2611, 2098], + [2619, 2096], + [2617, 2088], + [2618, 2081], + [2626, 2081], + [2625, 2071], + [2623, 2060], + [2623, 2052], + [2628, 2063], + [2637, 2052], + [2627, 2048], + [2614, 2046], + [2616, 2038], + [2615, 2046], + [2623, 2039], + [2630, 2047], + [2642, 2037], + [2654, 2038], + [2665, 2027], + [2660, 2016], + [2668, 2008], + [2651, 2007], + [2650, 2015], + [2642, 2014], + [2630, 2013], + [2615, 2010], + [2609, 2001], + [2594, 2006], + [2600, 1998], + [2569, 1988], + [2560, 1993], + [2544, 1979], + [2534, 1973], + [2546, 1971], + [2553, 1979], + [2561, 1979], + [2574, 1977], + [2589, 1980], + [2600, 1989], + [2612, 1993], + [2621, 1996], + [2627, 1986], + [2619, 1979], + [2628, 1985], + [2644, 1982], + [2645, 1973], + [2645, 1982], + [2654, 1976], + [2660, 1967], + [2661, 1950], + [2636, 1947], + [2645, 1951], + [2656, 1944], + [2659, 1932], + [2647, 1932], + [2653, 1923], + [2642, 1916], + [2634, 1916], + [2628, 1904], + [2611, 1886], + [2602, 1885], + [2602, 1877], + [2623, 1880], + [2620, 1872], + [2610, 1871], + [2625, 1870], + [2635, 1876], + [2651, 1875], + [2654, 1865], + [2643, 1861], + [2658, 1859], + [2659, 1873], + [2666, 1852], + [2656, 1852], + [2651, 1844], + [2616, 1843], + [2638, 1839], + [2621, 1832], + [2635, 1832], + [2620, 1816], + [2630, 1820], + [2624, 1809], + [2629, 1818], + [2645, 1832], + [2654, 1830], + [2649, 1822], + [2649, 1813], + [2654, 1823], + [2666, 1830], + [2670, 1846], + [2682, 1844], + [2696, 1852], + [2709, 1834], + [2700, 1832], + [2707, 1822], + [2699, 1821], + [2709, 1819], + [2711, 1809], + [2728, 1808], + [2739, 1799], + [2730, 1788], + [2714, 1780], + [2695, 1788], + [2680, 1779], + [2673, 1787], + [2663, 1781], + [2650, 1776], + [2639, 1775], + [2647, 1769], + [2638, 1763], + [2629, 1758], + [2614, 1740], + [2622, 1746], + [2630, 1753], + [2638, 1754], + [2666, 1774], + [2702, 1771], + [2716, 1767], + [2728, 1770], + [2723, 1762], + [2708, 1766], + [2676, 1764], + [2712, 1761], + [2691, 1750], + [2689, 1728], + [2696, 1744], + [2700, 1752], + [2716, 1762], + [2724, 1758], + [2747, 1755], + [2745, 1745], + [2753, 1751], + [2751, 1769], + [2742, 1821], + [2729, 1831], + [2739, 1825], + [2735, 1831], + [2727, 1831], + [2737, 1832], + [2729, 1836], + [2739, 1840], + [2730, 1844], + [2725, 1852], + [2736, 1847], + [2735, 1858], + [2731, 1871], + [2732, 1861], + [2722, 1868], + [2730, 1875], + [2725, 1889], + [2723, 1899], + [2714, 1903], + [2722, 1907], + [2714, 1907], + [2715, 1915], + [2717, 1924], + [2712, 1938], + [2697, 1944], + [2707, 1951], + [2708, 1960], + [2700, 1956], + [2703, 1972], + [2705, 1983], + [2706, 1998], + [2699, 2008], + [2708, 2008], + [2704, 2009], + [2704, 2029], + [2694, 2049], + [2681, 2049], + [2697, 2049], + [2694, 2057], + [2691, 2073], + [2699, 2089], + [2694, 2109], + [2690, 2171], + [2687, 2180], + [2688, 2197], + [2682, 2243], + [2675, 2252], + [2674, 2265], + [2682, 2290], + [2674, 2287], + [2679, 2300], + [2671, 2305], + [2662, 2299], + [2651, 2289], + [2654, 2300], + [2667, 2308], + [2681, 2323], + [2710, 2049], + [2733, 1891], + [2764, 1727], + [2776, 1685], + [2767, 1679], + [2765, 1683], + [2754, 1683], + [2743, 1689], + [2734, 1703], + [2720, 1709], + [2711, 1708], + [2699, 1700], + [2690, 1686], + [2673, 1680], + [2681, 1678], + [2681, 1665], + [2678, 1656], + [2675, 1639], + [2680, 1631], + [2681, 1644], + [2688, 1654], + [2691, 1667], + [2694, 1673], + [2694, 1683], + [2699, 1691], + [2710, 1697], + [2719, 1697], + [2734, 1688], + [2756, 1669], + [2746, 1666], + [2748, 1657], + [2757, 1661], + [2765, 1660], + [2762, 1670], + [2754, 1671], + [2767, 1674], + [2781, 1626], + [2810, 1522], + [2794, 1521], + [2783, 1526], + [2776, 1535], + [2765, 1535], + [2744, 1531], + [2734, 1510], + [2745, 1515], + [2762, 1525], + [2766, 1513], + [2764, 1505], + [2781, 1510], + [2786, 1520], + [2809, 1520], + [2812, 1494], + [2828, 1438], + [2850, 1332], + [2862, 1242], + [2863, 1186], + [2858, 1103], + [2849, 1075], + [2847, 1025], + [2832, 985], + [2814, 958], + [2810, 966], + [2796, 966], + [2794, 977], + [2811, 986], + [2817, 1021], + [2830, 1025], + [2739, 1025], + [2831, 1026], + [2830, 1057], + [2842, 1063], + [2845, 1081], + [2836, 1076], + [2850, 1090], + [2848, 1101], + [2855, 1117], + [2859, 1174], + [2853, 1235], + [2844, 1227], + [2836, 1240], + [2835, 1232], + [2827, 1235], + [2835, 1242], + [2838, 1253], + [2846, 1252], + [2844, 1263], + [2842, 1254], + [2828, 1252], + [2831, 1261], + [2839, 1279], + [2828, 1273], + [2811, 1286], + [2820, 1277], + [2827, 1261], + [2824, 1246], + [2808, 1252], + [2806, 1262], + [2807, 1250], + [2794, 1258], + [2791, 1266], + [2785, 1277], + [2776, 1277], + [2788, 1262], + [2768, 1263], + [2759, 1272], + [2751, 1272], + [2775, 1260], + [2790, 1259], + [2797, 1240], + [2784, 1243], + [2802, 1233], + [2777, 1234], + [2792, 1228], + [2798, 1220], + [2800, 1225], + [2809, 1225], + [2811, 1217], + [2804, 1215], + [2812, 1215], + [2820, 1205], + [2829, 1202], + [2842, 1199], + [2854, 1187], + [2851, 1160], + [2827, 1161], + [2806, 1154], + [2797, 1161], + [2788, 1159], + [2776, 1176], + [2754, 1175], + [2744, 1183], + [2740, 1195], + [2724, 1204], + [2713, 1198], + [2708, 1213], + [2699, 1221], + [2703, 1229], + [2705, 1209], + [2710, 1195], + [2723, 1193], + [2724, 1179], + [2739, 1170], + [2755, 1166], + [2784, 1148], + [2797, 1145], + [2797, 1134], + [2785, 1123], + [2794, 1125], + [2799, 1134], + [2811, 1136], + [2819, 1131], + [2829, 1145], + [2848, 1143], + [2850, 1123], + [2846, 1108], + [2821, 1092], + [2811, 1094], + [2788, 1088], + [2770, 1081], + [2762, 1081], + [2734, 1068], + [2712, 1051], + [2704, 1048], + [2653, 1025], + [2626, 1005], + [2606, 1020], + [2598, 1022], + [2579, 1020], + [2565, 1004], + [2548, 1023], + [2540, 1034], + [2511, 1046], + [2520, 1038], + [2516, 1024], + [2494, 1012], + [2478, 1004], + [2465, 1002], + [2447, 992], + [2429, 1008], + [2429, 1016], + [2444, 991], + [2428, 951], + [2424, 940], + [2402, 935], + [2393, 923], + [2397, 914], + [2372, 915], + [2356, 945], + [2341, 955], + [2319, 960], + [2308, 959], + [2304, 970], + [2295, 978], + [2284, 980], + [2288, 963], + [2275, 966], + [2264, 962], + [2261, 948], + [2247, 958], + [2242, 944], + [2231, 944], + [2223, 938], + [2208, 948], + [2194, 947], + [2180, 922], + [2166, 911], + [2120, 900], + [2099, 866], + [2072, 842], + [2062, 814], + [2047, 809], + [2057, 808], + [2066, 816], + [2073, 841], + [2100, 866], + [2122, 900], + [2169, 909], + [2181, 920], + [2189, 940], + [2197, 945], + [2207, 945], + [2221, 935], + [2241, 938], + [2250, 948], + [2258, 945], + [2254, 944], + [2264, 944], + [2265, 958], + [2283, 955], + [2283, 943], + [2283, 955], + [2291, 962], + [2288, 976], + [2301, 969], + [2302, 954], + [2312, 951], + [2302, 939], + [2312, 951], + [2331, 947], + [2341, 939], + [2353, 918], + [2376, 901], + [2392, 899], + [2403, 905], + [2410, 915], + [2434, 923], + [2443, 897], + [2449, 886], + [2458, 880], + [2452, 849], + [2450, 817], + [2451, 828], + [2455, 820], + [2484, 802], + [2500, 809], + [2509, 786], + [2517, 740], + [2528, 737], + [2529, 728], + [2521, 724], + [2523, 692], + [2527, 667], + [2544, 646], + [2561, 636], + [2576, 628], + [2592, 611], + [2605, 617], + [2619, 589], + [2588, 563], + [2612, 577], + [2624, 560], + [2617, 551], + [2597, 542], + [2619, 548], + [2629, 561], + [2641, 544], + [2646, 530], + [2641, 506], + [2649, 467], + [2641, 460], + [2652, 461], + [2647, 496], + [2652, 506], + [2672, 497], + [2674, 489], + [2683, 466], + [2710, 452], + [2710, 447], + [2687, 447], + [2681, 435], + [2691, 414], + [2689, 388], + [2698, 373], + [2688, 370], + [2690, 362], + [2698, 371], + [2701, 360], + [2712, 349], + [2693, 330], + [2715, 349], + [2732, 333], + [2772, 327], + [2776, 313], + [2766, 291], + [2774, 286], + [2775, 269], + [2779, 245], + [2769, 219], + [2770, 200], + [2771, 198], + [2771, 217], + [2781, 242], + [2778, 255], + [2789, 269], + [2802, 270], + [2816, 219], + [2809, 246], + [2804, 273], + [2791, 273], + [2781, 259], + [2778, 273], + [2781, 283], + [2772, 293], + [2780, 320], + [2773, 332], + [2765, 334], + [2773, 340], + [2781, 342], + [2771, 351], + [2773, 359], + [2765, 363], + [2763, 353], + [2770, 343], + [2762, 350], + [2754, 351], + [2761, 342], + [2758, 334], + [2738, 337], + [2724, 352], + [2714, 355], + [2692, 390], + [2696, 410], + [2688, 426], + [2686, 440], + [2710, 438], + [2714, 453], + [2705, 463], + [2692, 467], + [2678, 503], + [2667, 511], + [2667, 531], + [2660, 549], + [2657, 558], + [2648, 577], + [2639, 593], + [2636, 605], + [2628, 617], + [2618, 623], + [2611, 637], + [2612, 647], + [2648, 642], + [2652, 631], + [2680, 636], + [2695, 628], + [2689, 611], + [2691, 606], + [2680, 606], + [2665, 598], + [2693, 601], + [2719, 614], + [2682, 587], + [2693, 585], + [2725, 604], + [2703, 584], + [2717, 587], + [2719, 579], + [2709, 572], + [2718, 574], + [2705, 560], + [2717, 560], + [2726, 549], + [2742, 557], + [2740, 548], + [2762, 530], + [2771, 528], + [2744, 515], + [2760, 517], + [2775, 513], + [2774, 505], + [2772, 493], + [2783, 484], + [2777, 475], + [2768, 473], + [2783, 474], + [2790, 452], + [2790, 442], + [2782, 432], + [2794, 428], + [2792, 420], + [2801, 402], + [2807, 398], + [2807, 390], + [2822, 377], + [2834, 342], + [2845, 336], + [2845, 328], + [2867, 287], + [2866, 272], + [2881, 247], + [2883, 232], + [2903, 188], + [2934, 195], + [2949, 205], + [2940, 206], + [2931, 197], + [2913, 231], + [2899, 250], + [2900, 262], + [2889, 292], + [2883, 304], + [2840, 375], + [2838, 385], + [2831, 398], + [2826, 407], + [2818, 413], + [2818, 421], + [2806, 440], + [2808, 449], + [2804, 459], + [2806, 475], + [2800, 484], + [2803, 498], + [2794, 527], + [2803, 539], + [2814, 534], + [2824, 522], + [2849, 520], + [2863, 487], + [2859, 470], + [2863, 455], + [2905, 395], + [2904, 379], + [2925, 355], + [2925, 344], + [2917, 328], + [2916, 279], + [2937, 235], + [2951, 215], + [2950, 206], + [2919, 278], + [2921, 332], + [2927, 342], + [2950, 353], + [2964, 337], + [2974, 333], + [2989, 342], + [2999, 341], + [3014, 334], + [3014, 326], + [3026, 331], + [3043, 337], + [3042, 324], + [3051, 313], + [3059, 335], + [3067, 337], + [3067, 329], + [3089, 320], + [3123, 339], + [3106, 323], + [3103, 315], + [3108, 323], + [3116, 316], + [3106, 310], + [3102, 298], + [3092, 300], + [3094, 292], + [3090, 284], + [3089, 263], + [3088, 247], + [3094, 233], + [3083, 233], + [3079, 212], + [3083, 183], + [3073, 175], + [3082, 160], + [3078, 176], + [3081, 211], + [3091, 211], + [3091, 225], + [3101, 231], + [3107, 243], + [3112, 254], + [3115, 241], + [3125, 229], + [3125, 216], + [3134, 215], + [3135, 205], + [3136, 195], + [3128, 190], + [3121, 205], + [3110, 220], + [3099, 209], + [3109, 214], + [3124, 185], + [3134, 177], + [3138, 168], + [3148, 152], + [3142, 174], + [3152, 166], + [3162, 160], + [3165, 149], + [3160, 137], + [3152, 130], + [3161, 129], + [3169, 133], + [3173, 123], + [3189, 124], + [3195, 120], + [3195, 105], + [3196, 91], + [3198, 101], + [3204, 92], + [3203, 101], + [3213, 94], + [3208, 112], + [3213, 100], + [3221, 100], + [3227, 80], + [3204, 71], + [3215, 71], + [3211, 60], + [3221, 59], + [3218, 68], + [3229, 73], + [3237, 59], + [3235, 67], + [3247, 68], + [3255, 59], + [3263, 51], + [3271, 41], + [3261, 78], + [3267, 69], + [3281, 69], + [3276, 61], + [3284, 59], + [3281, 47], + [3292, 31], + [3300, 26], + [3314, 25], + [3322, 0], + [3313, -4], + [3317, 8], + [3309, 2], + [3313, -15], + [3321, -13], + [3337, -42], + [3345, -62], + [3345, -47], + [3353, -42], + [3365, -42], + [3369, -57], + [3360, -67], + [3368, -65], + [3363, -75], + [3372, -60], + [3374, -71], + [3377, -58], + [3384, -79], + [3386, -71], + [3385, -62], + [3398, -74], + [3402, -93], + [3412, -103], + [3414, -81], + [3418, -73], + [3409, -72], + [3414, -60], + [3423, -60], + [3424, -69], + [3433, -70], + [3437, -80], + [3440, -92], + [3443, -83], + [3448, -75], + [3445, -66], + [3447, -57], + [3439, -47], + [3430, -54], + [3427, -41], + [3446, -42], + [3451, -63], + [3459, -72], + [3471, -83], + [3478, -99], + [3476, -88], + [3480, -83], + [3480, -91], + [3488, -96], + [3483, -121], + [3490, -102], + [3490, -110], + [3495, -100], + [3496, -108], + [3505, -120], + [3502, -128], + [3508, -119], + [3497, -103], + [3507, -71], + [3517, -77], + [3526, -97], + [3517, -103], + [3517, -121], + [3520, -113], + [3539, -113], + [3543, -126], + [3550, -128], + [3562, -128], + [3568, -118], + [3571, -128], + [3582, -108], + [3585, -123], + [3584, -128], + [4224, -128], + [4224, 28], + [4216, 28], + [4216, 32], + [4224, 32], + [4220, 45], + [4212, 31], + [4166, 14], + [4145, 14], + [4156, 19], + [4169, 17], + [4164, 25], + [4180, 56], + [4172, 65], + [4165, 55], + [4139, 42], + [4141, 56], + [4130, 60], + [4130, 70], + [4123, 59], + [4113, 56], + [4113, 48], + [4121, 58], + [4132, 50], + [4132, 37], + [4124, 35], + [4120, 23], + [4105, 32], + [4110, 43], + [4106, 53], + [4109, 63], + [4104, 51], + [4095, 52], + [4091, 40], + [4107, 26], + [4111, 17], + [4124, 22], + [4147, 26], + [4142, 20], + [4125, 20], + [4106, 5], + [4095, 15], + [4079, 25], + [4077, 35], + [4068, 35], + [4059, 28], + [4073, 29], + [4047, 24], + [4068, 47], + [4063, 104], + [4068, 100], + [4068, 85], + [4070, 70], + [4074, 81], + [4074, 89], + [4069, 100], + [4059, 114], + [4063, 125], + [4041, 131], + [4029, 146], + [4032, 167], + [4021, 160], + [4011, 142], + [4012, 127], + [4027, 115], + [4026, 124], + [4033, 112], + [4045, 113], + [4058, 104], + [3959, 139], + [3939, 136], + [3944, 144], + [3934, 136], + [3891, 126], + [3850, 107], + [3815, 101], + [3776, 100], + [3776, 114], + [3774, 104], + [3743, 92], + [3709, 50], + [3696, 47], + [3690, 104], + [3686, 124], + [3688, 114], + [3693, 97], + [3714, 110], + [3721, 100], + [3716, 84], + [3729, 90], + [3722, 72], + [3740, 94], + [3732, 90], + [3724, 99], + [3739, 96], + [3766, 111], + [3762, 128], + [3764, 154], + [3764, 163], + [3762, 172], + [3750, 176], + [3748, 174], + [3748, 163], + [3753, 155], + [3732, 127], + [3723, 149], + [3731, 152], + [3736, 163], + [3725, 155], + [3717, 146], + [3701, 137], + [3680, 146], + [3646, 143], + [3649, 154], + [3667, 162], + [3671, 171], + [3668, 182], + [3665, 174], + [3659, 163], + [3651, 161], + [3631, 155], + [3641, 152], + [3647, 137], + [3636, 139], + [3625, 129], + [3579, 133], + [3574, 138], + [3574, 130], + [3620, 127], + [3634, 114], + [3648, 111], + [3644, 128], + [3654, 114], + [3652, 98], + [3642, 88], + [3603, 83], + [3581, 72], + [3572, 63], + [3560, 74], + [3562, 83], + [3567, 71], + [3568, 79], + [3560, 90], + [3560, 81], + [3554, 109], + [3563, 117], + [3579, 154], + [3591, 202], + [3606, 211], + [3604, 232], + [3594, 220], + [3602, 221], + [3603, 216], + [3590, 216], + [3584, 208], + [3567, 199], + [3563, 188], + [3557, 163], + [3536, 167], + [3534, 178], + [3544, 204], + [3534, 201], + [3517, 204], + [3506, 197], + [3489, 199], + [3480, 182], + [3480, 152], + [3452, 160], + [3457, 178], + [3443, 162], + [3445, 151], + [3456, 154], + [3468, 142], + [3479, 147], + [3492, 146], + [3501, 139], + [3510, 126], + [3517, 137], + [3516, 157], + [3508, 169], + [3501, 173], + [3501, 181], + [3520, 180], + [3521, 162], + [3526, 152], + [3539, 151], + [3536, 139], + [3519, 125], + [3503, 129], + [3481, 137], + [3454, 124], + [3433, 135], + [3411, 138], + [3408, 147], + [3385, 150], + [3378, 158], + [3356, 148], + [3354, 158], + [3352, 166], + [3340, 177], + [3325, 195], + [3322, 224], + [3329, 238], + [3352, 228], + [3343, 234], + [3336, 243], + [3327, 254], + [3328, 279], + [3335, 304], + [3332, 345], + [3327, 334], + [3326, 303], + [3331, 293], + [3323, 290], + [3318, 279], + [3294, 237], + [3237, 212], + [3230, 221], + [3215, 219], + [3219, 238], + [3204, 255], + [3216, 266], + [3218, 284], + [3218, 273], + [3232, 275], + [3245, 267], + [3246, 283], + [3252, 272], + [3260, 282], + [3251, 296], + [3253, 319], + [3243, 334], + [3245, 359], + [3235, 335], + [3234, 317], + [3229, 307], + [3215, 301], + [3212, 293], + [3201, 292], + [3197, 284], + [3186, 281], + [3181, 273], + [3176, 283], + [3181, 305], + [3164, 321], + [3166, 333], + [3183, 349], + [3182, 371], + [3191, 379], + [3179, 390], + [3181, 415], + [3163, 396], + [3151, 374], + [3146, 353], + [3137, 356], + [3124, 368], + [3121, 356], + [3095, 352], + [3084, 345], + [3073, 352], + [3073, 360], + [3067, 369], + [3059, 367], + [3054, 351], + [3046, 354], + [3035, 358], + [3033, 368], + [3032, 381], + [3041, 381], + [3040, 403], + [3048, 413], + [3056, 410], + [3060, 419], + [3057, 429], + [3055, 413], + [3039, 425], + [3026, 419], + [3022, 410], + [3031, 406], + [3008, 384], + [3009, 373], + [3003, 382], + [2988, 386], + [2991, 396], + [2982, 397], + [2980, 381], + [2964, 385], + [2973, 372], + [2953, 364], + [2926, 392], + [2916, 389], + [2917, 404], + [2905, 414], + [2885, 444], + [2876, 464], + [2889, 462], + [2899, 466], + [2911, 456], + [2900, 467], + [2912, 480], + [2938, 493], + [2937, 509], + [2926, 506], + [2921, 515], + [2932, 501], + [2926, 487], + [2912, 482], + [2903, 469], + [2894, 465], + [2884, 464], + [2876, 474], + [2878, 489], + [2869, 506], + [2865, 521], + [2869, 532], + [2862, 521], + [2864, 539], + [2857, 540], + [2857, 530], + [2830, 530], + [2825, 540], + [2821, 548], + [2820, 558], + [2812, 559], + [2804, 569], + [2794, 578], + [2794, 592], + [2803, 590], + [2807, 598], + [2799, 606], + [2807, 599], + [2820, 600], + [2820, 610], + [2807, 611], + [2799, 614], + [2799, 623], + [2790, 623], + [2791, 632], + [2786, 641], + [2781, 646], + [2772, 646], + [2768, 656], + [2762, 673], + [2761, 692], + [2763, 702], + [2775, 719], + [2808, 731], + [2820, 745], + [2821, 757], + [2830, 752], + [2822, 757], + [2827, 765], + [2836, 760], + [2841, 769], + [2812, 765], + [2804, 779], + [2819, 788], + [2922, 777], + [2920, 767], + [2889, 763], + [2950, 766], + [2948, 758], + [2931, 760], + [2922, 756], + [2920, 741], + [2924, 743], + [2924, 751], + [2932, 748], + [2931, 758], + [2947, 752], + [2921, 726], + [2932, 731], + [2945, 733], + [2950, 742], + [2950, 757], + [2968, 754], + [2974, 775], + [2986, 773], + [2997, 769], + [3001, 760], + [2993, 723], + [2948, 727], + [2939, 716], + [2943, 705], + [2943, 718], + [2951, 724], + [2965, 720], + [2964, 711], + [2955, 697], + [2965, 708], + [2968, 720], + [2977, 718], + [2982, 710], + [2973, 702], + [2973, 688], + [2986, 677], + [3001, 662], + [2980, 636], + [3006, 661], + [2997, 626], + [3016, 655], + [3030, 647], + [3026, 625], + [3031, 633], + [3041, 633], + [3039, 644], + [3054, 645], + [3055, 612], + [3062, 638], + [3064, 619], + [3066, 627], + [3073, 636], + [3079, 637], + [3079, 615], + [3097, 615], + [3086, 614], + [3079, 627], + [3086, 642], + [3138, 673], + [3126, 688], + [3114, 701], + [3114, 709], + [3123, 714], + [3127, 706], + [3132, 693], + [3143, 678], + [3156, 686], + [3162, 676], + [3188, 663], + [3189, 651], + [3179, 639], + [3189, 647], + [3191, 661], + [3199, 659], + [3194, 669], + [3203, 669], + [3190, 672], + [3158, 694], + [3174, 695], + [3166, 703], + [3179, 709], + [3169, 713], + [3162, 703], + [3152, 705], + [3155, 730], + [3142, 737], + [3149, 722], + [3150, 714], + [3128, 741], + [3127, 732], + [3133, 724], + [3124, 731], + [3109, 733], + [3109, 745], + [3099, 743], + [3071, 760], + [3056, 766], + [3039, 765], + [3000, 790], + [2978, 791], + [2965, 802], + [2951, 798], + [2929, 805], + [2908, 818], + [2908, 841], + [2954, 817], + [2977, 812], + [3071, 771], + [3080, 767], + [3146, 750], + [3180, 749], + [3193, 741], + [3205, 741], + [3204, 727], + [3218, 717], + [3209, 729], + [3208, 737], + [3221, 737], + [3232, 740], + [3252, 747], + [3276, 744], + [3278, 729], + [3264, 721], + [3259, 736], + [3256, 726], + [3246, 723], + [3252, 713], + [3250, 699], + [3259, 692], + [3270, 680], + [3268, 688], + [3276, 686], + [3274, 677], + [3268, 666], + [3270, 658], + [3270, 666], + [3277, 681], + [3280, 670], + [3288, 674], + [3284, 682], + [3295, 670], + [3307, 676], + [3307, 687], + [3317, 667], + [3316, 655], + [3325, 660], + [3316, 685], + [3326, 677], + [3323, 686], + [3327, 695], + [3328, 707], + [3315, 720], + [3314, 734], + [3325, 737], + [3337, 734], + [3328, 731], + [3339, 733], + [3334, 722], + [3342, 722], + [3341, 710], + [3344, 699], + [3358, 707], + [3367, 704], + [3378, 692], + [3379, 677], + [3371, 668], + [3382, 673], + [3389, 686], + [3400, 687], + [3411, 688], + [3414, 675], + [3405, 663], + [3406, 649], + [3406, 657], + [3423, 670], + [3421, 654], + [3426, 680], + [3426, 669], + [3428, 680], + [3427, 669], + [3429, 679], + [3430, 655], + [3438, 684], + [3440, 663], + [3444, 683], + [3452, 672], + [3450, 648], + [3441, 646], + [3440, 632], + [3444, 645], + [3453, 632], + [3457, 671], + [3469, 662], + [3468, 648], + [3465, 639], + [3469, 648], + [3482, 657], + [3485, 643], + [3478, 633], + [3485, 642], + [3485, 631], + [3491, 648], + [3499, 648], + [3504, 657], + [3507, 649], + [3498, 638], + [3509, 647], + [3505, 618], + [3513, 649], + [3521, 655], + [3529, 640], + [3528, 648], + [3539, 654], + [3538, 676], + [3547, 684], + [3548, 676], + [3556, 661], + [3547, 661], + [3566, 646], + [3572, 632], + [3578, 622], + [3579, 632], + [3580, 617], + [3581, 636], + [3589, 632], + [3591, 619], + [3595, 611], + [3593, 624], + [3596, 611], + [3594, 622], + [3603, 640], + [3612, 637], + [3616, 624], + [3619, 631], + [3619, 616], + [3622, 626], + [3628, 617], + [3622, 608], + [3631, 604], + [3626, 628], + [3635, 629], + [3646, 633], + [3649, 618], + [3659, 623], + [3660, 614], + [3664, 624], + [3672, 625], + [3675, 621], + [3675, 601], + [3682, 624], + [3682, 614], + [3684, 625], + [3688, 617], + [3696, 625], + [3696, 610], + [3696, 624], + [3705, 623], + [3708, 605], + [3711, 619], + [3725, 619], + [3717, 615], + [3714, 605], + [3712, 597], + [3719, 609], + [3723, 594], + [3725, 602], + [3729, 615], + [3731, 601], + [3744, 603], + [3742, 585], + [3745, 604], + [3755, 603], + [3759, 593], + [3753, 578], + [3759, 594], + [3769, 599], + [3769, 582], + [3774, 591], + [3786, 587], + [3787, 573], + [3788, 562], + [3789, 588], + [3791, 576], + [3791, 585], + [3795, 575], + [3807, 575], + [3805, 567], + [3808, 577], + [3806, 567], + [3811, 576], + [3808, 566], + [3811, 575], + [3810, 566], + [3813, 575], + [3813, 566], + [3818, 578], + [3821, 566], + [3813, 562], + [3815, 545], + [3815, 558], + [3820, 564], + [3820, 554], + [3822, 563], + [3824, 555], + [3827, 564], + [3833, 556], + [3831, 564], + [3840, 549], + [3843, 567], + [3844, 558], + [3848, 568], + [3874, 569], + [3871, 561], + [3893, 547], + [3887, 537], + [3894, 548], + [3903, 539], + [3915, 532], + [3901, 517], + [3915, 531], + [3914, 521], + [3932, 517], + [3924, 517], + [3923, 494], + [3931, 505], + [3942, 489], + [3939, 504], + [3951, 499], + [3951, 485], + [3953, 490], + [3953, 501], + [3952, 511], + [3951, 522], + [3956, 514], + [3955, 525], + [3963, 520], + [3964, 528], + [3981, 513], + [3983, 491], + [3983, 507], + [3980, 517], + [3999, 530], + [4002, 518], + [4010, 512], + [4007, 520], + [4015, 515], + [4006, 521], + [4020, 536], + [4022, 527], + [4022, 537], + [4053, 542], + [4062, 541], + [4069, 516], + [4081, 505], + [4085, 489], + [4095, 491], + [4118, 501], + [4127, 503], + [4139, 498], + [4176, 494], + [4195, 485], + [4203, 471], + [4201, 484], + [4224, 482], + [4223, 473], + [4224, 476], + [4224, 589], + [4215, 588], + [4206, 596], + [4176, 603], + [4128, 621], + [4095, 627], + [4080, 631], + [4069, 636], + [4050, 635], + [4033, 648], + [4010, 651], + [3998, 657], + [3997, 648], + [3976, 661], + [3952, 670], + [3936, 670], + [3906, 681], + [3854, 682], + [3844, 675], + [3832, 683], + [3837, 677], + [3818, 677], + [3826, 689], + [3840, 691], + [3915, 686], + [4095, 635], + [4224, 592], + [4224, 4224], + [-128, 4224], + [-128, 4224] + ], + [[1747, 3583], [1749, 3583]], + [[2049, 3132], [2049, 3134]], + [[2049, 3135], [2049, 3136]], + [[2175, 3040], [2177, 3039]], + [[2177, 3039], [2178, 3039]], + [[2175, 3009], [2175, 3008]], + [[2175, 3004], [2175, 3001]], + [[1025, 2978], [1025, 2985]], + [[2303, 2955], [2303, 2957]], + [[2176, 2986], [2173, 2987]], + [[2304, 2928], [2304, 2926]], + [[2305, 2923], [2306, 2924]], + [[2303, 2915], [2304, 2913]], + [[2561, 2531], [2562, 2532]], + [[2551, 2559], [2551, 2559]], + [[2559, 2427], [2559, 2427]], + [[2559, 2206], [2561, 2206]], + [[2639, 2049], [2638, 2049]], + [[3071, 361], [3071, 360]], + [[855, 2206], [855, 2206], [855, 2206]], + [ + [854, 2206], + [843, 2201], + [834, 2208], + [843, 2201], + [854, 2206], + [854, 2206] + ], + [[2494, 2527], [2494, 2527], [2494, 2527]], + [ + [2495, 2527], + [2500, 2533], + [2504, 2543], + [2509, 2534], + [2500, 2524], + [2507, 2535], + [2495, 2527], + [2495, 2527] + ], + [[2504, 2513], [2504, 2523], [2504, 2513], [2504, 2513]], + [[2607, 2128], [2607, 2128], [2607, 2128]], + [[2637, 2042], [2637, 2042], [2637, 2042]], + [[2637, 2042], [2637, 2042], [2637, 2042]], + [[2665, 2017], [2665, 2017], [2665, 2017]], + [[2635, 1757], [2635, 1757], [2635, 1757]], + [[2635, 1757], [2635, 1757], [2635, 1757]], + [[2721, 1892], [2721, 1892], [2721, 1892]], + [[2720, 1893], [2720, 1893], [2720, 1893]], + [[2773, 1679], [2773, 1679], [2773, 1679]], + [[2444, 991], [2444, 991], [2444, 991]], + [[3178, 128], [3178, 128], [3178, 128]], + [[3176, 130], [3176, 130], [3176, 130]], + [[2799, 606], [2794, 593], [2799, 606], [2799, 606]], + [ + [2049, 3181], + [2049, 3183], + [2037, 3194], + [2047, 3190], + [2110, 3142], + [2156, 3116], + [2224, 3084], + [2223, 3073], + [2217, 3057], + [2208, 3059], + [2196, 3054], + [2207, 3053], + [2204, 3040], + [2195, 3037], + [2186, 3045], + [2186, 3034], + [2177, 3037], + [2169, 3036], + [2165, 3044], + [2169, 3055], + [2177, 3048], + [2175, 3061], + [2174, 3073], + [2174, 3084], + [2162, 3092], + [2155, 3102], + [2126, 3123], + [2118, 3121], + [2109, 3127], + [2103, 3102], + [2102, 3114], + [2075, 3126], + [2079, 3144], + [2069, 3142], + [2069, 3151], + [2059, 3159], + [2049, 3181], + [2049, 3181] + ], + [[2206, 3059], [2206, 3059], [2206, 3059]], + [[1578, 3811], [1578, 3811], [1578, 3811]], + [[1577, 3813], [1577, 3813], [1577, 3813]], + [ + [1578, 3811], + [1580, 3811], + [1580, 3819], + [1575, 3827], + [1566, 3832], + [1558, 3844], + [1563, 3846], + [1551, 3846], + [1555, 3864], + [1567, 3883], + [1601, 3834], + [1675, 3768], + [1675, 3752], + [1665, 3738], + [1662, 3717], + [1656, 3727], + [1658, 3712], + [1643, 3707], + [1641, 3717], + [1643, 3725], + [1653, 3726], + [1645, 3740], + [1642, 3750], + [1647, 3758], + [1648, 3748], + [1658, 3750], + [1657, 3738], + [1659, 3751], + [1647, 3759], + [1635, 3756], + [1620, 3755], + [1633, 3767], + [1625, 3770], + [1611, 3773], + [1621, 3786], + [1610, 3776], + [1612, 3786], + [1598, 3815], + [1589, 3821], + [1578, 3811], + [1578, 3811] + ], + [[1370, 3184], [1370, 3184], [1370, 3184]], + [[1370, 3184], [1373, 3183], [1370, 3184], [1370, 3184]], + [ + [2304, 2930], + [2298, 2928], + [2312, 2926], + [2301, 2920], + [2292, 2925], + [2295, 2914], + [2304, 2919], + [2313, 2926], + [2324, 2928], + [2335, 2918], + [2331, 2908], + [2320, 2918], + [2307, 2911], + [2321, 2916], + [2329, 2906], + [2316, 2904], + [2319, 2896], + [2308, 2899], + [2303, 2891], + [2290, 2890], + [2287, 2880], + [2286, 2892], + [2283, 2911], + [2296, 2905], + [2288, 2907], + [2288, 2922], + [2279, 2926], + [2287, 2927], + [2292, 2938], + [2303, 2934], + [2313, 2929], + [2304, 2930], + [2304, 2930] + ], + [ + [2316, 2895], + [2317, 2895], + [2316, 2901], + [2331, 2901], + [2332, 2889], + [2321, 2885], + [2323, 2898], + [2325, 2889], + [2315, 2882], + [2308, 2896], + [2316, 2895], + [2316, 2895] + ], + [ + [2304, 2850], + [2300, 2851], + [2311, 2859], + [2323, 2868], + [2339, 2871], + [2335, 2861], + [2341, 2873], + [2341, 2885], + [2350, 2887], + [2341, 2887], + [2335, 2895], + [2336, 2906], + [2344, 2910], + [2369, 2866], + [2369, 2856], + [2357, 2828], + [2348, 2824], + [2349, 2840], + [2346, 2854], + [2335, 2839], + [2339, 2853], + [2331, 2857], + [2317, 2851], + [2304, 2850], + [2304, 2850] + ], + [[2344, 2910], [2344, 2910], [2344, 2910]], + [[2344, 2910], [2344, 2910], [2344, 2910]], + [[2151, 2999], [2152, 2999], [2162, 3004], [2151, 2999], [2151, 2999]], + [[2151, 2999], [2151, 2999], [2151, 2999]], + [[2203, 2998], [2197, 2989], [2195, 2997], [2203, 2998], [2203, 2998]], + [[2195, 2997], [2195, 2997], [2195, 2997]], + [[2195, 2997], [2195, 2997], [2195, 2997]], + [[2205, 2728], [2212, 2734], [2212, 2719], [2205, 2728], [2205, 2728]], + [[2212, 2734], [2212, 2734], [2212, 2734]], + [ + [3840, 644], + [3835, 649], + [3857, 646], + [3851, 637], + [3840, 644], + [3840, 644] + ], + [[3835, 649], [3835, 649], [3835, 649]], + [[3835, 649], [3835, 649], [3835, 649]], + [[3451, 713], [3451, 713], [3451, 713]], + [[3451, 711], [3451, 711], [3451, 711]], + [[3911, 623], [3911, 623], [3911, 623]], + [[3911, 623], [3911, 623], [3911, 623]], + [ + [2048, 3128], + [2040, 3140], + [2049, 3147], + [2049, 3155], + [2057, 3142], + [2049, 3135], + [2058, 3126], + [2048, 3128], + [2048, 3128] + ], + [ + [2047, 3163], + [2042, 3168], + [2038, 3148], + [2012, 3172], + [2008, 3180], + [2009, 3189], + [2043, 3172], + [2047, 3173], + [2047, 3163], + [2047, 3163] + ], + [ + [1714, 3583], + [1714, 3583], + [1720, 3595], + [1719, 3607], + [1709, 3606], + [1706, 3619], + [1721, 3630], + [1725, 3638], + [1722, 3649], + [1714, 3654], + [1712, 3664], + [1702, 3665], + [1698, 3688], + [1695, 3700], + [1681, 3706], + [1682, 3717], + [1697, 3707], + [1743, 3631], + [1782, 3583], + [1797, 3564], + [1775, 3544], + [1780, 3552], + [1781, 3560], + [1765, 3583], + [1759, 3592], + [1749, 3589], + [1757, 3587], + [1747, 3583], + [1735, 3586], + [1734, 3595], + [1744, 3599], + [1746, 3591], + [1746, 3603], + [1752, 3595], + [1747, 3605], + [1755, 3598], + [1732, 3633], + [1742, 3604], + [1731, 3596], + [1724, 3583], + [1720, 3574], + [1712, 3574], + [1714, 3583], + [1714, 3583] + ], + [ + [1537, 3873], + [1553, 3869], + [1546, 3859], + [1536, 3859], + [1508, 3867], + [1500, 3864], + [1502, 3854], + [1492, 3859], + [1475, 3878], + [1495, 3855], + [1456, 3827], + [1419, 3828], + [1405, 3876], + [1410, 3886], + [1420, 3894], + [1451, 3893], + [1461, 3898], + [1493, 3895], + [1537, 3873], + [1537, 3873] + ], + [ + [1537, 3849], + [1544, 3849], + [1536, 3837], + [1526, 3847], + [1537, 3849], + [1537, 3849] + ], + [ + [1535, 3837], + [1535, 3836], + [1545, 3848], + [1551, 3833], + [1541, 3830], + [1535, 3837], + [1535, 3837] + ], + [[1597, 3801], [1602, 3800], [1594, 3793], [1597, 3801], [1597, 3801]], + [ + [1574, 3798], + [1568, 3800], + [1573, 3808], + [1582, 3802], + [1574, 3798], + [1574, 3798] + ], + [ + [1707, 3657], + [1699, 3648], + [1705, 3635], + [1683, 3630], + [1679, 3643], + [1688, 3651], + [1695, 3657], + [1707, 3657], + [1707, 3657] + ], + [[1699, 3678], [1699, 3678], [1699, 3678]], + [[1552, 3843], [1552, 3843], [1552, 3843]], + [ + [1607, 3779], + [1600, 3764], + [1591, 3765], + [1590, 3753], + [1582, 3770], + [1596, 3777], + [1598, 3791], + [1607, 3779], + [1607, 3779] + ], + [ + [1701, 3627], + [1695, 3621], + [1697, 3607], + [1693, 3598], + [1685, 3606], + [1681, 3624], + [1687, 3627], + [1701, 3627], + [1701, 3627] + ], + [[1585, 3757], [1585, 3757], [1585, 3757]], + [ + [1626, 3762], + [1614, 3751], + [1607, 3762], + [1607, 3774], + [1618, 3767], + [1629, 3771], + [1626, 3762], + [1626, 3762] + ], + [[1706, 3669], [1700, 3667], [1706, 3669], [1706, 3669]], + [ + [1756, 3583], + [1759, 3583], + [1767, 3578], + [1754, 3569], + [1742, 3575], + [1756, 3583], + [1756, 3583] + ], + [[2034, 3135], [2034, 3135], [2034, 3135]], + [[1765, 3569], [1771, 3572], [1756, 3560], [1765, 3569], [1765, 3569]], + [[1770, 3573], [1756, 3568], [1770, 3573], [1770, 3573]], + [ + [1763, 3543], + [1772, 3538], + [1771, 3524], + [1753, 3525], + [1745, 3532], + [1728, 3525], + [1744, 3539], + [1763, 3543], + [1763, 3543] + ], + [[1709, 3569], [1709, 3569], [1709, 3569]], + [[1736, 3539], [1736, 3539], [1736, 3539]], + [[1739, 3544], [1739, 3544], [1739, 3544]], + [[1791, 3485], [1791, 3485], [1791, 3485]], + [ + [1849, 3373], + [1867, 3355], + [1867, 3346], + [1850, 3363], + [1849, 3373], + [1849, 3373] + ], + [ + [1858, 3351], + [1867, 3346], + [1864, 3337], + [1858, 3337], + [1858, 3351], + [1858, 3351] + ], + [ + [1963, 3207], + [1966, 3211], + [1977, 3201], + [1967, 3196], + [1957, 3199], + [1963, 3207], + [1963, 3207] + ], + [[1960, 3190], [1955, 3192], [1960, 3190], [1960, 3190]], + [[1963, 3186], [1959, 3188], [1972, 3191], [1963, 3186], [1963, 3186]], + [[1962, 3230], [1962, 3230], [1962, 3230]], + [ + [1978, 3199], + [1979, 3203], + [1967, 3210], + [1975, 3212], + [1978, 3199], + [1978, 3199] + ], + [[1970, 3220], [1970, 3220], [1970, 3220]], + [[1965, 3227], [1959, 3233], [1965, 3227], [1965, 3227]], + [ + [1739, 3545], + [1734, 3542], + [1745, 3549], + [1754, 3543], + [1739, 3545], + [1739, 3545] + ], + [ + [1470, 3408], + [1478, 3409], + [1482, 3396], + [1474, 3399], + [1470, 3408], + [1470, 3408] + ], + [[1373, 3252], [1383, 3251], [1384, 3242], [1373, 3252], [1373, 3252]], + [[1385, 3243], [1386, 3252], [1385, 3243], [1385, 3243]], + [[1388, 3254], [1391, 3254], [1393, 3235], [1388, 3254], [1388, 3254]], + [[1385, 3241], [1385, 3241], [1385, 3241]], + [ + [1363, 3263], + [1372, 3257], + [1366, 3246], + [1355, 3254], + [1363, 3263], + [1363, 3263] + ], + [[1375, 3270], [1379, 3260], [1364, 3268], [1375, 3270], [1375, 3270]], + [[1345, 3298], [1357, 3301], [1345, 3298], [1345, 3298]], + [[1324, 3340], [1320, 3337], [1332, 3336], [1324, 3340], [1324, 3340]], + [[1389, 3392], [1390, 3402], [1403, 3394], [1389, 3392], [1389, 3392]], + [[1400, 3383], [1410, 3386], [1400, 3383], [1400, 3383]], + [ + [1367, 3279], + [1368, 3276], + [1358, 3270], + [1360, 3279], + [1371, 3285], + [1376, 3277], + [1367, 3279], + [1367, 3279] + ], + [ + [2547, 2560], + [2550, 2563], + [2537, 2585], + [2527, 2605], + [2518, 2609], + [2507, 2631], + [2495, 2652], + [2489, 2656], + [2489, 2671], + [2477, 2683], + [2477, 2691], + [2471, 2699], + [2463, 2703], + [2459, 2719], + [2447, 2724], + [2448, 2738], + [2438, 2750], + [2436, 2758], + [2421, 2770], + [2414, 2787], + [2405, 2799], + [2394, 2808], + [2383, 2815], + [2375, 2815], + [2384, 2825], + [2403, 2810], + [2470, 2722], + [2559, 2562], + [2620, 2456], + [2658, 2368], + [2685, 2336], + [2667, 2324], + [2658, 2346], + [2649, 2342], + [2648, 2334], + [2648, 2310], + [2648, 2332], + [2638, 2337], + [2640, 2347], + [2649, 2350], + [2646, 2368], + [2642, 2376], + [2641, 2384], + [2626, 2389], + [2634, 2389], + [2639, 2397], + [2630, 2395], + [2638, 2399], + [2630, 2395], + [2638, 2400], + [2627, 2396], + [2636, 2403], + [2624, 2397], + [2629, 2406], + [2626, 2422], + [2621, 2431], + [2617, 2442], + [2609, 2453], + [2618, 2451], + [2609, 2458], + [2607, 2469], + [2589, 2498], + [2569, 2511], + [2565, 2519], + [2561, 2527], + [2552, 2536], + [2548, 2550], + [2547, 2560], + [2547, 2560] + ], + [ + [2176, 3057], + [2176, 3055], + [2166, 3056], + [2162, 3069], + [2172, 3068], + [2176, 3057], + [2176, 3057] + ], + [ + [2107, 3073], + [2110, 3083], + [2098, 3093], + [2107, 3098], + [2117, 3090], + [2127, 3086], + [2144, 3086], + [2132, 3073], + [2122, 3073], + [2113, 3059], + [2107, 3073], + [2107, 3073] + ], + [ + [2117, 3120], + [2125, 3122], + [2128, 3114], + [2137, 3112], + [2142, 3101], + [2156, 3099], + [2164, 3083], + [2151, 3082], + [2144, 3090], + [2129, 3094], + [2121, 3093], + [2106, 3103], + [2117, 3120], + [2117, 3120] + ], + [ + [2303, 2981], + [2303, 2981], + [2289, 2967], + [2265, 2977], + [2273, 2988], + [2284, 2993], + [2275, 3005], + [2265, 3009], + [2254, 3021], + [2238, 3022], + [2226, 3010], + [2229, 3025], + [2218, 3031], + [2210, 3035], + [2215, 3043], + [2218, 3034], + [2235, 3027], + [2230, 3041], + [2216, 3043], + [2232, 3064], + [2286, 3012], + [2303, 2989], + [2338, 2945], + [2344, 2928], + [2330, 2936], + [2305, 2942], + [2307, 2954], + [2313, 2941], + [2320, 2951], + [2321, 2943], + [2329, 2947], + [2322, 2957], + [2309, 2959], + [2307, 2967], + [2303, 2981], + [2303, 2981] + ], + [ + [2304, 2858], + [2292, 2854], + [2291, 2864], + [2301, 2863], + [2297, 2875], + [2305, 2877], + [2303, 2885], + [2316, 2875], + [2324, 2870], + [2311, 2866], + [2304, 2858], + [2304, 2858] + ], + [ + [2303, 2885], + [2295, 2882], + [2286, 2872], + [2271, 2863], + [2271, 2877], + [2287, 2877], + [2292, 2887], + [2303, 2885], + [2303, 2885] + ], + [ + [2303, 2963], + [2303, 2955], + [2301, 2945], + [2289, 2951], + [2291, 2960], + [2300, 2955], + [2303, 2963], + [2303, 2963] + ], + [[2317, 2958], [2317, 2958], [2317, 2958]], + [ + [2175, 3002], + [2173, 3007], + [2185, 3008], + [2183, 3000], + [2175, 3001], + [2181, 2991], + [2179, 2983], + [2163, 2987], + [2166, 2997], + [2174, 2998], + [2164, 3000], + [2152, 2991], + [2175, 3002], + [2175, 3002] + ], + [[2175, 3012], [2161, 3009], [2175, 3012], [2175, 3012]], + [ + [2175, 3022], + [2166, 3019], + [2153, 3026], + [2150, 3017], + [2150, 3025], + [2141, 3029], + [2145, 3038], + [2144, 3048], + [2154, 3046], + [2153, 3037], + [2159, 3031], + [2175, 3031], + [2184, 3030], + [2175, 3022], + [2175, 3022] + ], + [[2161, 3068], [2165, 3054], [2161, 3068], [2161, 3068]], + [[2158, 3018], [2161, 3014], [2150, 3009], [2158, 3018], [2158, 3018]], + [[2255, 2896], [2257, 2892], [2255, 2896], [2255, 2896]], + [[2212, 3026], [2194, 3013], [2199, 3026], [2212, 3026], [2212, 3026]], + [[2212, 3025], [2216, 3018], [2202, 3012], [2212, 3025], [2212, 3025]], + [[2198, 3015], [2201, 3009], [2190, 3009], [2198, 3015], [2198, 3015]], + [[2221, 2867], [2217, 2869], [2221, 2867], [2221, 2867]], + [ + [2232, 2946], + [2236, 2939], + [2226, 2934], + [2218, 2933], + [2210, 2929], + [2217, 2943], + [2232, 2946], + [2232, 2946] + ], + [[2221, 2945], [2216, 2944], [2214, 2932], [2221, 2945], [2221, 2945]], + [[2211, 2928], [2211, 2928], [2211, 2928]], + [[2199, 2909], [2209, 2930], [2212, 2922], [2199, 2909], [2199, 2909]], + [ + [2233, 2855], + [2233, 2862], + [2247, 2868], + [2246, 2860], + [2233, 2855], + [2233, 2855] + ], + [[2247, 2858], [2247, 2867], [2247, 2858], [2247, 2858]], + [[2252, 2980], [2252, 2980], [2252, 2980]], + [[2261, 2946], [2246, 2954], [2258, 2957], [2261, 2946], [2261, 2946]], + [[2232, 2948], [2223, 2948], [2232, 2948], [2232, 2948]], + [ + [2226, 2970], + [2226, 2966], + [2234, 2963], + [2222, 2947], + [2226, 2970], + [2226, 2970] + ], + [[2286, 2913], [2282, 2923], [2286, 2913], [2286, 2913]], + [[2280, 2933], [2280, 2933], [2280, 2933]], + [[2277, 2940], [2278, 2934], [2268, 2925], [2277, 2940], [2277, 2940]], + [[2274, 2940], [2266, 2931], [2274, 2940], [2274, 2940]], + [[2236, 2976], [2235, 2970], [2223, 2973], [2236, 2976], [2236, 2976]], + [[2224, 3021], [2224, 3021], [2224, 3021]], + [[2197, 2986], [2203, 2995], [2197, 2986], [2197, 2986]], + [[2190, 3027], [2190, 3027], [2190, 3027]], + [[2193, 2974], [2190, 2973], [2186, 2983], [2193, 2974], [2193, 2974]], + [[2187, 3040], [2187, 3040], [2187, 3040]], + [ + [2210, 2987], + [2214, 2986], + [2222, 2978], + [2214, 2975], + [2209, 2963], + [2216, 2983], + [2207, 2980], + [2199, 2984], + [2210, 2987], + [2210, 2987] + ], + [ + [2284, 2949], + [2285, 2949], + [2269, 2945], + [2278, 2951], + [2284, 2949], + [2284, 2949] + ], + [ + [2265, 2953], + [2270, 2950], + [2262, 2950], + [2263, 2958], + [2254, 2963], + [2253, 2979], + [2257, 2969], + [2261, 2979], + [2269, 2970], + [2279, 2966], + [2265, 2953], + [2265, 2953] + ], + [ + [2208, 2871], + [2211, 2873], + [2219, 2866], + [2209, 2866], + [2219, 2865], + [2206, 2861], + [2208, 2871], + [2208, 2871] + ], + [ + [2229, 2928], + [2237, 2939], + [2236, 2924], + [2239, 2920], + [2239, 2933], + [2250, 2928], + [2241, 2922], + [2239, 2914], + [2224, 2900], + [2237, 2914], + [2228, 2925], + [2229, 2928], + [2229, 2928] + ], + [[2330, 2792], [2332, 2787], [2314, 2776], [2330, 2792], [2330, 2792]], + [ + [2319, 2884], + [2331, 2882], + [2340, 2881], + [2334, 2871], + [2319, 2884], + [2319, 2884] + ], + [[2331, 2901], [2331, 2901], [2331, 2901]], + [[2324, 2799], [2312, 2778], [2324, 2799], [2324, 2799]], + [[2319, 2798], [2312, 2789], [2319, 2798], [2319, 2798]], + [[2325, 2807], [2316, 2803], [2325, 2807], [2325, 2807]], + [[2047, 2683], [2047, 2676], [2038, 2670], [2047, 2683], [2047, 2683]], + [[2178, 2723], [2174, 2733], [2187, 2742], [2178, 2723], [2178, 2723]], + [[2191, 2724], [2191, 2724], [2191, 2724]], + [[2051, 2679], [2051, 2679], [2051, 2679]], + [[2561, 2451], [2569, 2450], [2563, 2441], [2561, 2451], [2561, 2451]], + [[2559, 2448], [2559, 2443], [2559, 2448], [2559, 2448]], + [[2638, 2050], [2638, 2050], [2638, 2050]], + [[2577, 2438], [2577, 2438], [2577, 2438]], + [[2575, 2431], [2585, 2427], [2588, 2419], [2575, 2431], [2575, 2431]], + [[2532, 2473], [2539, 2473], [2543, 2463], [2532, 2473], [2532, 2473]], + [ + [2531, 2473], + [2525, 2476], + [2533, 2468], + [2520, 2466], + [2521, 2474], + [2511, 2503], + [2523, 2492], + [2541, 2488], + [2546, 2491], + [2546, 2483], + [2531, 2485], + [2531, 2473], + [2531, 2473] + ], + [[2544, 2434], [2544, 2434], [2544, 2434]], + [[2549, 2527], [2546, 2530], [2549, 2527], [2549, 2527]], + [ + [2547, 2526], + [2546, 2519], + [2535, 2516], + [2538, 2524], + [2529, 2519], + [2533, 2527], + [2536, 2537], + [2528, 2541], + [2544, 2538], + [2547, 2526], + [2547, 2526] + ], + [ + [2544, 2470], + [2553, 2462], + [2543, 2471], + [2556, 2462], + [2544, 2470], + [2544, 2470] + ], + [ + [2643, 1910], + [2650, 1904], + [2650, 1894], + [2635, 1905], + [2643, 1910], + [2643, 1910] + ], + [[2695, 1980], [2701, 1981], [2700, 1970], [2695, 1980], [2695, 1980]], + [ + [2697, 1988], + [2699, 1987], + [2692, 1981], + [2680, 1981], + [2697, 1988], + [2697, 1988] + ], + [ + [2722, 1883], + [2723, 1879], + [2716, 1875], + [2716, 1885], + [2724, 1889], + [2722, 1883], + [2722, 1883] + ], + [[2750, 1684], [2757, 1676], [2750, 1684], [2750, 1684]], + [[2788, 1522], [2779, 1518], [2777, 1527], [2788, 1522], [2788, 1522]], + [ + [2559, 646], + [2550, 647], + [2530, 671], + [2529, 697], + [2538, 704], + [2533, 715], + [2535, 738], + [2524, 751], + [2521, 785], + [2513, 810], + [2503, 818], + [2489, 815], + [2463, 835], + [2471, 858], + [2468, 882], + [2464, 892], + [2456, 895], + [2449, 908], + [2453, 922], + [2462, 930], + [2485, 919], + [2505, 916], + [2520, 900], + [2531, 898], + [2552, 886], + [2560, 884], + [2615, 852], + [2616, 840], + [2628, 833], + [2636, 842], + [2627, 854], + [2617, 854], + [2619, 865], + [2643, 837], + [2652, 831], + [2664, 820], + [2674, 816], + [2682, 802], + [2712, 771], + [2746, 731], + [2743, 719], + [2717, 683], + [2715, 673], + [2723, 676], + [2715, 669], + [2715, 660], + [2716, 652], + [2707, 638], + [2697, 637], + [2678, 644], + [2662, 643], + [2651, 651], + [2637, 654], + [2633, 651], + [2625, 651], + [2604, 659], + [2596, 658], + [2581, 650], + [2572, 651], + [2559, 646], + [2559, 646] + ], + [ + [2532, 728], + [2529, 717], + [2533, 705], + [2526, 716], + [2532, 728], + [2532, 728] + ], + [ + [3840, 653], + [3841, 653], + [3826, 650], + [3818, 645], + [3809, 641], + [3819, 648], + [3806, 645], + [3795, 656], + [3773, 665], + [3743, 671], + [3751, 672], + [3733, 681], + [3720, 678], + [3718, 689], + [3706, 682], + [3697, 685], + [3700, 693], + [3690, 698], + [3687, 688], + [3677, 692], + [3675, 702], + [3671, 694], + [3663, 697], + [3650, 707], + [3642, 702], + [3634, 703], + [3605, 707], + [3584, 716], + [3575, 722], + [3547, 733], + [3560, 725], + [3551, 723], + [3565, 716], + [3553, 712], + [3534, 720], + [3534, 728], + [3523, 732], + [3506, 733], + [3494, 738], + [3485, 742], + [3474, 746], + [3478, 750], + [3457, 750], + [3443, 767], + [3440, 780], + [3472, 767], + [3583, 734], + [3667, 710], + [3750, 679], + [3808, 665], + [3826, 667], + [3825, 656], + [3839, 657], + [3866, 655], + [3893, 663], + [3908, 659], + [3876, 649], + [3840, 653], + [3840, 653] + ], + [ + [3585, 668], + [3585, 668], + [3577, 668], + [3571, 658], + [3563, 668], + [3576, 677], + [3585, 668], + [3585, 668] + ], + [ + [3583, 690], + [3583, 692], + [3575, 691], + [3562, 686], + [3554, 698], + [3573, 704], + [3583, 694], + [3593, 684], + [3583, 690], + [3583, 690] + ], + [[3584, 705], [3572, 715], [3583, 714], [3584, 705], [3584, 705]], + [ + [3327, 741], + [3284, 746], + [3242, 750], + [3195, 745], + [3180, 758], + [3201, 758], + [3253, 763], + [3326, 764], + [3372, 759], + [3438, 756], + [3440, 742], + [3424, 744], + [3381, 737], + [3379, 740], + [3358, 740], + [3357, 740], + [3349, 740], + [3349, 751], + [3348, 740], + [3346, 751], + [3346, 740], + [3342, 740], + [3342, 751], + [3341, 740], + [3338, 741], + [3338, 751], + [3337, 741], + [3327, 741], + [3327, 741] + ], + [[3287, 738], [3287, 738], [3287, 738]], + [ + [3317, 716], + [3320, 714], + [3316, 701], + [3308, 715], + [3317, 716], + [3317, 716] + ], + [[3267, 707], [3267, 707], [3267, 707]], + [[3306, 709], [3315, 696], [3299, 699], [3306, 709], [3306, 709]], + [[3322, 712], [3326, 698], [3318, 688], [3322, 712], [3322, 712]], + [[3219, 742], [3219, 742], [3219, 742]], + [[3253, 725], [3266, 719], [3268, 710], [3253, 725], [3253, 725]], + [ + [3314, 727], + [3314, 720], + [3304, 722], + [3311, 737], + [3314, 727], + [3314, 727] + ], + [ + [3282, 702], + [3284, 696], + [3273, 688], + [3265, 699], + [3272, 709], + [3273, 721], + [3281, 722], + [3281, 712], + [3290, 714], + [3292, 696], + [3282, 702], + [3282, 702] + ], + [ + [3300, 722], + [3301, 721], + [3299, 712], + [3291, 724], + [3290, 732], + [3299, 736], + [3300, 722], + [3300, 722] + ], + [ + [3294, 693], + [3297, 698], + [3297, 690], + [3307, 689], + [3299, 689], + [3291, 685], + [3294, 692], + [3285, 692], + [3294, 693], + [3294, 693] + ], + [[3410, 737], [3394, 730], [3410, 737], [3410, 737]], + [ + [3576, 688], + [3582, 684], + [3567, 680], + [3558, 684], + [3576, 688], + [3576, 688] + ], + [ + [3442, 702], + [3448, 707], + [3461, 701], + [3443, 690], + [3442, 702], + [3442, 702] + ], + [ + [3511, 714], + [3514, 705], + [3504, 697], + [3498, 711], + [3505, 721], + [3511, 714], + [3511, 714] + ], + [ + [3522, 676], + [3527, 682], + [3519, 682], + [3522, 695], + [3534, 689], + [3533, 680], + [3522, 676], + [3522, 676] + ], + [ + [3469, 688], + [3476, 679], + [3478, 661], + [3468, 667], + [3463, 676], + [3469, 688], + [3469, 688] + ], + [[3528, 703], [3532, 703], [3535, 695], [3528, 703], [3528, 703]], + [ + [3486, 729], + [3503, 720], + [3496, 711], + [3500, 701], + [3485, 702], + [3475, 698], + [3471, 709], + [3486, 729], + [3486, 729] + ], + [[3571, 722], [3571, 722], [3571, 722]], + [ + [3387, 735], + [3395, 725], + [3392, 717], + [3387, 726], + [3387, 735], + [3387, 735] + ], + [[3478, 679], [3489, 671], [3481, 665], [3478, 679], [3478, 679]], + [[3581, 655], [3577, 644], [3569, 652], [3581, 655], [3581, 655]], + [[3547, 702], [3552, 687], [3547, 702], [3547, 702]], + [[3566, 712], [3566, 712], [3566, 712]], + [ + [3425, 721], + [3443, 713], + [3426, 711], + [3424, 702], + [3413, 699], + [3422, 708], + [3425, 721], + [3425, 721] + ], + [ + [3358, 735], + [3364, 722], + [3370, 712], + [3359, 716], + [3359, 724], + [3358, 735], + [3358, 735] + ], + [ + [3345, 732], + [3355, 721], + [3354, 709], + [3343, 710], + [3345, 732], + [3345, 732] + ], + [ + [3420, 726], + [3423, 723], + [3422, 711], + [3412, 704], + [3412, 723], + [3420, 726], + [3420, 726] + ], + [ + [3516, 694], + [3514, 688], + [3519, 679], + [3508, 680], + [3503, 672], + [3505, 691], + [3516, 694], + [3516, 694] + ], + [ + [3376, 721], + [3382, 719], + [3389, 702], + [3373, 702], + [3376, 721], + [3376, 721] + ], + [[3521, 723], [3541, 707], [3530, 705], [3521, 723], [3521, 723]], + [[3527, 660], [3535, 656], [3527, 660], [3527, 660]], + [[3375, 734], [3377, 731], [3375, 734], [3375, 734]], + [[3422, 681], [3422, 681], [3422, 681]], + [[3387, 724], [3393, 714], [3390, 706], [3387, 724], [3387, 724]], + [ + [3447, 722], + [3442, 718], + [3429, 722], + [3420, 730], + [3419, 738], + [3440, 735], + [3447, 722], + [3447, 722] + ], + [ + [3471, 714], + [3466, 712], + [3452, 716], + [3454, 730], + [3471, 733], + [3461, 737], + [3475, 731], + [3471, 714], + [3471, 714] + ], + [ + [3469, 700], + [3461, 675], + [3451, 676], + [3446, 688], + [3469, 700], + [3469, 700] + ], + [[3562, 650], [3558, 658], [3562, 650], [3562, 650]], + [[3425, 690], [3417, 697], [3427, 700], [3425, 690], [3425, 690]], + [[3441, 702], [3449, 696], [3439, 687], [3441, 702], [3441, 702]], + [[3513, 703], [3513, 703], [3513, 703]], + [ + [3486, 692], + [3490, 694], + [3502, 699], + [3502, 690], + [3494, 677], + [3487, 689], + [3491, 680], + [3474, 687], + [3486, 692], + [3486, 692] + ], + [ + [3432, 699], + [3432, 699], + [3433, 681], + [3424, 687], + [3427, 701], + [3428, 709], + [3439, 708], + [3432, 699], + [3432, 699] + ], + [[3634, 668], [3635, 659], [3634, 668], [3634, 668]], + [[3650, 697], [3670, 690], [3650, 697], [3650, 697]], + [[3717, 681], [3717, 681], [3717, 681]], + [[3691, 650], [3691, 650], [3691, 650]], + [[3789, 647], [3789, 647], [3789, 647]], + [[3670, 668], [3670, 661], [3662, 662], [3670, 668], [3670, 668]], + [[3768, 643], [3774, 638], [3768, 643], [3768, 643]], + [[3693, 667], [3698, 669], [3693, 667], [3693, 667]], + [[3766, 661], [3773, 659], [3766, 661], [3766, 661]], + [[3604, 703], [3604, 703], [3604, 703]], + [[3739, 670], [3748, 667], [3739, 658], [3739, 670], [3739, 670]], + [[3785, 653], [3785, 653], [3785, 653]], + [[3641, 669], [3641, 669], [3641, 669]], + [[3700, 663], [3703, 656], [3692, 659], [3700, 663], [3700, 663]], + [[3714, 645], [3714, 645], [3714, 645]], + [[3724, 669], [3723, 657], [3711, 657], [3724, 669], [3724, 669]], + [[3658, 659], [3661, 655], [3658, 659], [3658, 659]], + [[3649, 658], [3649, 658], [3649, 658]], + [[3620, 702], [3620, 702], [3620, 702]], + [ + [3655, 666], + [3658, 664], + [3649, 662], + [3646, 666], + [3655, 666], + [3655, 666] + ], + [[3614, 703], [3614, 703], [3614, 703]], + [ + [3695, 669], + [3676, 663], + [3674, 683], + [3685, 683], + [3695, 669], + [3695, 669] + ], + [[3780, 637], [3780, 637], [3780, 637]], + [[3795, 642], [3796, 635], [3795, 642], [3795, 642]], + [[3676, 660], [3686, 652], [3676, 646], [3676, 660], [3676, 660]], + [[3724, 602], [3724, 602], [3724, 602]], + [[3654, 702], [3654, 702], [3654, 702]], + [ + [3644, 696], + [3646, 697], + [3645, 683], + [3631, 681], + [3627, 692], + [3636, 691], + [3626, 694], + [3644, 696], + [3644, 696] + ], + [ + [3662, 675], + [3665, 677], + [3640, 674], + [3647, 684], + [3645, 692], + [3669, 682], + [3662, 675], + [3662, 675] + ], + [ + [3708, 648], + [3715, 649], + [3706, 643], + [3705, 652], + [3708, 648], + [3708, 648] + ], + [ + [3762, 662], + [3763, 662], + [3767, 654], + [3783, 654], + [3785, 646], + [3786, 638], + [3774, 639], + [3771, 648], + [3760, 640], + [3747, 652], + [3742, 653], + [3742, 663], + [3762, 662], + [3762, 662] + ], + [[3073, 740], [3073, 740], [3073, 740]], + [[3071, 738], [3071, 737], [3062, 739], [3071, 738], [3071, 738]], + [ + [3071, 703], + [3071, 703], + [3080, 711], + [3080, 720], + [3082, 728], + [3073, 735], + [3082, 741], + [3092, 703], + [3079, 655], + [3064, 657], + [3068, 669], + [3065, 677], + [3058, 701], + [3071, 703], + [3071, 703] + ], + [ + [3107, 700], + [3111, 696], + [3115, 682], + [3104, 689], + [3107, 700], + [3107, 700] + ], + [[3097, 734], [3097, 726], [3097, 734], [3097, 734]], + [ + [3134, 703], + [3128, 707], + [3126, 715], + [3141, 704], + [3134, 693], + [3134, 703], + [3134, 703] + ], + [ + [3118, 713], + [3109, 716], + [3107, 722], + [3118, 722], + [3118, 713], + [3118, 713] + ], + [ + [3932, 513], + [3935, 514], + [3944, 513], + [3936, 513], + [3938, 505], + [3932, 513], + [3932, 513] + ], + [ + [3946, 637], + [3951, 636], + [3947, 632], + [3936, 632], + [3946, 637], + [3946, 637] + ], + [[3862, 635], [3862, 635], [3862, 635]], + [[3849, 634], [3849, 627], [3841, 632], [3849, 634], [3849, 634]], + [ + [3918, 638], + [3924, 628], + [3912, 618], + [3919, 632], + [3918, 638], + [3918, 638] + ], + [[3929, 621], [3929, 621], [3929, 621]], + [ + [4003, 618], + [4000, 621], + [4018, 629], + [4018, 617], + [4003, 618], + [4003, 618] + ], + [[3862, 644], [3862, 644], [3862, 644]], + [[3992, 627], [3997, 623], [3985, 617], [3992, 627], [3992, 627]], + [[3916, 632], [3916, 632], [3916, 632]], + [ + [3881, 637], + [3871, 642], + [3885, 647], + [3904, 647], + [3912, 642], + [3904, 642], + [3906, 630], + [3915, 631], + [3914, 626], + [3903, 626], + [3893, 617], + [3891, 625], + [3881, 624], + [3881, 635], + [3879, 627], + [3871, 626], + [3861, 638], + [3870, 641], + [3881, 637], + [3881, 637] + ], + [ + [2804, 556], + [2804, 553], + [2793, 552], + [2783, 568], + [2804, 556], + [2804, 556] + ], + [ + [2991, 355], + [2986, 350], + [2979, 353], + [2979, 365], + [2998, 375], + [3009, 372], + [3008, 364], + [2991, 355], + [2991, 355] + ], + [[2971, 342], [2971, 342], [2971, 342]], + [[2878, 443], [2907, 405], [2878, 443], [2878, 443]], + [ + [2916, 379], + [2926, 383], + [2947, 359], + [2934, 343], + [2926, 361], + [2916, 379], + [2916, 379] + ], + [[3031, 674], [3038, 672], [3031, 674], [3031, 674]], + [ + [3001, 701], + [3017, 695], + [3017, 677], + [2998, 691], + [3001, 701], + [3001, 701] + ], + [[3061, 751], [3061, 751], [3061, 751]], + [[3057, 746], [3058, 749], [3056, 737], [3057, 746], [3057, 746]], + [[2946, 747], [2949, 742], [2937, 732], [2946, 747], [2946, 747]], + [[2758, 543], [2761, 546], [2758, 543], [2758, 543]], + [[3034, 718], [3041, 712], [3034, 718], [3034, 718]], + [ + [3042, 718], + [3053, 722], + [3060, 707], + [3047, 704], + [3042, 718], + [3042, 718] + ], + [[3061, 720], [3061, 720], [3061, 720]], + [[3032, 689], [3030, 693], [3040, 690], [3032, 689], [3032, 689]], + [[3040, 668], [3048, 660], [3040, 668], [3040, 668]], + [[3030, 738], [3040, 733], [3023, 726], [3030, 738], [3030, 738]], + [[2714, 562], [2719, 570], [2714, 562], [2714, 562]], + [[3143, 180], [3141, 175], [3132, 186], [3143, 180], [3143, 180]], + [[3157, 193], [3161, 191], [3161, 182], [3157, 193], [3157, 193]], + [[3176, 181], [3176, 181], [3176, 181]], + [ + [3126, 242], + [3125, 256], + [3138, 277], + [3140, 253], + [3130, 243], + [3129, 234], + [3126, 242], + [3126, 242] + ], + [ + [3157, 232], + [3153, 232], + [3153, 247], + [3158, 260], + [3157, 245], + [3157, 232], + [3157, 232] + ], + [[3133, 231], [3133, 231], [3133, 231]], + [[3250, 75], [3256, 67], [3248, 73], [3250, 75], [3250, 75]], + [[3368, -8], [3362, -7], [3368, -8], [3368, -8]], + [[3350, -24], [3342, -32], [3350, -24], [3350, -24]], + [[861, 2190], [876, 2187], [869, 2179], [861, 2190], [861, 2190]], + [ + [536, 2663], + [543, 2655], + [520, 2636], + [526, 2654], + [536, 2663], + [536, 2663] + ], + [[960, 2157], [970, 2155], [918, 2153], [960, 2157], [960, 2157]], + [[766, 3048], [770, 3048], [768, 3037], [766, 3048], [766, 3048]], + [[843, 3122], [835, 3118], [843, 3122], [843, 3122]], + [[540, 2806], [548, 2794], [547, 2786], [540, 2806], [540, 2806]], + [[1497, 3860], [1497, 3860], [1497, 3860]], + [[1656, 3727], [1657, 3738], [1656, 3727], [1656, 3727]], + [[1647, 3722], [1647, 3722], [1647, 3722]], + [[1749, 3589], [1749, 3589], [1749, 3589]], + [[1726, 3635], [1726, 3635], [1726, 3635]], + [[1740, 3546], [1740, 3546], [1740, 3546]], + [[1521, 3409], [1521, 3409], [1521, 3409]], + [[1515, 3425], [1515, 3425], [1515, 3425]], + [[1365, 3279], [1365, 3279], [1365, 3279]], + [[1992, 3168], [1992, 3168], [1992, 3168]], + [[1995, 3160], [1995, 3160], [1995, 3160]], + [[2117, 3090], [2117, 3090], [2117, 3090]], + [[2661, 2015], [2661, 2015], [2661, 2015]], + [[2661, 2015], [2661, 2015], [2661, 2015]], + [[2763, 1664], [2763, 1664], [2763, 1664]], + [[3707, 616], [3707, 616], [3707, 616]], + [[3292, 725], [3300, 722], [3292, 725], [3292, 725]], + [[3645, 706], [3645, 706], [3645, 706]], + [[3281, 712], [3281, 712], [3281, 712]], + [[3486, 706], [3486, 706], [3486, 706]], + [[3287, 713], [3287, 713], [3287, 713]], + [[3281, 705], [3281, 705], [3281, 705]], + [[3281, 705], [3281, 705], [3281, 705]], + [[3663, 697], [3663, 697], [3663, 697]], + [[3432, 699], [3432, 699], [3432, 699]], + [[3644, 696], [3644, 696], [3644, 696]], + [[3428, 695], [3428, 695], [3428, 695]], + [[3915, 632], [3915, 632], [3915, 632]], + [[3884, 625], [3884, 625], [3884, 625]], + [[3887, 638], [3887, 638], [3887, 638]], + [[3873, 632], [3873, 632], [3873, 632]], + [[3887, 638], [3888, 632], [3887, 638], [3887, 638]], + [[3906, 630], [3906, 630], [3906, 630]], + [[3487, 689], [3487, 689], [3487, 689]], + [[3294, 693], [3294, 693], [3294, 693]], + [[3297, 690], [3297, 690], [3297, 690]], + [[3662, 675], [3662, 675], [3662, 675]], + [[3319, 683], [3319, 683], [3319, 683]], + [[3754, 654], [3754, 654], [3754, 654]], + [[3759, 658], [3759, 658], [3759, 658]], + [[3759, 658], [3759, 658], [3759, 658]], + [[3759, 656], [3759, 656], [3759, 656]], + [[3710, 644], [3710, 644], [3710, 644]], + [[3707, 647], [3707, 647], [3707, 647]], + [[3875, 560], [3875, 560], [3875, 560]], + [[2704, 1048], [2704, 1048], [2704, 1048]], + [[2704, 1048], [2704, 1048], [2704, 1048]], + [[2183, 3051], [2183, 3051], [2183, 3051]], + [[2186, 3045], [2186, 3045], [2186, 3045]], + [[2183, 3051], [2183, 3051], [2183, 3051]], + [[2181, 3039], [2181, 3039], [2181, 3039]], + [[2181, 3039], [2181, 3039], [2181, 3039]], + [[2235, 3027], [2235, 3027], [2235, 3027]], + [[2235, 3027], [2235, 3027], [2235, 3027]], + [[2186, 3006], [2186, 3006], [2186, 3006]], + [[2175, 3002], [2175, 3002], [2175, 3002]], + [[2183, 3000], [2183, 3000], [2183, 3000]], + [[2151, 3057], [2151, 3057], [2151, 3057]], + [[2164, 2990], [2164, 2990], [2164, 2990]], + [[2172, 2992], [2172, 2992], [2172, 2992]], + [[2165, 2991], [2165, 2991], [2165, 2991]], + [[2172, 2992], [2172, 2992], [2172, 2992]], + [[2165, 2991], [2165, 2991], [2165, 2991]], + [[2280, 2722], [2280, 2722], [2280, 2722]], + [[2265, 2952], [2265, 2952], [2265, 2952]], + [[2179, 2983], [2179, 2983], [2179, 2983]], + [[2210, 2987], [2210, 2987], [2210, 2987]], + [[2163, 2988], [2163, 2988], [2163, 2988]], + [[2163, 2987], [2163, 2987], [2163, 2987]], + [[2207, 2980], [2207, 2980], [2207, 2980]], + [[2179, 2983], [2179, 2983], [2179, 2983]], + [[2207, 2980], [2207, 2980], [2207, 2980]], + [[2284, 2949], [2284, 2949], [2284, 2949]], + [[2314, 2924], [2314, 2924], [2314, 2924]], + [[2229, 2928], [2229, 2928], [2229, 2928]], + [[2290, 2925], [2290, 2925], [2290, 2925]], + [[2300, 2917], [2300, 2917], [2300, 2917]], + [[2239, 2914], [2239, 2914], [2239, 2914]], + [[2339, 2909], [2339, 2909], [2339, 2909]], + [ + [2354, 2861], + [2359, 2862], + [2361, 2871], + [2359, 2880], + [2354, 2861], + [2354, 2861] + ], + [[2358, 2862], [2358, 2862], [2358, 2862]], + [[2335, 2861], [2335, 2861], [2335, 2861]], + [[2332, 2876], [2332, 2876], [2332, 2876]], + [[2332, 2876], [2332, 2876], [2332, 2876]], + [[2309, 2907], [2309, 2907], [2309, 2907]], + [ + [2297, 2908], + [2304, 2910], + [2304, 2901], + [2291, 2903], + [2297, 2898], + [2288, 2898], + [2297, 2896], + [2305, 2900], + [2297, 2908], + [2297, 2908] + ], + [[2223, 2900], [2223, 2900], [2223, 2900]], + [[2296, 2905], [2296, 2905], [2296, 2905]], + [[2291, 2903], [2291, 2903], [2291, 2903]], + [[2291, 2903], [2291, 2903], [2291, 2903]], + [[2331, 2889], [2331, 2889], [2331, 2889]], + [[2314, 2895], [2314, 2895], [2314, 2895]], + [[2296, 2896], [2296, 2896], [2296, 2896]], + [[2296, 2896], [2296, 2896], [2296, 2896]], + [[2208, 2871], [2208, 2871], [2208, 2871]], + [[2325, 2857], [2325, 2857], [2325, 2857]], + [[2321, 2861], [2321, 2861], [2321, 2861]], + [[2332, 2876], [2323, 2876], [2332, 2876], [2332, 2876]], + [[2285, 2872], [2285, 2872], [2285, 2872]], + [[2310, 2875], [2310, 2875], [2310, 2875]], + [[2347, 2857], [2347, 2857], [2347, 2857]], + [[2358, 2862], [2349, 2845], [2358, 2862], [2358, 2862]], + [[2348, 2843], [2348, 2843], [2348, 2843]], + [[2258, 2849], [2258, 2849], [2258, 2849]], + [[2223, 2850], [2223, 2850], [2223, 2850]], + [[2276, 2719], [2276, 2719], [2276, 2719]], + [[2280, 2722], [2280, 2722], [2280, 2722]], + [[2276, 2719], [2276, 2719], [2276, 2719]], + [[2271, 2710], [2271, 2710], [2271, 2710]], + [[2504, 2543], [2504, 2543], [2507, 2535], [2504, 2543], [2504, 2543]], + [[2507, 2535], [2507, 2535], [2507, 2535]], + [[2543, 2471], [2543, 2471], [2543, 2471]], + [[2617, 2442], [2617, 2442], [2617, 2442]], + [[2624, 2428], [2624, 2428], [2624, 2428]], + [[2624, 2428], [2624, 2428], [2624, 2428]], + [[2645, 2346], [2645, 2346], [2645, 2346]], + [[2644, 2345], [2644, 2345], [2644, 2345]], + [[2644, 2345], [2644, 2345], [2644, 2345]], + [[2644, 2369], [2644, 2369], [2644, 2369]], + [[2602, 2174], [2602, 2174], [2602, 2174]], + [[2600, 2174], [2600, 2174], [2600, 2174]], + [[2596, 2174], [2596, 2174], [2588, 2174], [2596, 2174], [2596, 2174]], + [[2600, 2174], [2600, 2174], [2600, 2174]], + [[2602, 2174], [2602, 2174], [2602, 2174]], + [[2621, 2091], [2621, 2091], [2621, 2091]], + [[2533, 2318], [2533, 2318], [2533, 2318]], + [[2533, 2318], [2533, 2318], [2533, 2318]] +] diff --git a/packages/melonjs/tests/earcut/fixtures/water.json b/packages/melonjs/tests/earcut/fixtures/water.json new file mode 100644 index 000000000..984c0243f --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/water.json @@ -0,0 +1,2533 @@ +[ + [ + [2293, 4224], + [2294, 4219], + [2280, 4180], + [2288, 4172], + [2283, 4189], + [2301, 4218], + [2299, 4224], + [2347, 4224], + [2344, 4215], + [2351, 4224], + [2371, 4224], + [2379, 4224], + [2375, 4206], + [2363, 4202], + [2346, 4194], + [2371, 4195], + [2376, 4180], + [2383, 4202], + [2429, 4176], + [2431, 4163], + [2439, 4161], + [2438, 4144], + [2464, 4124], + [2457, 4111], + [2467, 4102], + [2473, 4060], + [2482, 4053], + [2488, 4031], + [2467, 3982], + [2456, 3991], + [2456, 4005], + [2451, 3998], + [2451, 4014], + [2432, 4011], + [2433, 4025], + [2427, 4012], + [2415, 4009], + [2438, 4003], + [2419, 3990], + [2411, 3987], + [2391, 4000], + [2391, 3989], + [2374, 3991], + [2382, 3995], + [2363, 4028], + [2364, 4042], + [2380, 4041], + [2389, 4029], + [2387, 4053], + [2412, 4055], + [2376, 4059], + [2389, 4085], + [2381, 4093], + [2371, 4076], + [2363, 4082], + [2372, 4067], + [2362, 4059], + [2347, 4054], + [2349, 4040], + [2344, 4057], + [2325, 4063], + [2322, 4073], + [2332, 4078], + [2325, 4086], + [2317, 4082], + [2308, 4065], + [2321, 4063], + [2299, 4051], + [2312, 4056], + [2326, 4055], + [2325, 4044], + [2302, 4021], + [2315, 4029], + [2324, 4023], + [2333, 4040], + [2335, 4026], + [2349, 4016], + [2333, 3999], + [2318, 4002], + [2333, 3991], + [2321, 3985], + [2350, 4000], + [2350, 3962], + [2331, 3964], + [2340, 3949], + [2332, 3946], + [2341, 3943], + [2345, 3952], + [2358, 3947], + [2350, 3922], + [2362, 3931], + [2363, 3922], + [2368, 3946], + [2377, 3946], + [2388, 3933], + [2378, 3908], + [2389, 3920], + [2393, 3948], + [2401, 3924], + [2400, 3911], + [2382, 3899], + [2388, 3875], + [2366, 3885], + [2350, 3878], + [2340, 3896], + [2327, 3880], + [2323, 3900], + [2313, 3894], + [2300, 3871], + [2307, 3890], + [2331, 3872], + [2317, 3867], + [2345, 3852], + [2343, 3840], + [2351, 3843], + [2348, 3823], + [2339, 3821], + [2341, 3805], + [2350, 3828], + [2379, 3853], + [2385, 3844], + [2368, 3823], + [2370, 3809], + [2362, 3809], + [2361, 3793], + [2372, 3804], + [2379, 3795], + [2376, 3823], + [2388, 3815], + [2402, 3822], + [2393, 3832], + [2384, 3824], + [2404, 3860], + [2407, 3876], + [2416, 3872], + [2418, 3852], + [2427, 3876], + [2409, 3893], + [2429, 3921], + [2484, 3863], + [2478, 3792], + [2440, 3820], + [2439, 3834], + [2438, 3820], + [2426, 3809], + [2435, 3801], + [2421, 3794], + [2429, 3786], + [2406, 3752], + [2424, 3748], + [2440, 3762], + [2431, 3732], + [2415, 3735], + [2412, 3721], + [2391, 3707], + [2381, 3720], + [2382, 3732], + [2370, 3724], + [2382, 3716], + [2372, 3705], + [2380, 3708], + [2378, 3687], + [2368, 3685], + [2349, 3710], + [2338, 3694], + [2337, 3708], + [2324, 3706], + [2327, 3717], + [2316, 3729], + [2323, 3715], + [2309, 3714], + [2318, 3713], + [2311, 3699], + [2332, 3698], + [2334, 3678], + [2356, 3670], + [2343, 3651], + [2332, 3649], + [2335, 3658], + [2324, 3655], + [2323, 3670], + [2324, 3661], + [2311, 3661], + [2332, 3640], + [2316, 3633], + [2286, 3655], + [2302, 3631], + [2277, 3610], + [2269, 3619], + [2250, 3619], + [2250, 3630], + [2239, 3635], + [2244, 3650], + [2228, 3660], + [2236, 3679], + [2226, 3666], + [2207, 3677], + [2199, 3672], + [2235, 3648], + [2232, 3621], + [2240, 3624], + [2249, 3605], + [2229, 3607], + [2219, 3593], + [2209, 3597], + [2218, 3587], + [2202, 3586], + [2201, 3576], + [2180, 3583], + [2177, 3598], + [2178, 3573], + [2165, 3548], + [2153, 3544], + [2148, 3519], + [2154, 3506], + [2139, 3492], + [2141, 3484], + [2149, 3492], + [2186, 3568], + [2207, 3567], + [2233, 3585], + [2231, 3533], + [2248, 3519], + [2248, 3532], + [2238, 3536], + [2247, 3547], + [2238, 3549], + [2237, 3574], + [2260, 3602], + [2261, 3586], + [2272, 3598], + [2294, 3599], + [2288, 3559], + [2300, 3578], + [2303, 3610], + [2324, 3615], + [2341, 3612], + [2342, 3596], + [2330, 3591], + [2342, 3588], + [2346, 3561], + [2348, 3612], + [2363, 3604], + [2365, 3582], + [2374, 3590], + [2376, 3576], + [2386, 3591], + [2403, 3596], + [2387, 3598], + [2370, 3598], + [2364, 3636], + [2379, 3621], + [2387, 3653], + [2400, 3620], + [2414, 3623], + [2402, 3632], + [2397, 3650], + [2411, 3667], + [2410, 3682], + [2427, 3678], + [2420, 3667], + [2425, 3649], + [2443, 3653], + [2426, 3651], + [2433, 3664], + [2429, 3672], + [2440, 3671], + [2440, 3681], + [2426, 3688], + [2454, 3700], + [2457, 3689], + [2462, 3698], + [2456, 3717], + [2499, 3696], + [2488, 3686], + [2498, 3690], + [2499, 3682], + [2520, 3700], + [2503, 3702], + [2499, 3713], + [2510, 3706], + [2518, 3708], + [2513, 3730], + [2530, 3746], + [2521, 3746], + [2546, 3760], + [2549, 3777], + [2574, 3779], + [2550, 3768], + [2536, 3721], + [2551, 3725], + [2555, 3750], + [2578, 3746], + [2564, 3704], + [2554, 3709], + [2542, 3694], + [2563, 3704], + [2571, 3682], + [2602, 3652], + [2577, 3623], + [2568, 3629], + [2581, 3639], + [2576, 3655], + [2561, 3636], + [2560, 3648], + [2549, 3634], + [2524, 3637], + [2531, 3625], + [2564, 3627], + [2537, 3582], + [2530, 3591], + [2534, 3554], + [2522, 3558], + [2519, 3574], + [2506, 3576], + [2504, 3595], + [2493, 3598], + [2502, 3592], + [2505, 3572], + [2513, 3563], + [2502, 3559], + [2517, 3548], + [2527, 3551], + [2533, 3539], + [2518, 3523], + [2503, 3538], + [2485, 3535], + [2479, 3545], + [2478, 3535], + [2467, 3540], + [2466, 3555], + [2454, 3547], + [2443, 3562], + [2450, 3547], + [2437, 3543], + [2462, 3542], + [2459, 3532], + [2470, 3535], + [2477, 3525], + [2500, 3530], + [2496, 3515], + [2515, 3515], + [2527, 3502], + [2503, 3482], + [2481, 3486], + [2453, 3506], + [2462, 3496], + [2461, 3485], + [2496, 3481], + [2490, 3464], + [2467, 3463], + [2479, 3445], + [2458, 3437], + [2430, 3471], + [2391, 3471], + [2403, 3470], + [2410, 3460], + [2428, 3464], + [2450, 3428], + [2435, 3418], + [2426, 3429], + [2437, 3412], + [2418, 3406], + [2415, 3415], + [2388, 3419], + [2411, 3403], + [2395, 3399], + [2404, 3392], + [2385, 3384], + [2366, 3406], + [2347, 3410], + [2384, 3376], + [2370, 3365], + [2347, 3376], + [2327, 3371], + [2376, 3358], + [2372, 3347], + [2357, 3342], + [2331, 3350], + [2334, 3342], + [2361, 3335], + [2363, 3326], + [2321, 3317], + [2303, 3328], + [2312, 3311], + [2320, 3316], + [2270, 3302], + [2257, 3308], + [2263, 3321], + [2248, 3330], + [2257, 3316], + [2246, 3300], + [2238, 3323], + [2227, 3318], + [2227, 3304], + [2243, 3294], + [2253, 3297], + [2249, 3282], + [2232, 3278], + [2242, 3274], + [2242, 3266], + [2258, 3264], + [2257, 3255], + [2269, 3248], + [2292, 3263], + [2278, 3245], + [2259, 3239], + [2278, 3244], + [2281, 3231], + [2266, 3217], + [2252, 3217], + [2250, 3196], + [2228, 3218], + [2220, 3219], + [2237, 3199], + [2215, 3194], + [2243, 3196], + [2237, 3177], + [2209, 3171], + [2189, 3154], + [2157, 3144], + [2144, 3152], + [2151, 3141], + [2139, 3130], + [2122, 3148], + [2113, 3127], + [2125, 3142], + [2130, 3117], + [2147, 3119], + [2149, 3128], + [2167, 3120], + [2169, 3146], + [2187, 3143], + [2212, 3166], + [2224, 3161], + [2225, 3173], + [2243, 3145], + [2244, 3156], + [2235, 3162], + [2254, 3175], + [2272, 3176], + [2289, 3165], + [2286, 3182], + [2274, 3178], + [2268, 3195], + [2304, 3196], + [2310, 3180], + [2323, 3209], + [2339, 3214], + [2349, 3249], + [2359, 3249], + [2357, 3295], + [2359, 3287], + [2385, 3284], + [2368, 3300], + [2393, 3315], + [2388, 3339], + [2401, 3357], + [2414, 3352], + [2410, 3342], + [2422, 3334], + [2417, 3348], + [2435, 3354], + [2416, 3357], + [2420, 3376], + [2436, 3385], + [2452, 3381], + [2444, 3384], + [2447, 3396], + [2466, 3394], + [2479, 3417], + [2490, 3400], + [2499, 3452], + [2529, 3469], + [2531, 3481], + [2547, 3497], + [2554, 3488], + [2565, 3503], + [2579, 3490], + [2569, 3465], + [2591, 3499], + [2589, 3527], + [2600, 3518], + [2606, 3498], + [2604, 3456], + [2589, 3465], + [2591, 3456], + [2572, 3442], + [2583, 3440], + [2582, 3430], + [2571, 3419], + [2557, 3420], + [2570, 3415], + [2580, 3423], + [2580, 3409], + [2530, 3373], + [2587, 3402], + [2595, 3447], + [2604, 3413], + [2598, 3436], + [2609, 3432], + [2601, 3446], + [2614, 3451], + [2635, 3442], + [2644, 3447], + [2655, 3434], + [2646, 3429], + [2646, 3411], + [2632, 3413], + [2650, 3405], + [2646, 3393], + [2610, 3389], + [2619, 3383], + [2603, 3373], + [2616, 3372], + [2623, 3384], + [2646, 3388], + [2650, 3359], + [2612, 3347], + [2641, 3355], + [2643, 3345], + [2654, 3359], + [2648, 3382], + [2662, 3381], + [2654, 3413], + [2659, 3426], + [2673, 3429], + [2673, 3417], + [2685, 3418], + [2679, 3396], + [2695, 3397], + [2684, 3405], + [2693, 3416], + [2686, 3425], + [2676, 3422], + [2684, 3439], + [2669, 3471], + [2676, 3482], + [2688, 3472], + [2684, 3453], + [2711, 3444], + [2698, 3444], + [2710, 3426], + [2702, 3424], + [2716, 3422], + [2737, 3403], + [2731, 3374], + [2746, 3381], + [2744, 3399], + [2765, 3387], + [2745, 3326], + [2735, 3313], + [2715, 3318], + [2724, 3314], + [2739, 3307], + [2666, 3259], + [2658, 3286], + [2668, 3292], + [2656, 3294], + [2655, 3312], + [2642, 3304], + [2656, 3286], + [2645, 3286], + [2653, 3278], + [2644, 3273], + [2662, 3259], + [2637, 3234], + [2591, 3240], + [2555, 3270], + [2578, 3246], + [2574, 3238], + [2585, 3239], + [2596, 3228], + [2583, 3210], + [2576, 3218], + [2580, 3208], + [2545, 3209], + [2529, 3198], + [2517, 3209], + [2513, 3182], + [2491, 3203], + [2495, 3222], + [2488, 3230], + [2483, 3213], + [2491, 3208], + [2476, 3207], + [2486, 3201], + [2483, 3187], + [2471, 3185], + [2460, 3193], + [2466, 3183], + [2452, 3158], + [2426, 3163], + [2418, 3175], + [2434, 3195], + [2435, 3211], + [2424, 3200], + [2426, 3185], + [2413, 3177], + [2403, 3190], + [2405, 3205], + [2395, 3210], + [2398, 3198], + [2383, 3205], + [2384, 3194], + [2400, 3195], + [2414, 3172], + [2393, 3157], + [2362, 3192], + [2364, 3183], + [2356, 3180], + [2371, 3170], + [2364, 3166], + [2379, 3166], + [2360, 3150], + [2394, 3153], + [2398, 3135], + [2401, 3147], + [2408, 3128], + [2395, 3126], + [2386, 3114], + [2377, 3117], + [2371, 3106], + [2351, 3105], + [2343, 3109], + [2360, 3098], + [2380, 3105], + [2376, 3090], + [2355, 3081], + [2362, 3073], + [2358, 3041], + [2339, 3025], + [2334, 3010], + [2314, 3000], + [2335, 3006], + [2349, 3032], + [2359, 3025], + [2370, 3073], + [2384, 3089], + [2388, 3072], + [2411, 3063], + [2422, 3047], + [2417, 3063], + [2394, 3072], + [2384, 3101], + [2400, 3113], + [2418, 3094], + [2412, 3108], + [2423, 3106], + [2426, 3117], + [2446, 3119], + [2446, 3141], + [2466, 3128], + [2456, 3108], + [2460, 3097], + [2471, 3117], + [2487, 3107], + [2470, 3122], + [2479, 3137], + [2485, 3127], + [2499, 3130], + [2506, 3106], + [2528, 3101], + [2529, 3109], + [2515, 3113], + [2529, 3135], + [2526, 3114], + [2541, 3130], + [2558, 3114], + [2561, 3101], + [2548, 3102], + [2535, 3087], + [2555, 3094], + [2544, 3073], + [2562, 3099], + [2576, 3101], + [2585, 3096], + [2580, 3079], + [2588, 3073], + [2605, 3065], + [2615, 3073], + [2632, 3084], + [2628, 3071], + [2620, 3067], + [2600, 3039], + [2612, 3046], + [2634, 3071], + [2642, 3082], + [2646, 3073], + [2646, 3083], + [2672, 3093], + [2677, 3106], + [2670, 3071], + [2652, 3011], + [2659, 2936], + [2636, 2937], + [2629, 2961], + [2636, 2973], + [2617, 2976], + [2629, 2992], + [2618, 2988], + [2599, 2996], + [2613, 2989], + [2613, 2967], + [2604, 2973], + [2609, 2958], + [2598, 2962], + [2586, 2962], + [2583, 2975], + [2581, 2965], + [2565, 2975], + [2574, 2963], + [2537, 2964], + [2536, 2984], + [2535, 2961], + [2512, 2973], + [2501, 2962], + [2531, 2959], + [2530, 2951], + [2538, 2957], + [2553, 2954], + [2578, 2954], + [2604, 2944], + [2618, 2953], + [2610, 2939], + [2574, 2946], + [2541, 2926], + [2576, 2938], + [2618, 2927], + [2634, 2921], + [2552, 2863], + [2521, 2805], + [2498, 2823], + [2494, 2838], + [2503, 2847], + [2493, 2842], + [2455, 2853], + [2485, 2877], + [2459, 2862], + [2443, 2871], + [2449, 2888], + [2429, 2873], + [2430, 2861], + [2416, 2880], + [2421, 2900], + [2408, 2887], + [2388, 2915], + [2420, 2868], + [2412, 2855], + [2441, 2851], + [2455, 2834], + [2447, 2809], + [2421, 2784], + [2423, 2796], + [2395, 2818], + [2400, 2827], + [2387, 2823], + [2384, 2844], + [2376, 2841], + [2367, 2847], + [2371, 2858], + [2348, 2865], + [2347, 2879], + [2325, 2871], + [2326, 2891], + [2308, 2884], + [2298, 2898], + [2297, 2888], + [2283, 2893], + [2283, 2884], + [2312, 2880], + [2294, 2859], + [2316, 2872], + [2315, 2862], + [2349, 2857], + [2333, 2848], + [2360, 2850], + [2358, 2840], + [2369, 2834], + [2339, 2821], + [2309, 2824], + [2310, 2815], + [2328, 2816], + [2342, 2814], + [2340, 2804], + [2357, 2819], + [2360, 2798], + [2365, 2818], + [2379, 2820], + [2391, 2793], + [2409, 2789], + [2392, 2771], + [2392, 2782], + [2384, 2779], + [2370, 2792], + [2368, 2783], + [2356, 2785], + [2366, 2775], + [2375, 2783], + [2373, 2774], + [2389, 2773], + [2360, 2717], + [2360, 2707], + [2377, 2698], + [2356, 2669], + [2364, 2645], + [2355, 2642], + [2360, 2633], + [2339, 2644], + [2342, 2629], + [2324, 2645], + [2312, 2639], + [2310, 2616], + [2275, 2627], + [2229, 2610], + [2219, 2563], + [2234, 2585], + [2252, 2578], + [2270, 2589], + [2286, 2553], + [2266, 2527], + [2255, 2528], + [2235, 2496], + [2221, 2505], + [2230, 2489], + [2220, 2497], + [2225, 2486], + [2210, 2479], + [2185, 2482], + [2190, 2517], + [2171, 2513], + [2171, 2500], + [2162, 2517], + [2144, 2518], + [2121, 2472], + [2096, 2474], + [2076, 2458], + [2094, 2427], + [2087, 2410], + [2095, 2408], + [2104, 2408], + [2105, 2444], + [2126, 2453], + [2136, 2471], + [2152, 2458], + [2142, 2448], + [2159, 2433], + [2196, 2452], + [2216, 2442], + [2225, 2451], + [2232, 2441], + [2223, 2420], + [2217, 2428], + [2223, 2416], + [2215, 2425], + [2219, 2412], + [2210, 2420], + [2213, 2409], + [2207, 2417], + [2197, 2397], + [2170, 2407], + [2154, 2398], + [2150, 2376], + [2132, 2372], + [2132, 2360], + [2143, 2364], + [2143, 2356], + [2158, 2373], + [2176, 2372], + [2166, 2375], + [2167, 2385], + [2192, 2374], + [2202, 2384], + [2199, 2373], + [2208, 2368], + [2225, 2380], + [2228, 2392], + [2250, 2393], + [2253, 2411], + [2257, 2423], + [2246, 2426], + [2257, 2428], + [2246, 2431], + [2257, 2438], + [2248, 2447], + [2257, 2459], + [2268, 2456], + [2269, 2469], + [2276, 2452], + [2286, 2468], + [2285, 2451], + [2294, 2450], + [2295, 2465], + [2304, 2453], + [2304, 2464], + [2340, 2491], + [2352, 2462], + [2339, 2446], + [2342, 2433], + [2357, 2470], + [2345, 2510], + [2362, 2534], + [2389, 2522], + [2408, 2524], + [2409, 2559], + [2418, 2574], + [2398, 2596], + [2450, 2560], + [2456, 2541], + [2445, 2541], + [2461, 2531], + [2440, 2529], + [2437, 2519], + [2467, 2522], + [2474, 2513], + [2460, 2501], + [2437, 2505], + [2447, 2498], + [2433, 2476], + [2447, 2493], + [2439, 2469], + [2449, 2475], + [2456, 2497], + [2462, 2489], + [2477, 2501], + [2489, 2493], + [2488, 2485], + [2468, 2477], + [2473, 2460], + [2461, 2455], + [2462, 2446], + [2486, 2477], + [2507, 2485], + [2509, 2472], + [2518, 2469], + [2505, 2458], + [2514, 2462], + [2522, 2451], + [2512, 2414], + [2493, 2409], + [2505, 2409], + [2516, 2401], + [2517, 2412], + [2533, 2405], + [2519, 2414], + [2522, 2438], + [2554, 2449], + [2525, 2453], + [2527, 2462], + [2541, 2463], + [2529, 2465], + [2524, 2475], + [2542, 2492], + [2521, 2481], + [2517, 2490], + [2527, 2501], + [2492, 2499], + [2494, 2516], + [2475, 2543], + [2487, 2578], + [2466, 2581], + [2461, 2594], + [2470, 2601], + [2458, 2602], + [2471, 2608], + [2458, 2609], + [2470, 2612], + [2468, 2625], + [2455, 2633], + [2475, 2634], + [2454, 2640], + [2456, 2652], + [2468, 2652], + [2462, 2661], + [2481, 2677], + [2481, 2671], + [2499, 2671], + [2501, 2639], + [2527, 2635], + [2513, 2645], + [2511, 2676], + [2515, 2664], + [2565, 2659], + [2565, 2614], + [2563, 2589], + [2571, 2569], + [2587, 2575], + [2604, 2570], + [2572, 2584], + [2572, 2592], + [2587, 2588], + [2584, 2594], + [2594, 2594], + [2578, 2606], + [2594, 2613], + [2626, 2608], + [2630, 2590], + [2619, 2589], + [2633, 2586], + [2634, 2572], + [2642, 2572], + [2638, 2598], + [2635, 2613], + [2642, 2605], + [2618, 2624], + [2622, 2642], + [2604, 2675], + [2611, 2691], + [2626, 2699], + [2643, 2671], + [2620, 2670], + [2642, 2663], + [2624, 2659], + [2628, 2645], + [2640, 2649], + [2635, 2637], + [2645, 2638], + [2653, 2625], + [2660, 2639], + [2647, 2655], + [2655, 2662], + [2676, 2660], + [2684, 2667], + [2676, 2657], + [2698, 2605], + [2754, 2571], + [2743, 2564], + [2753, 2537], + [2723, 2564], + [2687, 2563], + [2673, 2544], + [2627, 2520], + [2633, 2509], + [2617, 2501], + [2613, 2511], + [2594, 2512], + [2615, 2487], + [2591, 2457], + [2597, 2444], + [2587, 2421], + [2599, 2423], + [2602, 2413], + [2570, 2381], + [2538, 2365], + [2525, 2340], + [2498, 2347], + [2511, 2334], + [2508, 2322], + [2495, 2321], + [2485, 2302], + [2459, 2293], + [2458, 2281], + [2468, 2271], + [2483, 2280], + [2486, 2262], + [2498, 2265], + [2487, 2288], + [2503, 2296], + [2517, 2291], + [2528, 2304], + [2551, 2311], + [2558, 2335], + [2562, 2313], + [2552, 2307], + [2548, 2290], + [2562, 2302], + [2567, 2322], + [2591, 2296], + [2574, 2321], + [2565, 2332], + [2589, 2352], + [2601, 2338], + [2593, 2353], + [2600, 2361], + [2636, 2366], + [2638, 2355], + [2646, 2352], + [2643, 2336], + [2651, 2352], + [2658, 2343], + [2653, 2354], + [2661, 2363], + [2644, 2361], + [2642, 2371], + [2651, 2375], + [2635, 2374], + [2639, 2413], + [2650, 2416], + [2631, 2451], + [2641, 2454], + [2642, 2479], + [2671, 2475], + [2702, 2501], + [2717, 2497], + [2726, 2504], + [2731, 2491], + [2721, 2477], + [2735, 2496], + [2746, 2498], + [2734, 2473], + [2764, 2425], + [2742, 2435], + [2741, 2419], + [2752, 2418], + [2756, 2407], + [2743, 2403], + [2756, 2396], + [2745, 2389], + [2756, 2389], + [2761, 2380], + [2763, 2397], + [2787, 2379], + [2794, 2397], + [2800, 2387], + [2792, 2370], + [2803, 2363], + [2795, 2356], + [2764, 2357], + [2762, 2344], + [2761, 2363], + [2753, 2361], + [2742, 2372], + [2750, 2359], + [2741, 2357], + [2715, 2378], + [2719, 2360], + [2702, 2371], + [2709, 2361], + [2695, 2343], + [2713, 2354], + [2722, 2350], + [2714, 2327], + [2722, 2329], + [2731, 2352], + [2740, 2346], + [2732, 2334], + [2750, 2346], + [2752, 2318], + [2744, 2320], + [2736, 2307], + [2723, 2306], + [2725, 2316], + [2723, 2301], + [2714, 2290], + [2710, 2304], + [2702, 2304], + [2702, 2313], + [2693, 2318], + [2685, 2320], + [2686, 2310], + [2704, 2299], + [2703, 2289], + [2683, 2300], + [2675, 2294], + [2673, 2303], + [2665, 2298], + [2653, 2304], + [2662, 2298], + [2657, 2289], + [2669, 2293], + [2668, 2283], + [2678, 2289], + [2677, 2277], + [2683, 2285], + [2694, 2282], + [2693, 2266], + [2677, 2264], + [2675, 2254], + [2653, 2260], + [2654, 2270], + [2642, 2269], + [2647, 2259], + [2635, 2266], + [2620, 2242], + [2636, 2256], + [2652, 2253], + [2629, 2228], + [2623, 2204], + [2645, 2235], + [2669, 2245], + [2658, 2225], + [2646, 2205], + [2660, 2213], + [2677, 2198], + [2668, 2223], + [2680, 2227], + [2677, 2236], + [2717, 2275], + [2695, 2228], + [2713, 2238], + [2722, 2259], + [2737, 2242], + [2740, 2218], + [2722, 2199], + [2719, 2182], + [2727, 2191], + [2730, 2177], + [2742, 2169], + [2733, 2198], + [2738, 2208], + [2744, 2188], + [2756, 2187], + [2748, 2188], + [2743, 2208], + [2755, 2209], + [2747, 2236], + [2750, 2247], + [2760, 2245], + [2743, 2262], + [2742, 2274], + [2755, 2270], + [2766, 2291], + [2770, 2261], + [2783, 2253], + [2783, 2274], + [2797, 2272], + [2797, 2262], + [2806, 2267], + [2808, 2290], + [2796, 2294], + [2795, 2305], + [2809, 2309], + [2833, 2291], + [2851, 2258], + [2836, 2266], + [2826, 2257], + [2845, 2248], + [2833, 2244], + [2833, 2235], + [2813, 2245], + [2805, 2227], + [2787, 2242], + [2773, 2224], + [2789, 2229], + [2797, 2219], + [2781, 2202], + [2798, 2214], + [2808, 2209], + [2809, 2220], + [2825, 2230], + [2834, 2227], + [2830, 2215], + [2839, 2207], + [2840, 2218], + [2849, 2223], + [2860, 2203], + [2848, 2185], + [2836, 2195], + [2819, 2192], + [2836, 2189], + [2837, 2179], + [2825, 2164], + [2824, 2156], + [2794, 2148], + [2799, 2140], + [2790, 2130], + [2813, 2149], + [2822, 2147], + [2821, 2133], + [2835, 2159], + [2877, 2174], + [2870, 2160], + [2875, 2149], + [2856, 2150], + [2846, 2131], + [2838, 2134], + [2829, 2109], + [2841, 2122], + [2848, 2110], + [2858, 2117], + [2865, 2103], + [2851, 2093], + [2860, 2092], + [2858, 2083], + [2869, 2100], + [2867, 2110], + [2876, 2110], + [2868, 2121], + [2874, 2135], + [2886, 2133], + [2895, 2116], + [2890, 2138], + [2896, 2157], + [2909, 2148], + [2932, 2155], + [2940, 2177], + [2952, 2172], + [2908, 2089], + [2923, 2075], + [2923, 2049], + [2929, 2028], + [2895, 2023], + [2885, 2002], + [2871, 1999], + [2861, 2014], + [2837, 2011], + [2832, 2021], + [2851, 2042], + [2828, 2033], + [2831, 2049], + [2828, 2049], + [2814, 2049], + [2826, 2029], + [2811, 2019], + [2795, 2032], + [2801, 2018], + [2755, 2011], + [2757, 1995], + [2749, 1996], + [2750, 2007], + [2732, 2008], + [2733, 1998], + [2704, 1994], + [2715, 1985], + [2695, 1987], + [2713, 1981], + [2753, 1987], + [2772, 2002], + [2788, 1999], + [2788, 1988], + [2792, 2001], + [2828, 1999], + [2856, 1952], + [2837, 1954], + [2828, 1933], + [2815, 1928], + [2860, 1933], + [2854, 1971], + [2863, 1959], + [2872, 1966], + [2874, 1936], + [2882, 1933], + [2892, 1956], + [2896, 1943], + [2905, 1942], + [2911, 1961], + [2954, 1975], + [2966, 1967], + [2992, 1968], + [3021, 1984], + [3036, 2021], + [3030, 2047], + [3022, 2078], + [2973, 2093], + [3007, 2095], + [3051, 2113], + [3055, 2128], + [3044, 2153], + [3043, 2189], + [3066, 2238], + [3069, 2269], + [3049, 2299], + [3073, 2303], + [3094, 2306], + [3103, 2225], + [3136, 2196], + [3135, 2188], + [3126, 2194], + [3168, 2163], + [3157, 2149], + [3163, 2130], + [3141, 2120], + [3137, 2109], + [3141, 2083], + [3120, 2077], + [3119, 2109], + [3115, 2078], + [3104, 2078], + [3115, 2074], + [3112, 2064], + [3088, 2062], + [3078, 2047], + [3083, 2035], + [3092, 2042], + [3094, 2033], + [3106, 2038], + [3122, 2017], + [3115, 2006], + [3103, 2008], + [3105, 1998], + [3132, 1971], + [3125, 1979], + [3107, 1972], + [3107, 1956], + [3093, 1963], + [3081, 1966], + [3101, 1952], + [3089, 1939], + [3101, 1935], + [3121, 1953], + [3124, 1964], + [3142, 1956], + [3131, 1919], + [3111, 1905], + [3105, 1918], + [3103, 1908], + [3086, 1912], + [3099, 1897], + [3092, 1887], + [3077, 1887], + [3093, 1881], + [3103, 1894], + [3102, 1874], + [3093, 1869], + [3105, 1870], + [3111, 1858], + [3110, 1895], + [3124, 1899], + [3131, 1881], + [3144, 1877], + [3133, 1886], + [3146, 1889], + [3133, 1891], + [3168, 1888], + [3172, 1866], + [3183, 1858], + [3187, 1826], + [3176, 1824], + [3194, 1797], + [3178, 1774], + [3162, 1766], + [3156, 1779], + [3117, 1761], + [3119, 1775], + [3097, 1784], + [3092, 1795], + [3097, 1783], + [3096, 1772], + [3082, 1774], + [3110, 1736], + [3127, 1740], + [3138, 1756], + [3159, 1740], + [3187, 1737], + [3203, 1725], + [3210, 1699], + [3190, 1698], + [3192, 1690], + [3205, 1682], + [3235, 1684], + [3241, 1675], + [3262, 1675], + [3272, 1637], + [3286, 1633], + [3260, 1692], + [3238, 1703], + [3239, 1732], + [3231, 1767], + [3217, 1783], + [3258, 1823], + [3270, 1815], + [3249, 1859], + [3209, 1900], + [3211, 1916], + [3183, 1980], + [3196, 1975], + [3194, 1987], + [3203, 1997], + [3195, 1995], + [3175, 2017], + [3194, 2030], + [3207, 2029], + [3194, 2046], + [3179, 2049], + [3186, 2075], + [3215, 2074], + [3232, 2105], + [3250, 2117], + [3273, 2089], + [3330, 2061], + [3341, 2049], + [3370, 2001], + [3344, 1990], + [3321, 2016], + [3321, 1997], + [3311, 1995], + [3307, 2006], + [3305, 1984], + [3291, 1993], + [3294, 1972], + [3287, 1985], + [3266, 1991], + [3272, 1999], + [3262, 1999], + [3268, 2009], + [3258, 2004], + [3247, 2014], + [3239, 1990], + [3232, 2003], + [3235, 1987], + [3248, 1976], + [3232, 1931], + [3249, 1880], + [3283, 1873], + [3280, 1883], + [3254, 1882], + [3246, 1919], + [3237, 1925], + [3256, 1964], + [3266, 1955], + [3266, 1968], + [3288, 1957], + [3277, 1953], + [3281, 1942], + [3293, 1948], + [3316, 1916], + [3298, 1954], + [3313, 1970], + [3339, 1952], + [3324, 1969], + [3332, 1984], + [3347, 1968], + [3364, 1980], + [3375, 1976], + [3387, 1964], + [3378, 1953], + [3389, 1962], + [3399, 1946], + [3408, 1946], + [3396, 1937], + [3412, 1943], + [3429, 1933], + [3390, 1971], + [3390, 2008], + [3402, 1974], + [3451, 1903], + [3477, 1909], + [3508, 1895], + [3556, 1852], + [3573, 1824], + [3616, 1797], + [3610, 1781], + [3599, 1780], + [3601, 1795], + [3581, 1797], + [3584, 1806], + [3575, 1800], + [3573, 1783], + [3573, 1772], + [3579, 1792], + [3577, 1762], + [3585, 1760], + [3584, 1783], + [3601, 1792], + [3595, 1778], + [3608, 1779], + [3609, 1771], + [3602, 1756], + [3619, 1769], + [3630, 1746], + [3609, 1734], + [3622, 1726], + [3633, 1673], + [3625, 1656], + [3616, 1662], + [3603, 1637], + [3627, 1651], + [3604, 1630], + [3588, 1604], + [3564, 1640], + [3570, 1625], + [3553, 1620], + [3541, 1601], + [3527, 1597], + [3525, 1569], + [3523, 1539], + [3534, 1502], + [3533, 1531], + [3544, 1544], + [3542, 1553], + [3556, 1554], + [3546, 1571], + [3558, 1578], + [3555, 1596], + [3587, 1546], + [3603, 1473], + [3627, 1443], + [3625, 1422], + [3667, 1400], + [3667, 1370], + [3651, 1351], + [3682, 1339], + [3722, 1374], + [3778, 1376], + [3760, 1362], + [3748, 1337], + [3784, 1353], + [3807, 1317], + [3809, 1292], + [3822, 1285], + [3817, 1297], + [3825, 1325], + [3807, 1354], + [3832, 1359], + [3824, 1361], + [3827, 1369], + [3864, 1376], + [3877, 1401], + [3897, 1405], + [3907, 1393], + [3894, 1372], + [3903, 1353], + [3897, 1343], + [3906, 1344], + [3916, 1320], + [3943, 1312], + [3974, 1284], + [3993, 1285], + [4015, 1251], + [4016, 1224], + [4038, 1198], + [4057, 1198], + [4055, 1187], + [4073, 1191], + [4062, 1199], + [4074, 1200], + [4069, 1208], + [4070, 1220], + [4065, 1247], + [4057, 1255], + [4067, 1262], + [4057, 1256], + [4042, 1296], + [4022, 1317], + [4034, 1330], + [4024, 1334], + [4005, 1320], + [4005, 1344], + [4009, 1369], + [4025, 1379], + [4012, 1378], + [4004, 1394], + [4028, 1418], + [4017, 1429], + [3987, 1431], + [3971, 1442], + [3972, 1476], + [3957, 1504], + [3952, 1553], + [3942, 1580], + [3928, 1593], + [3932, 1638], + [3923, 1673], + [3881, 1719], + [3880, 1735], + [3894, 1743], + [3926, 1726], + [3923, 1713], + [3952, 1698], + [3956, 1664], + [3976, 1664], + [3979, 1651], + [4000, 1650], + [4003, 1622], + [4022, 1623], + [4023, 1611], + [4040, 1604], + [4036, 1592], + [4062, 1588], + [4062, 1573], + [4087, 1555], + [4095, 1555], + [4111, 1553], + [4115, 1537], + [4127, 1533], + [4121, 1502], + [4104, 1505], + [4096, 1492], + [4112, 1499], + [4112, 1478], + [4140, 1496], + [4160, 1481], + [4200, 1507], + [4224, 1474], + [4224, 1532], + [4190, 1541], + [4159, 1541], + [4133, 1596], + [4137, 1606], + [4178, 1607], + [4218, 1604], + [4224, 1600], + [4224, 1660], + [4208, 1675], + [4211, 1663], + [4203, 1664], + [4222, 1658], + [4194, 1643], + [4175, 1662], + [4175, 1679], + [4156, 1678], + [4161, 1687], + [4140, 1688], + [4138, 1680], + [4148, 1682], + [4128, 1651], + [4097, 1650], + [4070, 1649], + [4043, 1687], + [4056, 1707], + [4095, 1718], + [4082, 1720], + [4076, 1739], + [4078, 1727], + [4057, 1724], + [4052, 1713], + [4030, 1710], + [4030, 1698], + [4011, 1694], + [3982, 1748], + [3976, 1783], + [3959, 1802], + [3925, 1812], + [3906, 1845], + [3899, 1878], + [3908, 1864], + [3920, 1880], + [3920, 1871], + [3945, 1880], + [3949, 1887], + [3935, 1887], + [3939, 1900], + [3911, 1900], + [3906, 1910], + [3908, 1885], + [3893, 1900], + [3894, 1887], + [3884, 1881], + [3807, 1927], + [3795, 1949], + [3802, 1978], + [3593, 2033], + [3585, 2049], + [3571, 2080], + [3524, 2110], + [3517, 2123], + [3516, 2140], + [3532, 2163], + [3529, 2177], + [3536, 2167], + [3561, 2172], + [3575, 2164], + [3577, 2174], + [3549, 2180], + [3565, 2191], + [3571, 2211], + [3624, 2208], + [3642, 2181], + [3633, 2209], + [3658, 2215], + [3666, 2233], + [3650, 2240], + [3649, 2226], + [3620, 2230], + [3610, 2225], + [3611, 2215], + [3582, 2225], + [3572, 2218], + [3556, 2222], + [3544, 2213], + [3550, 2197], + [3538, 2180], + [3515, 2183], + [3492, 2211], + [3514, 2208], + [3529, 2215], + [3538, 2235], + [3573, 2263], + [3551, 2256], + [3551, 2247], + [3508, 2218], + [3497, 2225], + [3499, 2240], + [3489, 2242], + [3495, 2251], + [3478, 2222], + [3482, 2204], + [3496, 2201], + [3492, 2177], + [3473, 2183], + [3469, 2173], + [3449, 2171], + [3416, 2188], + [3408, 2213], + [3373, 2236], + [3372, 2260], + [3392, 2266], + [3397, 2277], + [3395, 2310], + [3412, 2312], + [3424, 2326], + [3422, 2345], + [3461, 2323], + [3458, 2334], + [3435, 2347], + [3420, 2377], + [3423, 2387], + [3439, 2383], + [3453, 2390], + [3454, 2406], + [3446, 2397], + [3429, 2391], + [3416, 2421], + [3429, 2428], + [3404, 2425], + [3421, 2404], + [3412, 2398], + [3409, 2362], + [3424, 2364], + [3386, 2337], + [3358, 2377], + [3330, 2383], + [3327, 2413], + [3317, 2430], + [3319, 2451], + [3328, 2475], + [3341, 2479], + [3353, 2469], + [3345, 2477], + [3350, 2495], + [3358, 2493], + [3369, 2510], + [3390, 2502], + [3389, 2510], + [3411, 2510], + [3370, 2515], + [3382, 2540], + [3391, 2541], + [3380, 2550], + [3356, 2506], + [3334, 2492], + [3318, 2495], + [3324, 2515], + [3318, 2503], + [3310, 2498], + [3315, 2488], + [3299, 2467], + [3305, 2435], + [3296, 2430], + [3299, 2420], + [3289, 2427], + [3269, 2463], + [3277, 2460], + [3282, 2481], + [3268, 2466], + [3259, 2491], + [3248, 2537], + [3260, 2547], + [3251, 2543], + [3247, 2555], + [3245, 2543], + [3231, 2579], + [3214, 2595], + [3197, 2630], + [3206, 2627], + [3203, 2639], + [3177, 2701], + [3135, 2759], + [3116, 2805], + [3104, 2876], + [3111, 2884], + [3138, 2885], + [3148, 2820], + [3144, 2798], + [3154, 2834], + [3141, 2892], + [3154, 2875], + [3169, 2870], + [3157, 2851], + [3165, 2826], + [3177, 2824], + [3170, 2813], + [3178, 2799], + [3202, 2789], + [3213, 2794], + [3189, 2797], + [3178, 2816], + [3193, 2826], + [3175, 2830], + [3171, 2848], + [3186, 2880], + [3193, 2859], + [3205, 2853], + [3193, 2869], + [3203, 2878], + [3201, 2904], + [3188, 2906], + [3175, 2883], + [3165, 2900], + [3154, 2884], + [3150, 2905], + [3183, 2933], + [3193, 2924], + [3216, 2933], + [3202, 2943], + [3200, 2962], + [3207, 2972], + [3205, 2988], + [3223, 3007], + [3194, 2987], + [3195, 2998], + [3229, 3061], + [3243, 3129], + [3240, 3182], + [3258, 3195], + [3250, 3204], + [3241, 3199], + [3247, 3212], + [3215, 3281], + [3073, 3283], + [3071, 3283], + [3032, 3283], + [3004, 3303], + [2976, 3371], + [2979, 3405], + [2970, 3445], + [2943, 3481], + [2943, 3494], + [2922, 3493], + [2951, 3507], + [2939, 3508], + [2932, 3528], + [2947, 3520], + [2931, 3530], + [2940, 3549], + [2920, 3528], + [2880, 3594], + [2860, 3665], + [2858, 3698], + [2867, 3707], + [2847, 3750], + [2857, 3750], + [2848, 3751], + [2853, 3863], + [2876, 3855], + [2854, 3866], + [2849, 3917], + [2820, 3998], + [2821, 4035], + [2842, 4044], + [2856, 3991], + [2890, 3967], + [2918, 3973], + [2908, 3941], + [2912, 3906], + [2919, 3946], + [2924, 3926], + [2930, 3937], + [2923, 3962], + [2932, 3957], + [2923, 3972], + [2951, 3940], + [2928, 3836], + [2933, 3820], + [2922, 3857], + [2923, 3835], + [2907, 3828], + [2904, 3812], + [2922, 3826], + [2936, 3790], + [2926, 3778], + [2918, 3784], + [2914, 3758], + [2900, 3761], + [2915, 3749], + [2907, 3715], + [2914, 3700], + [2922, 3762], + [2935, 3749], + [2929, 3727], + [2956, 3736], + [2955, 3712], + [2969, 3763], + [2988, 3763], + [2992, 3722], + [2979, 3716], + [2979, 3701], + [2998, 3681], + [2975, 3653], + [2959, 3649], + [2946, 3662], + [2958, 3641], + [2953, 3631], + [2933, 3642], + [2929, 3631], + [2939, 3625], + [2934, 3609], + [2945, 3617], + [2918, 3606], + [2932, 3599], + [2923, 3593], + [2938, 3593], + [2941, 3601], + [2952, 3594], + [2955, 3613], + [2963, 3616], + [2954, 3620], + [2969, 3621], + [2980, 3627], + [2979, 3638], + [2985, 3630], + [3000, 3642], + [3000, 3622], + [2983, 3621], + [2994, 3612], + [2975, 3584], + [2985, 3592], + [2984, 3572], + [2995, 3591], + [3002, 3551], + [2993, 3527], + [3007, 3553], + [3006, 3601], + [3016, 3595], + [3040, 3577], + [3017, 3529], + [3032, 3527], + [3036, 3554], + [3058, 3554], + [3047, 3564], + [3045, 3587], + [3036, 3598], + [3019, 3614], + [3026, 3645], + [3036, 3653], + [3034, 3663], + [3025, 3658], + [3027, 3687], + [3019, 3682], + [3007, 3691], + [3014, 3715], + [3033, 3724], + [3043, 3800], + [3059, 3796], + [3041, 3737], + [3057, 3689], + [3051, 3680], + [3059, 3680], + [3067, 3675], + [3061, 3654], + [3073, 3642], + [3073, 3663], + [3077, 3637], + [3073, 3628], + [3065, 3625], + [3064, 3605], + [3073, 3622], + [3081, 3621], + [3085, 3612], + [3090, 3571], + [3093, 3607], + [3075, 3651], + [3079, 3671], + [3102, 3651], + [3086, 3674], + [3097, 3669], + [3123, 3640], + [3124, 3651], + [3138, 3647], + [3125, 3661], + [3152, 3732], + [3161, 3721], + [3169, 3736], + [3171, 3723], + [3188, 3727], + [3186, 3706], + [3159, 3700], + [3148, 3665], + [3161, 3677], + [3165, 3664], + [3176, 3660], + [3173, 3649], + [3181, 3644], + [3170, 3634], + [3181, 3632], + [3181, 3622], + [3172, 3625], + [3176, 3598], + [3161, 3609], + [3148, 3604], + [3144, 3623], + [3132, 3611], + [3109, 3614], + [3120, 3605], + [3113, 3574], + [3121, 3580], + [3125, 3606], + [3141, 3601], + [3139, 3592], + [3158, 3598], + [3153, 3573], + [3143, 3572], + [3139, 3563], + [3158, 3566], + [3161, 3576], + [3175, 3567], + [3183, 3546], + [3194, 3557], + [3190, 3545], + [3179, 3542], + [3190, 3543], + [3191, 3533], + [3177, 3532], + [3191, 3531], + [3191, 3513], + [3204, 3506], + [3211, 3538], + [3206, 3526], + [3197, 3546], + [3205, 3561], + [3217, 3558], + [3224, 3568], + [3212, 3573], + [3222, 3576], + [3230, 3566], + [3250, 3562], + [3251, 3576], + [3260, 3569], + [3265, 3578], + [3264, 3589], + [3255, 3590], + [3259, 3600], + [3270, 3601], + [3274, 3592], + [3293, 3596], + [3278, 3596], + [3269, 3609], + [3273, 3620], + [3261, 3620], + [3264, 3611], + [3248, 3614], + [3230, 3590], + [3230, 3648], + [3253, 3651], + [3258, 3631], + [3268, 3627], + [3277, 3626], + [3294, 3644], + [3302, 3633], + [3308, 3658], + [3296, 3662], + [3295, 3683], + [3318, 3690], + [3318, 3675], + [3318, 3685], + [3331, 3685], + [3318, 3691], + [3326, 3713], + [3318, 3749], + [3322, 3774], + [3320, 3830], + [3332, 3821], + [3331, 3794], + [3341, 3772], + [3340, 3814], + [3348, 3806], + [3367, 3807], + [3374, 3794], + [3368, 3767], + [3378, 3753], + [3370, 3729], + [3382, 3741], + [3388, 3718], + [3385, 3692], + [3392, 3701], + [3394, 3688], + [3396, 3736], + [3378, 3764], + [3377, 3804], + [3370, 3816], + [3341, 3823], + [3313, 3975], + [3340, 4009], + [3347, 4053], + [3375, 4064], + [3358, 4069], + [3352, 4090], + [3363, 4085], + [3363, 4095], + [3363, 4097], + [3351, 4097], + [3336, 4132], + [3339, 4140], + [3347, 4136], + [3338, 4143], + [3333, 4172], + [3343, 4187], + [3350, 4178], + [3342, 4153], + [3358, 4157], + [3364, 4144], + [3376, 4143], + [3370, 4133], + [3382, 4134], + [3382, 4126], + [3397, 4133], + [3412, 4121], + [3411, 4107], + [3426, 4095], + [3447, 4079], + [3434, 4095], + [3422, 4108], + [3430, 4116], + [3415, 4123], + [3432, 4132], + [3381, 4147], + [3388, 4166], + [3375, 4160], + [3354, 4196], + [3357, 4209], + [3374, 4204], + [3370, 4224], + [3394, 4224], + [3407, 4205], + [3415, 4210], + [3423, 4197], + [3440, 4196], + [3436, 4184], + [3446, 4195], + [3462, 4189], + [3471, 4195], + [3431, 4202], + [3426, 4213], + [3407, 4224], + [3492, 4224], + [3492, 4214], + [3504, 4219], + [3519, 4197], + [3519, 4205], + [3534, 4208], + [3540, 4194], + [3554, 4190], + [3555, 4177], + [3543, 4181], + [3542, 4146], + [3532, 4145], + [3547, 4138], + [3541, 4097], + [3542, 4085], + [3529, 4075], + [3539, 4068], + [3538, 4079], + [3546, 4082], + [3571, 4062], + [3595, 4025], + [3604, 4025], + [3622, 3995], + [3611, 4014], + [3613, 4022], + [3593, 4031], + [3578, 4058], + [3585, 4067], + [3577, 4064], + [3550, 4085], + [3555, 4097], + [3563, 4098], + [3556, 4120], + [3574, 4111], + [3556, 4126], + [3558, 4139], + [3550, 4148], + [3563, 4173], + [3586, 4157], + [3586, 4140], + [3593, 4151], + [3603, 4135], + [3609, 4145], + [3635, 4134], + [3588, 4160], + [3565, 4189], + [3570, 4199], + [3645, 4193], + [3605, 4203], + [3608, 4214], + [3591, 4201], + [3586, 4215], + [3573, 4206], + [3563, 4209], + [3563, 4201], + [3553, 4204], + [3540, 4221], + [3546, 4224], + [3275, 4224], + [3266, 4212], + [3279, 4218], + [3289, 4199], + [3274, 4194], + [3279, 4180], + [3261, 4189], + [3271, 4177], + [3266, 4168], + [3263, 4158], + [3287, 4177], + [3299, 4162], + [3252, 4108], + [3248, 4128], + [3238, 4106], + [3246, 4101], + [3220, 4105], + [3228, 4123], + [3206, 4134], + [3212, 4120], + [3194, 4119], + [3201, 4110], + [3191, 4095], + [3179, 4089], + [3186, 4069], + [3171, 4059], + [3165, 4072], + [3161, 4085], + [3159, 4075], + [3149, 4081], + [3145, 4068], + [3157, 4065], + [3148, 4061], + [3167, 4049], + [3164, 4029], + [3156, 4017], + [3151, 4027], + [3152, 4035], + [3137, 4038], + [3137, 4057], + [3132, 4040], + [3124, 4037], + [3136, 4030], + [3128, 4014], + [3140, 4016], + [3140, 3987], + [3180, 3967], + [3175, 3949], + [3100, 4026], + [3096, 4037], + [3108, 4063], + [3091, 4065], + [3079, 4085], + [3071, 4081], + [3056, 4084], + [3047, 4074], + [3033, 4097], + [3018, 4123], + [3013, 4192], + [2988, 4224], + [3027, 4224], + [3044, 4223], + [3040, 4206], + [3046, 4219], + [3051, 4224], + [3074, 4224], + [3074, 4216], + [3076, 4224], + [3116, 4224], + [3111, 4198], + [3098, 4192], + [3094, 4178], + [3075, 4180], + [3069, 4127], + [3080, 4145], + [3084, 4173], + [3089, 4165], + [3100, 4169], + [3124, 4202], + [3132, 4190], + [3125, 4181], + [3134, 4185], + [3139, 4173], + [3127, 4143], + [3138, 4148], + [3157, 4136], + [3154, 4122], + [3144, 4124], + [3155, 4117], + [3153, 4109], + [3166, 4134], + [3140, 4155], + [3146, 4172], + [3131, 4214], + [3133, 4224], + [3161, 4224], + [3164, 4180], + [3176, 4203], + [3203, 4177], + [3199, 4162], + [3213, 4155], + [3207, 4166], + [3216, 4186], + [3208, 4187], + [3205, 4199], + [3189, 4197], + [3188, 4215], + [3170, 4221], + [3169, 4224], + [4224, 4224], + [4224, 4224], + [4224, -128], + [4224, -128], + [4224, 4224], + [2293, 4224] + ], + [ + [2681, 3125], + [2665, 3123], + [2657, 3113], + [2655, 3124], + [2640, 3119], + [2663, 3099], + [2642, 3105], + [2640, 3089], + [2618, 3108], + [2622, 3138], + [2622, 3153], + [2653, 3192], + [2652, 3210], + [2685, 3144], + [2681, 3125], + [2681, 3125] + ], + [ + [3189, 3788], + [3205, 3783], + [3206, 3763], + [3193, 3756], + [3189, 3788], + [3189, 3788] + ], + [[2264, 3287], [2274, 3283], [2269, 3270], [2264, 3287], [2264, 3287]], + [ + [2436, 3801], + [2448, 3809], + [2446, 3798], + [2462, 3796], + [2473, 3772], + [2449, 3781], + [2436, 3801], + [2436, 3801] + ], + [ + [3142, 2365], + [3155, 2362], + [3162, 2350], + [3157, 2333], + [3137, 2341], + [3122, 2401], + [3142, 2382], + [3142, 2365], + [3142, 2365] + ], + [[2761, 2561], [2769, 2563], [2780, 2549], [2761, 2561], [2761, 2561]], + [ + [2923, 2209], + [2910, 2200], + [2893, 2208], + [2898, 2222], + [2888, 2211], + [2896, 2176], + [2880, 2194], + [2862, 2195], + [2864, 2218], + [2876, 2232], + [2865, 2227], + [2886, 2247], + [2879, 2258], + [2884, 2266], + [2892, 2260], + [2894, 2239], + [2912, 2246], + [2917, 2236], + [2916, 2251], + [2907, 2248], + [2924, 2290], + [2934, 2286], + [2922, 2272], + [2928, 2254], + [2955, 2248], + [2946, 2241], + [2942, 2214], + [2923, 2209], + [2923, 2209] + ], + [ + [2823, 2539], + [2896, 2498], + [2911, 2465], + [2876, 2449], + [2805, 2496], + [2788, 2496], + [2792, 2523], + [2823, 2539], + [2823, 2539] + ], + [ + [3675, 1790], + [3740, 1742], + [3708, 1651], + [3683, 1646], + [3674, 1634], + [3638, 1646], + [3652, 1647], + [3661, 1664], + [3670, 1660], + [3649, 1717], + [3641, 1722], + [3647, 1736], + [3635, 1756], + [3653, 1759], + [3655, 1741], + [3666, 1743], + [3674, 1731], + [3662, 1730], + [3661, 1711], + [3670, 1711], + [3674, 1691], + [3678, 1695], + [3678, 1649], + [3688, 1650], + [3692, 1665], + [3684, 1671], + [3686, 1698], + [3696, 1689], + [3696, 1708], + [3707, 1709], + [3696, 1719], + [3707, 1731], + [3719, 1729], + [3702, 1729], + [3696, 1741], + [3688, 1759], + [3676, 1769], + [3675, 1790], + [3675, 1790] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/water2.json b/packages/melonjs/tests/earcut/fixtures/water2.json new file mode 100644 index 000000000..cd939b385 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/water2.json @@ -0,0 +1,1253 @@ +[ + [ + [-128, -128], + [-128, -128], + [-128, -128], + [-128, 1998], + [-119, 1978], + [-127, 2036], + [-128, 2037], + [-128, 2050], + [-107, 2044], + [-77, 2056], + [-61, 2076], + [-57, 2112], + [-59, 2198], + [-49, 2208], + [-29, 2196], + [-21, 2178], + [33, 2132], + [23, 2018], + [69, 1948], + [75, 1932], + [65, 1912], + [13, 1888], + [-13, 1862], + [-29, 1834], + [-67, 1832], + [-107, 1816], + [-128, 1817], + [-128, 962], + [-128, 962], + [-128, 1583], + [-121, 1578], + [-93, 1578], + [-55, 1586], + [-23, 1598], + [37, 1598], + [169, 1466], + [45, 1606], + [65, 1672], + [91, 1692], + [83, 1864], + [101, 1886], + [139, 1872], + [175, 1810], + [177, 1786], + [185, 1808], + [163, 1846], + [153, 1876], + [185, 1882], + [219, 1874], + [269, 1846], + [293, 1842], + [317, 1846], + [329, 1866], + [361, 1888], + [395, 1908], + [415, 1910], + [431, 1886], + [441, 1864], + [465, 1842], + [491, 1828], + [519, 1800], + [537, 1758], + [547, 1698], + [549, 1626], + [579, 1580], + [595, 1528], + [593, 1470], + [585, 1428], + [555, 1356], + [509, 1302], + [481, 1262], + [441, 1236], + [419, 1232], + [393, 1248], + [375, 1228], + [397, 1238], + [417, 1222], + [441, 1224], + [491, 1264], + [501, 1230], + [501, 1206], + [511, 1236], + [497, 1272], + [531, 1312], + [571, 1350], + [583, 1382], + [603, 1422], + [651, 1386], + [661, 1352], + [655, 1390], + [633, 1414], + [607, 1430], + [615, 1476], + [615, 1590], + [657, 1568], + [703, 1522], + [667, 1570], + [637, 1596], + [667, 1590], + [693, 1612], + [663, 1600], + [641, 1604], + [621, 1616], + [607, 1736], + [629, 1718], + [653, 1710], + [671, 1710], + [703, 1726], + [737, 1726], + [699, 1734], + [677, 1722], + [657, 1718], + [637, 1722], + [619, 1738], + [603, 1766], + [585, 1828], + [571, 1854], + [555, 1874], + [513, 1880], + [483, 1876], + [465, 1888], + [443, 1888], + [433, 1914], + [431, 1926], + [437, 1946], + [461, 1942], + [483, 1918], + [481, 1934], + [459, 1954], + [485, 1960], + [509, 1960], + [539, 1968], + [569, 1970], + [597, 1980], + [617, 1980], + [643, 1976], + [667, 1958], + [719, 1900], + [699, 1934], + [671, 1972], + [743, 1978], + [765, 1984], + [735, 1988], + [697, 1982], + [661, 1990], + [645, 1998], + [665, 2042], + [695, 2098], + [705, 2140], + [719, 2162], + [757, 2190], + [853, 2186], + [865, 2214], + [881, 2242], + [915, 2252], + [925, 2264], + [925, 2286], + [917, 2316], + [907, 2376], + [941, 2382], + [903, 2392], + [895, 2444], + [883, 2470], + [877, 2566], + [871, 2596], + [947, 2648], + [1011, 2686], + [1017, 2706], + [1029, 2708], + [1041, 2700], + [1099, 2724], + [1167, 2768], + [1427, 2832], + [1447, 2826], + [1467, 2810], + [1481, 2792], + [1487, 2766], + [1489, 2742], + [1480, 2705], + [1466, 2683], + [1429, 2654], + [1270, 2561], + [1243, 2565], + [1260, 2552], + [1209, 2524], + [1190, 2506], + [1187, 2482], + [1195, 2431], + [1215, 2397], + [1222, 2368], + [1210, 2357], + [1174, 2343], + [1126, 2305], + [1114, 2281], + [1099, 2136], + [1135, 2096], + [1174, 2060], + [1179, 2040], + [1173, 2020], + [1175, 2008], + [1170, 1976], + [1136, 1924], + [1121, 1897], + [1129, 1863], + [1157, 1815], + [1175, 1800], + [1205, 1791], + [1227, 1771], + [1243, 1737], + [1236, 1776], + [1218, 1800], + [1198, 1805], + [1178, 1818], + [1160, 1839], + [1140, 1887], + [1147, 1915], + [1170, 1942], + [1191, 1948], + [1211, 1962], + [1259, 1977], + [1301, 2020], + [1369, 2046], + [1385, 2048], + [1379, 2063], + [1409, 2125], + [1425, 2141], + [1444, 2188], + [1459, 2197], + [1549, 2188], + [1579, 2180], + [1592, 2165], + [1601, 2136], + [1595, 2110], + [1579, 2086], + [1556, 2073], + [1529, 2070], + [1485, 2071], + [1444, 2053], + [1423, 2036], + [1453, 2042], + [1483, 2056], + [1511, 2058], + [1529, 2055], + [1560, 2061], + [1597, 2085], + [1636, 2120], + [1653, 2115], + [1681, 2098], + [1693, 2072], + [1696, 2048], + [1696, 2016], + [1713, 2003], + [1702, 1986], + [1705, 1966], + [1675, 1931], + [1659, 1920], + [1626, 1915], + [1571, 1885], + [1554, 1857], + [1573, 1877], + [1627, 1907], + [1665, 1912], + [1686, 1925], + [1711, 1953], + [1739, 1963], + [1731, 1945], + [1707, 1909], + [1661, 1846], + [1631, 1839], + [1575, 1842], + [1602, 1839], + [1618, 1827], + [1642, 1824], + [1671, 1834], + [1703, 1862], + [1755, 1893], + [1774, 1896], + [1798, 1891], + [1823, 1878], + [1843, 1862], + [1857, 1814], + [1835, 1738], + [1871, 1804], + [1890, 1811], + [1903, 1824], + [1911, 1841], + [1937, 1864], + [1974, 1888], + [2001, 1894], + [2026, 1906], + [2047, 1921], + [2062, 1952], + [2076, 2007], + [2092, 1995], + [2091, 1910], + [2081, 1879], + [2085, 1853], + [2127, 1818], + [2134, 1801], + [2127, 1787], + [2102, 1764], + [2099, 1746], + [2103, 1728], + [1649, 1232], + [1587, 1151], + [1616, 1180], + [1651, 1226], + [2110, 1719], + [2122, 1720], + [2153, 1755], + [2175, 1772], + [2202, 1775], + [2214, 1750], + [2218, 1728], + [2205, 1715], + [2186, 1704], + [2179, 1689], + [2186, 1674], + [2203, 1672], + [2236, 1679], + [2247, 1666], + [2251, 1648], + [2231, 1615], + [2226, 1573], + [2218, 1565], + [2200, 1574], + [2178, 1572], + [2166, 1561], + [2165, 1549], + [2179, 1538], + [2198, 1513], + [2192, 1477], + [2166, 1483], + [2141, 1480], + [2121, 1442], + [2116, 1427], + [2100, 1420], + [2077, 1420], + [2059, 1409], + [2061, 1378], + [2079, 1319], + [2095, 1305], + [2117, 1303], + [2135, 1314], + [2147, 1330], + [2171, 1325], + [2183, 1312], + [2183, 1290], + [2163, 1260], + [2143, 1238], + [2107, 1221], + [2101, 1206], + [2104, 1191], + [2122, 1176], + [2143, 1160], + [2151, 1143], + [2147, 1126], + [2135, 1114], + [2115, 1111], + [2095, 1101], + [2084, 1086], + [2087, 1067], + [2111, 1023], + [2109, 1010], + [2095, 1002], + [2081, 984], + [2081, 962], + [2095, 945], + [2115, 937], + [2137, 939], + [2157, 929], + [2161, 889], + [2153, 869], + [2127, 869], + [2101, 859], + [2091, 829], + [2093, 801], + [2121, 783], + [2151, 783], + [2167, 799], + [2189, 791], + [2197, 771], + [2191, 741], + [2199, 729], + [2231, 713], + [2237, 699], + [2209, 681], + [2191, 659], + [2189, 635], + [2207, 591], + [2233, 553], + [2231, 519], + [2239, 495], + [2255, 483], + [2271, 443], + [2299, 437], + [2341, 439], + [2371, 421], + [2419, 399], + [2443, 397], + [2457, 405], + [2483, 393], + [2515, 371], + [2545, 361], + [2597, 359], + [2631, 321], + [2665, 317], + [2705, 319], + [2679, 327], + [2678, 327], + [2645, 327], + [2636, 332], + [2615, 361], + [2591, 371], + [2541, 373], + [2507, 389], + [2469, 415], + [2453, 415], + [2429, 405], + [2401, 415], + [2363, 445], + [2337, 457], + [2303, 453], + [2283, 457], + [2271, 477], + [2247, 507], + [2239, 531], + [2245, 555], + [2213, 605], + [2201, 641], + [2201, 655], + [2247, 687], + [2257, 707], + [2217, 733], + [2203, 747], + [2209, 775], + [2197, 801], + [2171, 811], + [2153, 805], + [2141, 797], + [2117, 801], + [2103, 819], + [2107, 839], + [2129, 851], + [2165, 857], + [2177, 873], + [2175, 897], + [2167, 923], + [2153, 949], + [2107, 957], + [2095, 969], + [2097, 985], + [2121, 1003], + [2135, 1021], + [2127, 1041], + [2105, 1065], + [2107, 1075], + [2121, 1089], + [2145, 1103], + [2163, 1125], + [2167, 1143], + [2157, 1163], + [2125, 1191], + [2119, 1203], + [2135, 1221], + [2161, 1233], + [2199, 1287], + [2201, 1299], + [2195, 1323], + [2175, 1339], + [2147, 1341], + [2129, 1337], + [2125, 1319], + [2113, 1317], + [2095, 1335], + [2087, 1353], + [2077, 1397], + [2079, 1411], + [2117, 1407], + [2135, 1415], + [2149, 1457], + [2165, 1467], + [2415, 1383], + [2205, 1467], + [2213, 1487], + [2211, 1523], + [2201, 1545], + [2183, 1557], + [2223, 1553], + [2233, 1563], + [2243, 1579], + [2241, 1597], + [2255, 1617], + [2273, 1625], + [2477, 1599], + [2263, 1639], + [2261, 1671], + [2251, 1687], + [2237, 1697], + [2223, 1701], + [2199, 1695], + [2227, 1713], + [2237, 1733], + [2233, 1761], + [2219, 1781], + [2207, 1791], + [2225, 1811], + [2245, 1827], + [2281, 1839], + [2315, 1839], + [2377, 1855], + [2313, 1849], + [2277, 1853], + [2251, 1843], + [2223, 1825], + [2207, 1807], + [2193, 1799], + [2173, 1797], + [2159, 1799], + [2153, 1821], + [2141, 1839], + [2115, 1853], + [2105, 1871], + [2113, 2025], + [2117, 2057], + [2113, 2077], + [2101, 2097], + [2095, 2119], + [2101, 2135], + [2121, 2151], + [2133, 2169], + [2127, 2193], + [2129, 2211], + [2145, 2221], + [2167, 2215], + [2195, 2199], + [2219, 2191], + [2265, 2189], + [2293, 2169], + [2317, 2143], + [2355, 2137], + [2377, 2141], + [2427, 1971], + [2387, 2147], + [2401, 2165], + [2535, 2167], + [2405, 2179], + [2421, 2205], + [2441, 2227], + [2445, 2255], + [2427, 2287], + [2391, 2325], + [2365, 2357], + [2361, 2381], + [2349, 2397], + [2327, 2419], + [2291, 2413], + [2263, 2453], + [2229, 2473], + [2251, 2491], + [2265, 2555], + [2263, 2583], + [2253, 2613], + [2285, 2623], + [2331, 2645], + [2319, 2617], + [2319, 2583], + [2335, 2565], + [2359, 2565], + [2389, 2603], + [2401, 2627], + [2447, 2639], + [2475, 2631], + [2493, 2619], + [2515, 2615], + [2561, 2633], + [2603, 2635], + [2636, 2627], + [2661, 2571], + [2687, 2569], + [2678, 2561], + [2655, 2537], + [2636, 2546], + [2621, 2553], + [2581, 2555], + [2549, 2539], + [2523, 2509], + [2571, 2537], + [2611, 2545], + [2636, 2533], + [2653, 2525], + [2637, 2503], + [2701, 2565], + [2737, 2561], + [2679, 2583], + [2669, 2599], + [2667, 2619], + [2659, 2637], + [2673, 2651], + [2677, 2679], + [2665, 2697], + [2641, 2719], + [2609, 2733], + [2601, 2759], + [2599, 2787], + [2633, 2785], + [2671, 2787], + [2701, 2725], + [2725, 2715], + [2779, 2717], + [2725, 2723], + [2705, 2739], + [2689, 2771], + [2683, 2791], + [2693, 2793], + [2737, 2831], + [2687, 2797], + [2678, 2795], + [2667, 2793], + [2599, 2797], + [2589, 2819], + [2575, 2839], + [2581, 2881], + [2607, 2901], + [2611, 2927], + [2623, 2951], + [2636, 2968], + [2647, 2997], + [2649, 3019], + [2671, 3031], + [2687, 3029], + [2733, 3053], + [2747, 3067], + [2753, 3089], + [2741, 3117], + [2709, 3139], + [2757, 3151], + [2791, 3129], + [2837, 3093], + [2865, 3063], + [2877, 3041], + [2871, 3019], + [2823, 2963], + [2885, 3017], + [2909, 2993], + [2951, 2975], + [2909, 3007], + [2887, 3027], + [2885, 3053], + [2867, 3081], + [2833, 3109], + [2805, 3139], + [2817, 3153], + [2973, 3125], + [2983, 3135], + [2995, 3157], + [2971, 3135], + [2939, 3135], + [2809, 3165], + [2795, 3177], + [2801, 3191], + [2795, 3207], + [2783, 3221], + [2785, 3239], + [2801, 3251], + [2823, 3253], + [2847, 3239], + [2879, 3245], + [2901, 3257], + [2921, 3273], + [2931, 3303], + [2947, 3277], + [2967, 3273], + [3013, 3297], + [3027, 3315], + [3179, 3419], + [3227, 3457], + [3257, 3455], + [3275, 3441], + [3265, 3417], + [3283, 3351], + [3277, 3327], + [3293, 3293], + [3119, 3119], + [3297, 3283], + [3305, 3303], + [3295, 3323], + [3309, 3333], + [3327, 3321], + [3331, 3293], + [3383, 3241], + [3387, 3211], + [3351, 3187], + [3321, 3153], + [3289, 3091], + [3279, 3051], + [3263, 3047], + [3217, 3077], + [3179, 3083], + [3147, 3067], + [3199, 3071], + [3235, 3055], + [3261, 3039], + [3217, 2997], + [3115, 2953], + [3169, 2955], + [3219, 2977], + [3261, 3019], + [3289, 3039], + [3303, 3081], + [3313, 3121], + [3351, 3171], + [3395, 3195], + [3415, 3153], + [3433, 3131], + [3435, 3055], + [3403, 3049], + [3373, 3033], + [3303, 2931], + [3281, 2915], + [3213, 2909], + [3287, 2907], + [3311, 2925], + [3381, 3027], + [3417, 3043], + [3443, 3045], + [3449, 3061], + [3443, 3123], + [3475, 3115], + [3493, 3091], + [3485, 3113], + [3521, 3107], + [3545, 3085], + [3577, 2981], + [3567, 2961], + [3519, 2943], + [3515, 2933], + [3491, 2937], + [3447, 2913], + [3363, 2899], + [3449, 2901], + [3497, 2923], + [3527, 2921], + [3533, 2895], + [3557, 2881], + [3585, 2875], + [3635, 2839], + [3615, 2817], + [3589, 2797], + [3603, 2777], + [3609, 2743], + [3591, 2723], + [3587, 2709], + [3453, 2701], + [3435, 2695], + [3411, 2719], + [3179, 2655], + [3409, 2707], + [3439, 2685], + [3467, 2691], + [3585, 2695], + [3607, 2639], + [3597, 2605], + [3609, 2567], + [3601, 2557], + [3539, 2551], + [3531, 2531], + [3551, 2515], + [3593, 2505], + [3629, 2463], + [3617, 2419], + [3605, 2389], + [3583, 2365], + [3581, 2341], + [3553, 2347], + [3477, 2343], + [3465, 2315], + [3479, 2289], + [3473, 2265], + [3453, 2283], + [3431, 2289], + [3407, 2285], + [3381, 2267], + [3377, 2245], + [3405, 2213], + [3397, 2195], + [3361, 2197], + [3337, 2209], + [3313, 2213], + [3305, 2235], + [3319, 2261], + [3321, 2287], + [3305, 2335], + [3311, 2287], + [3305, 2259], + [3289, 2235], + [3301, 2215], + [3321, 2199], + [3347, 2195], + [3371, 2181], + [3395, 2187], + [3407, 2139], + [3391, 2121], + [3379, 2083], + [3375, 2019], + [3367, 1959], + [3373, 1913], + [3371, 1893], + [3313, 1855], + [3299, 1829], + [3305, 1797], + [3305, 1781], + [3289, 1769], + [3243, 1759], + [3209, 1737], + [3183, 1699], + [3155, 1687], + [3141, 1673], + [3151, 1627], + [3151, 1603], + [3189, 1555], + [3201, 1533], + [3181, 1483], + [3189, 1465], + [3225, 1463], + [3239, 1441], + [3269, 1439], + [3287, 1421], + [3307, 1411], + [3329, 1417], + [3349, 1403], + [3355, 1373], + [3385, 1341], + [3389, 1313], + [3377, 1269], + [3387, 1253], + [3399, 1211], + [3409, 1197], + [3403, 1183], + [3407, 1169], + [3439, 1145], + [3445, 1101], + [3439, 1063], + [3455, 1047], + [3459, 1025], + [3471, 1007], + [3483, 981], + [3505, 961], + [3569, 935], + [3639, 895], + [3569, 945], + [3509, 971], + [3489, 985], + [3479, 1007], + [3463, 1031], + [3465, 1049], + [3449, 1065], + [3453, 1101], + [3449, 1143], + [3431, 1165], + [3411, 1179], + [3423, 1197], + [3411, 1211], + [3389, 1273], + [3395, 1317], + [3393, 1339], + [3373, 1371], + [3363, 1379], + [3359, 1405], + [3337, 1427], + [3305, 1425], + [3277, 1441], + [3259, 1459], + [3243, 1455], + [3227, 1475], + [3197, 1481], + [3209, 1511], + [3213, 1541], + [3173, 1595], + [3161, 1623], + [3157, 1657], + [3165, 1671], + [3197, 1689], + [3221, 1729], + [3263, 1751], + [3291, 1751], + [3319, 1767], + [3325, 1795], + [3319, 1817], + [3331, 1847], + [3363, 1865], + [3383, 1883], + [3395, 1909], + [3387, 1985], + [3397, 2027], + [3399, 2071], + [3415, 2097], + [3423, 2117], + [3423, 2141], + [3415, 2185], + [3429, 2211], + [3473, 2235], + [3497, 2257], + [3501, 2287], + [3489, 2309], + [3495, 2325], + [3531, 2331], + [3565, 2321], + [3593, 2327], + [3605, 2353], + [3603, 2367], + [3631, 2387], + [3729, 2143], + [3771, 2119], + [3735, 2149], + [3635, 2407], + [3649, 2459], + [3737, 2519], + [3733, 2477], + [3747, 2447], + [3811, 2361], + [3749, 2461], + [3739, 2487], + [3745, 2531], + [3741, 2557], + [3729, 2583], + [3699, 2625], + [3695, 2649], + [3707, 2671], + [3753, 2731], + [3791, 2773], + [3805, 2811], + [3823, 2847], + [3855, 2803], + [3853, 2771], + [3837, 2759], + [3829, 2737], + [3797, 2695], + [3785, 2689], + [3801, 2653], + [3831, 2651], + [3835, 2623], + [3851, 2621], + [3857, 2593], + [3867, 2569], + [3865, 2547], + [3879, 2529], + [3873, 2553], + [3875, 2577], + [3861, 2625], + [3845, 2633], + [3841, 2659], + [3807, 2661], + [3799, 2681], + [3843, 2737], + [3847, 2753], + [3865, 2765], + [3865, 2807], + [3837, 2847], + [3845, 2865], + [3869, 2899], + [3889, 2945], + [3911, 3021], + [3951, 3069], + [3959, 3097], + [3955, 3129], + [3975, 3143], + [4017, 3147], + [4051, 3169], + [4075, 3188], + [4087, 3197], + [4117, 3198], + [4145, 3199], + [4177, 3223], + [4215, 3245], + [4213, 3279], + [4199, 3331], + [4224, 3350], + [4224, 3661], + [4117, 3663], + [4081, 3664], + [3963, 3670], + [3937, 3690], + [3941, 3736], + [3949, 3798], + [3965, 3816], + [3987, 3852], + [4045, 3858], + [4075, 3832], + [4089, 3820], + [4155, 3788], + [4215, 3782], + [4224, 3785], + [4224, 4062], + [4195, 4066], + [4179, 4088], + [4189, 4112], + [4224, 4129], + [4224, 4145], + [4177, 4122], + [4101, 4200], + [4082, 4224], + [4224, 4224], + [4224, 4224], + [-128, 4224], + [-128, -128] + ], + [ + [4117, 4162], + [4161, 4115], + [4165, 4091], + [4177, 4067], + [4203, 4053], + [4224, 4047], + [4224, 3801], + [4181, 3801], + [4157, 3801], + [4127, 3819], + [4081, 3857], + [4041, 3877], + [3997, 3875], + [3969, 3851], + [3941, 3831], + [3933, 3769], + [3911, 3717], + [3925, 3665], + [3929, 3639], + [3879, 3619], + [3849, 3581], + [3823, 3601], + [3815, 3629], + [3829, 3669], + [3861, 3699], + [3883, 3737], + [3883, 3775], + [3881, 3827], + [3867, 3869], + [3839, 3907], + [3787, 3959], + [3783, 3989], + [3801, 4005], + [3797, 4027], + [3799, 4061], + [3813, 4093], + [3805, 4141], + [3795, 4191], + [3789, 4221], + [3801, 4224], + [3907, 4224], + [4033, 4217], + [4049, 4224], + [4059, 4224], + [4117, 4162], + [4117, 4162] + ], + [ + [3857, 2915], + [3833, 2925], + [3817, 2921], + [3807, 2913], + [3773, 2913], + [3761, 2927], + [3765, 2957], + [3757, 2979], + [3773, 2991], + [3791, 2995], + [3789, 3013], + [3817, 3017], + [3835, 3027], + [3839, 3039], + [3827, 3047], + [3817, 3055], + [3811, 3077], + [3789, 3085], + [3765, 3079], + [3739, 3093], + [3711, 3107], + [3705, 3115], + [3707, 3135], + [3689, 3161], + [3705, 3167], + [3695, 3197], + [3705, 3205], + [3723, 3211], + [3723, 3231], + [3751, 3229], + [3749, 3217], + [3767, 3203], + [3799, 3167], + [3793, 3131], + [3809, 3117], + [3869, 3085], + [3911, 3057], + [3891, 3035], + [3887, 3001], + [3871, 2959], + [3857, 2915], + [3857, 2915] + ], + [ + [3653, 2641], + [3665, 2621], + [3681, 2615], + [3693, 2613], + [3731, 2567], + [3737, 2541], + [3727, 2521], + [3649, 2473], + [3625, 2503], + [3599, 2519], + [3573, 2525], + [3555, 2531], + [3555, 2543], + [3603, 2541], + [3631, 2553], + [3625, 2579], + [3615, 2607], + [3625, 2643], + [3653, 2641], + [3653, 2641] + ], + [ + [3413, 2227], + [3395, 2243], + [3393, 2261], + [3413, 2273], + [3433, 2277], + [3473, 2259], + [3413, 2227], + [3413, 2227] + ], + [ + [1991, 2570], + [2223, 2614], + [2239, 2600], + [2247, 2570], + [2237, 2542], + [2235, 2516], + [2223, 2504], + [2207, 2490], + [2213, 2464], + [2225, 2446], + [2249, 2440], + [2255, 2424], + [2263, 2406], + [2283, 2394], + [2307, 2388], + [2333, 2394], + [2343, 2386], + [2343, 2364], + [2351, 2340], + [2373, 2318], + [2403, 2298], + [2417, 2272], + [2421, 2256], + [2411, 2234], + [2397, 2200], + [2379, 2172], + [2349, 2158], + [2333, 2156], + [2315, 2166], + [2303, 2192], + [2279, 2208], + [2241, 2208], + [2221, 2212], + [2197, 2218], + [2181, 2228], + [2159, 2246], + [2139, 2256], + [2127, 2260], + [2111, 2266], + [2127, 2332], + [2251, 2288], + [2121, 2348], + [2099, 2358], + [2081, 2378], + [2055, 2388], + [2015, 2410], + [1973, 2430], + [1951, 2442], + [1945, 2456], + [1947, 2476], + [1963, 2484], + [2095, 2432], + [1969, 2494], + [1965, 2510], + [1971, 2524], + [1983, 2538], + [1989, 2552], + [1991, 2570], + [1991, 2570] + ], + [ + [850, 2552], + [858, 2452], + [790, 2436], + [778, 2380], + [806, 2416], + [870, 2428], + [910, 2276], + [870, 2256], + [838, 2204], + [762, 2212], + [706, 2164], + [686, 2128], + [634, 2016], + [582, 1996], + [510, 1976], + [422, 1964], + [370, 1928], + [314, 1884], + [270, 1884], + [218, 1908], + [130, 1924], + [134, 1988], + [106, 2028], + [86, 2064], + [114, 2108], + [114, 2152], + [-22, 2292], + [-102, 2272], + [-128, 2252], + [-128, 2319], + [-106, 2328], + [-102, 2364], + [-10, 2400], + [98, 2400], + [234, 2408], + [338, 2432], + [450, 2448], + [606, 2488], + [734, 2536], + [850, 2552], + [850, 2552] + ], + [ + [-128, 1781], + [-118, 1780], + [-54, 1808], + [-2, 1820], + [30, 1860], + [58, 1860], + [74, 1708], + [46, 1692], + [18, 1620], + [-54, 1608], + [-114, 1608], + [-128, 1615], + [-128, 1781] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/water3.json b/packages/melonjs/tests/earcut/fixtures/water3.json new file mode 100644 index 000000000..4ac8d9cc5 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/water3.json @@ -0,0 +1,220 @@ +[ + [[-128, 4224], [-128, -128], [4224, -128], [4224, 4224], [-128, 4224]], + [ + [3030, -21], + [3019, 7], + [3025, 21], + [3045, 65], + [3054, 114], + [3041, 189], + [3000, 219], + [3017, 257], + [2966, 338], + [2938, 340], + [2934, 541], + [2973, 618], + [2979, 752], + [3026, 803], + [3052, 938], + [3083, 1030], + [3034, 1175], + [3041, 1264], + [3083, 1311], + [3088, 1348], + [3067, 1399], + [3139, 1435], + [3209, 1412], + [3220, 1378], + [3242, 1316], + [3276, 1335], + [3314, 1367], + [3369, 1529], + [3436, 1563], + [3464, 1681], + [3512, 1732], + [3521, 1811], + [3508, 1883], + [3591, 1939], + [3724, 2088], + [3828, 2171], + [3867, 2238], + [3905, 2344], + [3939, 2443], + [3892, 2498], + [3889, 2521], + [3884, 2560], + [3942, 2624], + [3986, 2681], + [3999, 2831], + [4089, 3008], + [4117, 3130], + [4104, 3172], + [4023, 3205], + [3969, 3283], + [3991, 3347], + [4091, 3365], + [4146, 3411], + [4136, 3456], + [4068, 3467], + [3999, 3412], + [3978, 3373], + [3935, 3350], + [3937, 3401], + [4001, 3465], + [4036, 3503], + [3941, 3459], + [3907, 3533], + [3939, 3655], + [3867, 3574], + [3867, 3663], + [3796, 3614], + [3773, 3730], + [3880, 4118], + [3854, 4159], + [3891, 4224], + [4084, 4224], + [4106, 4103], + [4213, 4062], + [4224, 4060], + [4224, 2439], + [4155, 2244], + [4020, 2282], + [3978, 2233], + [3976, 2146], + [3927, 2103], + [3937, 2060], + [3910, 1930], + [3933, 1862], + [3893, 1781], + [3850, 1774], + [3803, 1712], + [3824, 1651], + [3794, 1572], + [3820, 1535], + [3835, 1493], + [3920, 1550], + [3957, 1520], + [3948, 1444], + [3973, 1459], + [3982, 1508], + [4016, 1520], + [4012, 1471], + [4042, 1426], + [4068, 1422], + [4198, 1390], + [4224, 1368], + [4224, 969], + [4214, 1019], + [4177, 1095], + [4142, 1070], + [4176, 978], + [4202, 843], + [4213, 653], + [4181, 656], + [4181, 804], + [4155, 796], + [4138, 673], + [4114, 600], + [4050, 622], + [4050, 573], + [4100, 551], + [4050, 379], + [4015, 274], + [3986, 208], + [3972, 175], + [3965, 158], + [3953, 131], + [3921, 99], + [3885, 60], + [3853, 29], + [3807, -4], + [3755, -27], + [3692, -53], + [3639, -58], + [3595, -34], + [3573, -11], + [3519, -4], + [3488, 17], + [3467, 6], + [3426, 4], + [3384, 25], + [3308, 28], + [3263, -93], + [3126, -83], + [3041, -46], + [3030, -21], + [3030, -21] + ], + [ + [3832, -21], + [3840, -17], + [3877, 21], + [3895, 39], + [3961, -21], + [3893, -98], + [3855, -128], + [3688, -128], + [3742, -81], + [3793, -41], + [3832, -21], + [3832, -21] + ], + [ + [4205, 596], + [4224, 572], + [4224, 248], + [4166, 163], + [4119, 50], + [4020, 36], + [4004, 21], + [3969, 21], + [3936, 62], + [3982, 117], + [4088, 293], + [4152, 419], + [4185, 544], + [4205, 596], + [4205, 596] + ], + [ + [3228, 2459], + [3243, 2459], + [3248, 2434], + [3273, 2429], + [3218, 2186], + [3255, 2102], + [3285, 2094], + [3314, 1972], + [3198, 1969], + [3192, 1943], + [3223, 1943], + [3222, 1913], + [3177, 1928], + [3187, 1979], + [3180, 2171], + [3134, 2187], + [3212, 2399], + [3243, 2398], + [3228, 2459], + [3228, 2459] + ], + [ + [4224, 1574], + [4212, 1572], + [4175, 1600], + [4152, 1647], + [4131, 1689], + [4106, 1736], + [4101, 1785], + [4115, 1851], + [4149, 1885], + [4169, 1920], + [4204, 1908], + [4224, 1875], + [4214, 1844], + [4199, 1798], + [4215, 1763], + [4224, 1767], + [4224, 1574] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/water3b.json b/packages/melonjs/tests/earcut/fixtures/water3b.json new file mode 100644 index 000000000..dd9f2e137 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/water3b.json @@ -0,0 +1,34 @@ +[ + [[-128, 4224], [-128, -128], [4224, -128], [4224, 4224], [-128, 4224]], + [ + [3832, -21], + [3840, -17], + [3877, 21], + [3895, 39], + [3961, -21], + [3893, -98], + [3855, -128], + [3688, -128], + [3742, -81], + [3793, -41], + [3832, -21], + [3832, -21] + ], + [ + [4205, 596], + [4224, 572], + [4224, 248], + [4166, 163], + [4119, 50], + [4020, 36], + [4004, 21], + [3969, 21], + [3936, 62], + [3982, 117], + [4088, 293], + [4152, 419], + [4185, 544], + [4205, 596], + [4205, 596] + ] +] diff --git a/packages/melonjs/tests/earcut/fixtures/water4.json b/packages/melonjs/tests/earcut/fixtures/water4.json new file mode 100644 index 000000000..fffd5e282 --- /dev/null +++ b/packages/melonjs/tests/earcut/fixtures/water4.json @@ -0,0 +1,734 @@ +[ + [ + [3911, 4075], + [3910, 4075], + [3926, 4114], + [3950, 4132], + [3965, 4126], + [3978, 4139], + [3986, 4131], + [3979, 4119], + [3986, 4084], + [3991, 4075], + [4020, 4020], + [4027, 4012], + [4030, 4022], + [4047, 4033], + [4058, 4030], + [4067, 4022], + [4120, 4003], + [4118, 3993], + [4135, 3995], + [4130, 4032], + [4121, 4038], + [4118, 4056], + [4107, 4050], + [4095, 4060], + [4086, 4062], + [4070, 4075], + [4027, 4111], + [4042, 4140], + [4058, 4139], + [4067, 4135], + [4078, 4138], + [4067, 4151], + [4067, 4166], + [4077, 4180], + [4088, 4191], + [4047, 4172], + [4031, 4161], + [4020, 4165], + [4000, 4147], + [4013, 4171], + [4000, 4224], + [3836, 4224], + [3828, 4224], + [3071, 4224], + [3070, 4212], + [3158, 4140], + [3202, 4158], + [3171, 4117], + [3161, 4104], + [3136, 4131], + [3122, 4117], + [3105, 4099], + [3122, 4075], + [3136, 4055], + [3156, 4075], + [3178, 4097], + [3205, 4082], + [3176, 4036], + [3187, 3979], + [3105, 3947], + [3084, 3920], + [3036, 3976], + [2980, 3982], + [2993, 4043], + [2956, 3964], + [3020, 3960], + [3050, 3921], + [3032, 3880], + [3069, 3902], + [3093, 3894], + [3188, 3961], + [3236, 3917], + [3222, 3893], + [3191, 3891], + [3173, 3863], + [3187, 3818], + [3225, 3775], + [3292, 3774], + [3239, 3798], + [3197, 3845], + [3211, 3873], + [3249, 3877], + [3442, 3801], + [3567, 3769], + [3587, 3798], + [3632, 3777], + [3607, 3820], + [3644, 3880], + [3707, 3851], + [3726, 3899], + [3766, 3951], + [3770, 3977], + [3778, 3985], + [3772, 4012], + [3763, 3998], + [3745, 3990], + [3747, 3977], + [3738, 3974], + [3735, 3985], + [3725, 3995], + [3745, 4010], + [3758, 4024], + [3763, 4048], + [3772, 4067], + [3762, 4074], + [3754, 4093], + [3763, 4094], + [3779, 4083], + [3779, 4074], + [3784, 4066], + [3792, 4060], + [3794, 4043], + [3795, 4029], + [3798, 4016], + [3807, 4006], + [3799, 3933], + [3849, 3871], + [3838, 3840], + [3885, 3818], + [3913, 3778], + [3958, 3687], + [4056, 3501], + [4109, 3301], + [3956, 3259], + [3876, 3277], + [3775, 3251], + [3705, 3225], + [3659, 3243], + [3613, 3232], + [3614, 3310], + [3606, 3266], + [3552, 3297], + [3494, 3235], + [3440, 3221], + [3402, 3190], + [3344, 3177], + [3264, 3142], + [3279, 3201], + [3248, 3256], + [3229, 3197], + [3200, 3194], + [3191, 3246], + [3159, 3244], + [3125, 3282], + [3097, 3296], + [3068, 3279], + [3013, 3393], + [3002, 3486], + [2994, 3383], + [2917, 3406], + [2985, 3359], + [3073, 3239], + [3106, 3270], + [3139, 3238], + [3156, 3166], + [3156, 3101], + [3106, 3069], + [3095, 3021], + [3060, 3025], + [3100, 2967], + [3058, 2920], + [3115, 2933], + [3138, 2891], + [3168, 2877], + [3217, 2892], + [3207, 2847], + [3143, 2821], + [3192, 2691], + [3239, 2686], + [3176, 2615], + [3191, 2615], + [3191, 2600], + [3240, 2590], + [3189, 2544], + [3161, 2570], + [3112, 2769], + [3087, 2798], + [3045, 2878], + [3028, 2890], + [2992, 3118], + [2905, 3266], + [2880, 3271], + [2860, 3342], + [2820, 3348], + [2800, 3419], + [2775, 3424], + [2756, 3495], + [2731, 3501], + [2711, 3572], + [2686, 3577], + [2642, 3729], + [2612, 3730], + [2628, 3805], + [2628, 3821], + [2579, 3968], + [2554, 3973], + [2554, 4004], + [2524, 4004], + [2534, 4029], + [2479, 4050], + [2470, 4075], + [2457, 4111], + [2442, 4117], + [2419, 4126], + [2414, 4197], + [2390, 4218], + [2388, 4224], + [-128, 4224], + [-128, -128], + [-128, -128], + [4224, -128], + [4224, -128], + [4224, 3063], + [4156, 3260], + [4172, 3284], + [4147, 3288], + [4125, 3375], + [4092, 3462], + [4080, 3524], + [3983, 3692], + [3965, 3786], + [3984, 3816], + [3943, 3891], + [3973, 3902], + [3978, 3917], + [3976, 3929], + [3964, 3953], + [3957, 3968], + [3941, 3983], + [3925, 4009], + [3923, 4024], + [3924, 4033], + [3922, 4046], + [3920, 4055], + [3911, 4075], + [3911, 4075] + ], + [ + [3364, 4097], + [3383, 4108], + [3398, 4124], + [3406, 4144], + [3413, 4155], + [3426, 4156], + [3442, 4162], + [3446, 4176], + [3465, 4185], + [3488, 4189], + [3502, 4192], + [3517, 4205], + [3520, 4224], + [3549, 4224], + [3557, 4208], + [3540, 4198], + [3528, 4191], + [3523, 4183], + [3510, 4184], + [3498, 4178], + [3485, 4184], + [3479, 4173], + [3480, 4136], + [3489, 4120], + [3475, 4116], + [3460, 4105], + [3471, 4103], + [3469, 4083], + [3444, 4074], + [3444, 4056], + [3455, 4070], + [3470, 4074], + [3478, 4083], + [3488, 4079], + [3477, 4089], + [3483, 4100], + [3475, 4107], + [3483, 4113], + [3506, 4102], + [3502, 4092], + [3527, 4107], + [3513, 4106], + [3512, 4117], + [3504, 4125], + [3490, 4136], + [3487, 4146], + [3486, 4172], + [3501, 4173], + [3510, 4178], + [3523, 4177], + [3532, 4185], + [3568, 4199], + [3582, 4198], + [3600, 4183], + [3579, 4144], + [3580, 4123], + [3586, 4114], + [3586, 4104], + [3594, 4099], + [3573, 4090], + [3581, 4103], + [3578, 4114], + [3565, 4110], + [3565, 4101], + [3562, 4092], + [3542, 4081], + [3540, 4067], + [3553, 4052], + [3538, 4041], + [3529, 4040], + [3532, 4027], + [3538, 4019], + [3551, 4018], + [3565, 4011], + [3567, 3999], + [3576, 3996], + [3595, 3992], + [3588, 3958], + [3573, 3922], + [3578, 3885], + [3559, 3878], + [3553, 3866], + [3558, 3790], + [3529, 3795], + [3468, 3809], + [3395, 3836], + [3247, 3891], + [3246, 3922], + [3246, 3948], + [3274, 3976], + [3335, 3983], + [3387, 3980], + [3383, 4036], + [3387, 4052], + [3364, 4097], + [3364, 4097] + ], + [ + [2976, 2176], + [2953, 2237], + [2969, 2285], + [3011, 2301], + [3046, 2297], + [3091, 2255], + [3133, 2276], + [3155, 2245], + [3145, 2194], + [3171, 2157], + [3148, 2085], + [3109, 2097], + [3096, 2079], + [3073, 2080], + [3056, 2136], + [3008, 2171], + [3032, 2134], + [3042, 2085], + [3064, 2068], + [3067, 2028], + [3099, 1984], + [3126, 1980], + [3146, 1951], + [3158, 1893], + [3207, 1857], + [3240, 1826], + [3321, 1842], + [3238, 1848], + [3213, 1885], + [3177, 1917], + [3163, 1968], + [3138, 2017], + [3180, 2004], + [3206, 1958], + [3272, 1951], + [3346, 1944], + [3360, 1988], + [3402, 2001], + [3437, 2053], + [3460, 2054], + [3468, 2089], + [3455, 2140], + [3425, 2187], + [3486, 2135], + [3505, 2080], + [3506, 2038], + [3516, 1985], + [3559, 1955], + [3556, 1887], + [3548, 1857], + [3520, 1881], + [3482, 1895], + [3473, 1860], + [3448, 1842], + [3449, 1791], + [3480, 1773], + [3532, 1750], + [3510, 1789], + [3463, 1808], + [3475, 1835], + [3509, 1874], + [3542, 1836], + [3579, 1847], + [3579, 1891], + [3580, 1936], + [3601, 1954], + [3630, 1924], + [3699, 1930], + [3720, 1966], + [3708, 1994], + [3695, 1943], + [3629, 1945], + [3611, 1975], + [3581, 1966], + [3556, 1993], + [3548, 2073], + [3517, 2148], + [3475, 2199], + [3486, 2254], + [3456, 2300], + [3410, 2293], + [3384, 2219], + [3346, 2189], + [3270, 2185], + [3214, 2148], + [3183, 2217], + [3231, 2271], + [3301, 2317], + [3296, 2369], + [3282, 2441], + [3230, 2488], + [3242, 2507], + [3233, 2539], + [3275, 2568], + [3272, 2646], + [3301, 2638], + [3312, 2583], + [3359, 2662], + [3350, 2602], + [3374, 2555], + [3413, 2549], + [3444, 2550], + [3459, 2526], + [3481, 2534], + [3464, 2556], + [3506, 2588], + [3536, 2535], + [3555, 2549], + [3518, 2625], + [3491, 2600], + [3463, 2623], + [3451, 2583], + [3398, 2637], + [3437, 2690], + [3378, 2678], + [3354, 2693], + [3301, 2701], + [3301, 2767], + [3266, 2712], + [3235, 2713], + [3195, 2731], + [3203, 2761], + [3224, 2792], + [3291, 2804], + [3341, 2802], + [3357, 2780], + [3363, 2753], + [3388, 2724], + [3415, 2726], + [3445, 2736], + [3460, 2779], + [3516, 2736], + [3537, 2741], + [3579, 2749], + [3608, 2715], + [3645, 2709], + [3659, 2727], + [3691, 2712], + [3734, 2691], + [3745, 2648], + [3731, 2635], + [3687, 2679], + [3654, 2685], + [3633, 2662], + [3598, 2658], + [3584, 2630], + [3596, 2597], + [3594, 2557], + [3613, 2518], + [3640, 2517], + [3636, 2486], + [3658, 2444], + [3647, 2409], + [3686, 2446], + [3652, 2488], + [3651, 2525], + [3626, 2560], + [3655, 2597], + [3630, 2629], + [3667, 2669], + [3727, 2616], + [3758, 2623], + [3817, 2628], + [3823, 2593], + [3791, 2551], + [3753, 2515], + [3754, 2484], + [3775, 2484], + [3795, 2454], + [3831, 2471], + [3893, 2485], + [3927, 2485], + [3953, 2458], + [3998, 2422], + [4046, 2383], + [4022, 2355], + [4020, 2296], + [3946, 2285], + [3902, 2357], + [3920, 2295], + [3894, 2249], + [3839, 2250], + [3898, 2235], + [3927, 2187], + [3916, 2149], + [3887, 2161], + [3822, 2135], + [3883, 2132], + [3922, 2040], + [3909, 2109], + [3937, 2104], + [3949, 2152], + [3998, 2135], + [4080, 2138], + [4119, 2083], + [4101, 2020], + [4106, 1978], + [4164, 1986], + [4163, 1952], + [4203, 1992], + [4210, 2013], + [4200, 2031], + [4224, 2021], + [4224, 1949], + [4216, 1915], + [4199, 1891], + [4199, 1876], + [4183, 1816], + [4097, 1796], + [4059, 1748], + [4030, 1713], + [3989, 1696], + [3955, 1681], + [3926, 1657], + [3869, 1646], + [3824, 1612], + [3788, 1591], + [3561, 1609], + [3546, 1624], + [3515, 1624], + [3510, 1649], + [3350, 1732], + [3335, 1732], + [3274, 1748], + [3259, 1763], + [3108, 1795], + [3049, 1887], + [3015, 2080], + [2976, 2176], + [2976, 2176] + ], + [ + [3183, -128], + [3192, -118], + [3253, -36], + [3313, 26], + [3357, 31], + [3406, 103], + [3514, 134], + [3541, 271], + [3547, 344], + [3664, 311], + [3669, 216], + [3565, 168], + [3662, 150], + [3655, 88], + [3528, 39], + [3581, 26], + [3608, -21], + [3675, -87], + [3637, -128], + [3183, -128] + ], + [ + [3205, -15], + [3114, -30], + [3065, -59], + [3017, -29], + [3047, 7], + [3013, 118], + [2971, 183], + [2978, 281], + [3026, 305], + [3081, 298], + [3107, 369], + [3157, 360], + [3191, 397], + [3312, 393], + [3350, 371], + [3363, 294], + [3419, 236], + [3334, 298], + [3306, 338], + [3305, 290], + [3261, 235], + [3253, 140], + [3254, 86], + [3335, 51], + [3273, 34], + [3227, 26], + [3199, 49], + [3232, 96], + [3223, 166], + [3224, 247], + [3242, 268], + [3224, 281], + [3202, 244], + [3173, 266], + [3187, 328], + [3158, 328], + [3136, 258], + [3184, 231], + [3177, 169], + [3149, 144], + [3133, 188], + [3078, 155], + [3058, 183], + [3102, 221], + [3074, 236], + [3048, 198], + [3011, 180], + [3043, 144], + [3111, 74], + [3120, 37], + [3098, 19], + [3100, -1], + [3201, 8], + [3205, -15], + [3205, -15] + ], + [ + [4224, 2296], + [4180, 2330], + [4198, 2362], + [4203, 2411], + [4224, 2415], + [4224, 2482], + [4212, 2474], + [4198, 2509], + [4197, 2541], + [4177, 2531], + [4124, 2533], + [4101, 2514], + [4023, 2555], + [4029, 2506], + [4055, 2468], + [4029, 2422], + [3955, 2489], + [3928, 2532], + [3913, 2515], + [3857, 2512], + [3804, 2481], + [3789, 2511], + [3844, 2590], + [3830, 2643], + [3767, 2641], + [3761, 2730], + [3704, 2728], + [3675, 2737], + [3670, 2764], + [3651, 2765], + [3651, 2741], + [3626, 2729], + [3607, 2761], + [3552, 2763], + [3551, 2781], + [3513, 2781], + [3505, 2817], + [3477, 2800], + [3459, 2831], + [3422, 2852], + [3420, 2901], + [3399, 2855], + [3428, 2807], + [3428, 2770], + [3402, 2751], + [3378, 2764], + [3400, 2817], + [3363, 2833], + [3319, 2849], + [3299, 2895], + [3313, 2925], + [3283, 2942], + [3286, 2853], + [3237, 2904], + [3230, 2941], + [3254, 2952], + [3267, 2985], + [3302, 3016], + [3346, 2995], + [3379, 3004], + [3384, 3070], + [3416, 3072], + [3456, 3069], + [3459, 3042], + [3478, 2986], + [3481, 3022], + [3496, 3023], + [3512, 3072], + [3486, 3080], + [3488, 3150], + [3508, 3174], + [3535, 3195], + [3553, 3174], + [3571, 3206], + [3605, 3179], + [3639, 3213], + [3701, 3204], + [3881, 3256], + [3964, 3239], + [4113, 3273], + [4168, 3133], + [4224, 2979], + [4224, 2296] + ] +] diff --git a/packages/melonjs/tests/earcut/test.spec.ts b/packages/melonjs/tests/earcut/test.spec.ts new file mode 100644 index 000000000..375f1be70 --- /dev/null +++ b/packages/melonjs/tests/earcut/test.spec.ts @@ -0,0 +1,59 @@ +import { expect, test } from "vitest"; +import { deviation, flatten } from "./utils"; +import expected from "./expected.json"; +import { server } from "@vitest/browser/context"; +import { earcut } from "../../src/geometries/earcut"; + +const { readFile } = server.commands; + +test("indices-2d", () => { + const indices = earcut([10, 0, 0, 50, 60, 60, 70, 10]); + expect(indices).toStrictEqual([1, 0, 3, 3, 2, 1]); +}); + +test("indices-3d", () => { + const indices = earcut([10, 0, 0, 0, 50, 0, 60, 60, 0, 70, 10, 0], null, 3); + expect(indices).toStrictEqual([1, 0, 3, 3, 2, 1]); +}); + +test("empty", () => { + expect(earcut([])).toStrictEqual([]); +}); + +const keys = Object.keys( + expected.triangles, +) as (keyof typeof expected.triangles)[]; + +const isExpectedError = ( + prop: string, +): prop is keyof typeof expected.errors => { + return prop in expected.errors; +}; + +for (const id of keys) { + test(id, async () => { + const json = await readFile(`./fixtures/${id}.json`); + const data = flatten(JSON.parse(json) as number[][][]), + indices = earcut(data.vertices, data.holes, data.dimensions), + err = deviation(data.vertices, data.holes, data.dimensions, indices), + expectedTriangles = expected.triangles[id], + expectedDeviation = isExpectedError(id) ? expected.errors[id] : 0; + + const numTriangles = indices.length / 3; + expect( + numTriangles, + `${numTriangles} triangles when expected ${expectedTriangles}`, + ).toBe(expectedTriangles); + + if (expectedTriangles > 0) { + expect( + err, + `deviation ${err} <= ${expectedDeviation}`, + ).toBeLessThanOrEqual(expectedDeviation); + } + }); +} + +test("infinite-loop", () => { + earcut([1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 4, 1, 5, 1, 3, 2, 4, 2, 4, 1], [5], 2); +}); diff --git a/packages/melonjs/tests/earcut/utils.ts b/packages/melonjs/tests/earcut/utils.ts new file mode 100644 index 000000000..df5868634 --- /dev/null +++ b/packages/melonjs/tests/earcut/utils.ts @@ -0,0 +1,59 @@ +/* eslint-disable jsdoc/require-jsdoc */ +// return a percentage difference between the polygon area and its triangulation area; + +import { signedArea } from "../../src/geometries/earcut"; + +// used to verify correctness of triangulation +export function deviation( + data: number[], + holeIndices: number[] | null | undefined, + dim: number, + triangles: number[], +) { + const hasHoles = holeIndices && holeIndices.length; + const outerLen = hasHoles ? holeIndices[0] * dim : data.length; + + let polygonArea = Math.abs(signedArea(data, 0, outerLen, dim)); + if (hasHoles) { + for (let i = 0, len = holeIndices.length; i < len; i++) { + const start = holeIndices[i] * dim; + const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; + polygonArea -= Math.abs(signedArea(data, start, end, dim)); + } + } + + let trianglesArea = 0; + for (let i = 0; i < triangles.length; i += 3) { + const a = triangles[i] * dim; + const b = triangles[i + 1] * dim; + const c = triangles[i + 2] * dim; + trianglesArea += Math.abs( + (data[a] - data[c]) * (data[b + 1] - data[a + 1]) - + (data[a] - data[b]) * (data[c + 1] - data[a + 1]), + ); + } + + return polygonArea === 0 && trianglesArea === 0 + ? 0 + : Math.abs((trianglesArea - polygonArea) / polygonArea); +} + +export function flatten(data: number[][][]) { + const vertices = []; + const holes = []; + const dimensions = data[0][0].length; + let holeIndex = 0; + let prevLen = 0; + + for (const ring of data) { + for (const p of ring) { + for (let d = 0; d < dimensions; d++) vertices.push(p[d]); + } + if (prevLen) { + holeIndex += prevLen; + holes.push(holeIndex); + } + prevLen = ring.length; + } + return { vertices, holes, dimensions }; +} diff --git a/packages/melonjs/tests/mat2d.spec.js b/packages/melonjs/tests/mat2d.spec.ts similarity index 86% rename from packages/melonjs/tests/mat2d.spec.js rename to packages/melonjs/tests/mat2d.spec.ts index f0eba9f41..f55b7dfd4 100644 --- a/packages/melonjs/tests/mat2d.spec.js +++ b/packages/melonjs/tests/mat2d.spec.ts @@ -4,7 +4,7 @@ import { Matrix2d, Matrix3d, Vector2d } from "../src/index.js"; describe("Matrix2d", () => { it("should be initialized to a 3x3 identity matrix", () => { const matA = new Matrix2d(); - const result = "me.Matrix2d(1, 0, 0, 0, 1, 0, 0, 0, 1)"; + const result = "Matrix2d(1, 0, 0, 0, 1, 0, 0, 0, 1)"; expect(matA.toString() === result).toEqual(true); }); @@ -34,7 +34,7 @@ describe("Matrix2d", () => { 15, 16, ); - const result = "me.Matrix2d(1, 2, 3, 5, 6, 7, 9, 10, 11)"; + const result = "Matrix2d(1, 2, 3, 5, 6, 7, 9, 10, 11)"; matA.fromMat3d(matB); @@ -44,7 +44,7 @@ describe("Matrix2d", () => { it("should multiply all values properly", () => { const matA = new Matrix2d(1, 2, 0, 3, 4, 0, 5, 6, 1); const matB = new Matrix2d(7, 8, 0, 9, 10, 0, 11, 12, 1); - const result = "me.Matrix2d(31, 46, 0, 39, 58, 0, 52, 76, 1)"; + const result = "Matrix2d(31, 46, 0, 39, 58, 0, 52, 76, 1)"; matA.multiply(matB); @@ -61,7 +61,7 @@ describe("Matrix2d", () => { it("should rotate all values properly", () => { const matA = new Matrix2d(1, 2, 0, 3, 4, 0, 5, 6, 1); - const result = "me.Matrix2d(3, 4, 0, -1, -2, 0, 5, 6, 1)"; + const result = "Matrix2d(3, 4, 0, -1, -2, 0, 5, 6, 1)"; matA.rotate(Math.PI * 0.5); @@ -70,7 +70,7 @@ describe("Matrix2d", () => { it("should scale all values properly", () => { const matA = new Matrix2d().setTransform(1, 2, 0, 3, 4, 0, 5, 6, 1); - const result = "me.Matrix2d(2, 4, 0, 9, 12, 0, 5, 6, 1)"; + const result = "Matrix2d(2, 4, 0, 9, 12, 0, 5, 6, 1)"; matA.scale(2, 3); @@ -79,7 +79,7 @@ describe("Matrix2d", () => { it("should translate all values properly", () => { const matA = new Matrix2d(1, 2, 0, 3, 4, 0, 5, 6, 1); - const result = "me.Matrix2d(1, 2, 0, 3, 4, 0, 16, 22, 1)"; + const result = "Matrix2d(1, 2, 0, 3, 4, 0, 16, 22, 1)"; matA.translate(2, 3); @@ -90,7 +90,7 @@ describe("Matrix2d", () => { it("should transpose the matrix properly", () => { const matA = new Matrix2d(1, 2, 3, 4, 5, 6, 7, 8, 9); - const result = "me.Matrix2d(1, 4, 7, 2, 5, 8, 3, 6, 9)"; + const result = "Matrix2d(1, 4, 7, 2, 5, 8, 3, 6, 9)"; matA.transpose(); @@ -99,7 +99,7 @@ describe("Matrix2d", () => { it("should invert the matrix properly", () => { const matA = new Matrix2d(4, 2, 3, 3, 1, 3, 2, -1, 4); - const result = "me.Matrix2d(7, -11, 3, -6, 10, -3, -5, 8, -2)"; + const result = "Matrix2d(7, -11, 3, -6, 10, -3, -5, 8, -2)"; matA.invert(); diff --git a/packages/melonjs/tests/mat3d.spec.js b/packages/melonjs/tests/mat3d.spec.ts similarity index 86% rename from packages/melonjs/tests/mat3d.spec.js rename to packages/melonjs/tests/mat3d.spec.ts index 0f381e6f7..4ffbf1377 100644 --- a/packages/melonjs/tests/mat3d.spec.js +++ b/packages/melonjs/tests/mat3d.spec.ts @@ -4,8 +4,7 @@ import { Matrix3d, Vector2d, Vector3d } from "../src/index.js"; describe("Matrix3d", () => { it("should be initialized to a 4x4 identity matrix", () => { const matA = new Matrix3d(); - const result = - "me.Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)"; + const result = "Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)"; expect(matA.toString() === result).toEqual(true); }); @@ -30,7 +29,7 @@ describe("Matrix3d", () => { 15, ); const result = - "me.Matrix3d(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)"; + "Matrix3d(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)"; expect(matA.toString() === result).toEqual(true); }); @@ -38,8 +37,7 @@ describe("Matrix3d", () => { it("should multiply all values properly", () => { const matA = new Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1); const matB = new Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4, 5, 6, 1); - const result = - "me.Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5, 7, 9, 1)"; + const result = "Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5, 7, 9, 1)"; matA.multiply(matB); @@ -56,7 +54,24 @@ describe("Matrix3d", () => { }); it("should reset to an identity matrix", () => { - const matA = new Matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9); + const matA = new Matrix3d( + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + ); matA.identity(); @@ -110,8 +125,7 @@ describe("Matrix3d", () => { 3, 1, ); - const result = - "me.Matrix3d(4, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 0, 1, 2, 3, 1)"; + const result = "Matrix3d(4, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 0, 1, 2, 3, 1)"; matA.scale(4, 5, 6); @@ -120,8 +134,7 @@ describe("Matrix3d", () => { it("should translate all values properly", () => { const matA = new Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1); - const result = - "me.Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 4, 6, 1)"; + const result = "Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 4, 6, 1)"; matA.translate(1, 2, 3); @@ -133,8 +146,7 @@ describe("Matrix3d", () => { it("a 2d vector should translate all values properly", () => { const matA = new Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1); - const result = - "me.Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 4, 3, 1)"; + const result = "Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 4, 3, 1)"; const vecA = new Vector2d(1, 2); matA.translate(vecA); @@ -147,8 +159,7 @@ describe("Matrix3d", () => { it("should transpose the matrix properly", () => { const matA = new Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1); - const result = - "me.Matrix3d(1, 0, 0, 1, 0, 1, 0, 2, 0, 0, 1, 3, 0, 0, 0, 1)"; + const result = "Matrix3d(1, 0, 0, 1, 0, 1, 0, 2, 0, 0, 1, 3, 0, 0, 0, 1)"; matA.transpose(); @@ -158,7 +169,7 @@ describe("Matrix3d", () => { it("should invert the matrix properly", () => { const matA = new Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1); const result = - "me.Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1, -2, -3, 1)"; + "Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1, -2, -3, 1)"; matA.invert(); @@ -180,11 +191,9 @@ describe("Matrix3d", () => { it("should multiply a 3d vector properly with the inverted matrix", () => { const matA = new Matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1); const vecA = new Vector3d(3, 7, 1); - matA.apply(vecA); // multiply back with the inverted matrix matA.applyInverse(vecA); - // and we should have back the original vector values expect(vecA.toString()).toEqual("x:3,y:7,z:1"); }); diff --git a/packages/melonjs/tests/observableVect2d.spec.js b/packages/melonjs/tests/observableVect2d.spec.js deleted file mode 100644 index a0c54ed04..000000000 --- a/packages/melonjs/tests/observableVect2d.spec.js +++ /dev/null @@ -1,227 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { ObservableVector2d, Vector2d, math } from "../src/index.js"; - -describe("ObservableVector2d", () => { - const x = 1; - const y = 2; - - let a; - let b; - let c; - - let _newX; - let _newY; - let _oldX; - let _oldY; - - const callback = function (newX, newY, oldX, oldY) { - // this will also validate the argument list - _newX = newX; - _newY = newY; - _oldX = oldX; - _oldY = oldY; - }; - - const callback_with_ret = function () { - return { - x: 10, - y: 10, - }; - }; - - it("should be initialized to a (0, 0) 2d vector", function () { - a = new ObservableVector2d(0, 0, { - onUpdate: callback.bind(this), - }); - b = new ObservableVector2d(0, 0, { - onUpdate: callback.bind(this), - }); - c = new ObservableVector2d(0, 0, { - onUpdate: callback.bind(this), - }); - - expect(a.toString()).toEqual("x:0,y:0"); - }); - - it("setting the vector triggers the callback", () => { - a.set(10, 100); - expect(a.x + a.y).toEqual(_newX + _newY); - }); - - it("callback returns a vector value", function () { - const d = new ObservableVector2d(0, 0, { - onUpdate: callback_with_ret.bind(this), - }); - d.set(100, 100); - expect(d.x + d.y).toEqual(20); // 10 + 10 - }); - - it("add a vector triggers the callback", () => { - a.add(new Vector2d(10, 10)); - expect(a.y).toEqual(_oldY + 10); - }); - - it("sub a vector triggers the callback", () => { - a.sub(new Vector2d(10, 10)); - expect(a.x).toEqual(_oldX - 10); - }); - - it("a(1, 2) should be copied into b", () => { - a.set(x, y); - b.copy(a); - - expect(b.equals(a)).toEqual(true); - }); - - it("scale (1, 2) by (-1, -2)", () => { - a.set(x, y); - b.set(-x, -y); - - expect(a.scaleV(b).toString()).toEqual("x:" + x * -x + ",y:" + y * -y); - }); - - it("negate (1, 2)", () => { - a.set(x, y); - - expect(a.negateSelf().toString()).toEqual("x:" + -x + ",y:" + -y); - }); - - it("dot Product (1, 2) and (-1, -2)", () => { - a.set(x, y); - b.set(-x, -y); - - // calculate the dot product - expect(a.dot(b)).toEqual(-x * x - y * y); - }); - - it("cross Product (2, 3) and (5, 6)", () => { - a.set(2, 3); - b.set(5, 6); - - // calculate the cross product - expect(a.cross(b)).toEqual(-3); - }); - - it("length/lengthSqrt functions", () => { - a.set(x, 0); - b.set(0, -y); - c.set(0, 0); - - expect(a.length()).toEqual(x); - expect(a.length2()).toEqual(x * x); - expect(b.length()).toEqual(y); - expect(b.length2()).toEqual(y * y); - expect(c.length()).toEqual(0); - expect(c.length2()).toEqual(0); - - a.set(x, y); - expect(a.length()).toEqual(Math.sqrt(x * x + y * y)); - expect(a.length2()).toEqual(x * x + y * y); - }); - - it("lerp functions", () => { - a.set(x, 0); - b.set(0, -y); - - expect(a.clone().lerp(a, 0).equals(a.lerp(a, 0.5))).toEqual(true); - expect(a.clone().lerp(a, 0).equals(a.lerp(a, 1))).toEqual(true); - - expect(a.clone().lerp(b, 0).equals(a)).toEqual(true); - - expect(a.clone().lerp(b, 0.5).x).toEqual(x * 0.5); - expect(a.clone().lerp(b, 0.5).y).toEqual(-y * 0.5); - - expect(a.clone().lerp(b, 1).equals(b)).toEqual(true); - }); - - it("normalize function", () => { - a.set(x, 0); - b.set(0, -y); - - a.normalize(); - expect(a.length()).toEqual(1); - expect(a.x).toEqual(1); - - b.normalize(); - expect(b.length()).toEqual(1); - expect(b.y).toEqual(-1); - }); - - it("distance function", () => { - a.set(x, 0); - b.set(0, -y); - c.set(0, 0); - - expect(a.distance(c)).toEqual(x); - expect(b.distance(c)).toEqual(y); - }); - - it("min/max/clamp", () => { - a.set(x, y); - b.set(-x, -y); - c.set(0, 0); - - c.copy(a).minV(b); - expect(c.x).toEqual(-x); - expect(c.y).toEqual(-y); - - c.copy(a).maxV(b); - expect(c.x).toEqual(x); - expect(c.y).toEqual(y); - - c.set(-2 * x, 2 * x); - c.clampSelf(-x, x); - expect(c.x).toEqual(-x); - expect(c.y).toEqual(x); - }); - - it("ceil/floor", () => { - expect( - a.setMuted(-0.1, 0.1).floorSelf().equals(new Vector2d(-1, 0)), - ).toEqual(true); - expect( - b.setMuted(-0.5, 0.5).floorSelf().equals(new Vector2d(-1, 0)), - ).toEqual(true); - expect( - c.setMuted(-0.9, 0.9).floorSelf().equals(new Vector2d(-1, 0)), - ).toEqual(true); - - expect(a.setMuted(-0.1, 0.1).ceilSelf().equals(new Vector2d(0, 1))).toEqual( - true, - ); - expect(b.setMuted(-0.5, 0.5).ceilSelf().equals(new Vector2d(0, 1))).toEqual( - true, - ); - expect(c.setMuted(-0.9, 0.9).ceilSelf().equals(new Vector2d(0, 1))).toEqual( - true, - ); - }); - - it("project a on b", () => { - a.set(x, y); - b.set(-x, -y); - - // the following only works with (-)1, (-)2style of values - expect(a.project(b).equals(b)).toEqual(true); - }); - - it("angle between a and b", () => { - a.set(x, y); - b.set(-x, -y); - - // why is this not perfectly 180 degrees ? - expect(Math.round(math.radToDeg(a.angle(b)))).toEqual(180); - - b.set(4 * x, -y); - expect(a.angle(b)).toEqual(Math.PI / 2); - }); - - it("perp and rotate function", () => { - a.set(x, y); - b.copy(a).perp(); - // perp rotate the vector by 90 degree clockwise on the z axis - c.copy(a).rotate(Math.PI / 2); - - expect(a.angle(b)).toEqual(a.angle(c)); - }); -}); diff --git a/packages/melonjs/tests/observableVect3d.spec.js b/packages/melonjs/tests/observableVect3d.spec.js deleted file mode 100644 index 271a29d39..000000000 --- a/packages/melonjs/tests/observableVect3d.spec.js +++ /dev/null @@ -1,281 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { ObservableVector3d, Vector3d, math } from "../src/index.js"; - -describe("ObservableVector3d", () => { - const x = 1; - const y = 2; - const z = 3; - - let a; - let b; - let c; - let d; - - let _newX; - let _newY; - let _newZ; - let _oldX; - let _oldY; - let _oldZ; - - const callback = function (newX, newY, newZ, oldX, oldY, oldZ) { - // this will also validate the argument list - _newX = newX; - _newY = newY; - _newZ = newZ; - _oldX = oldX; - _oldY = oldY; - _oldZ = oldZ; - }; - - const callback_with_ret = function () { - return { - x: 10, - y: 10, - z: 10, - }; - }; - - it("should be initialized to a (0, 0, 0) 3d vector", function () { - a = new ObservableVector3d(0, 0, 0, { - onUpdate: callback.bind(this), - }); - b = new ObservableVector3d(x, 0, 0, { - onUpdate: callback.bind(this), - }); - c = new ObservableVector3d(x, y, 0, { - onUpdate: callback.bind(this), - }); - - d = new ObservableVector3d(x, y, z, { - onUpdate: callback.bind(this), - }); - - expect(a.toString()).toEqual("x:0,y:0,z:0"); - }); - - it("setting the vector triggers the callback", () => { - a.set(10, 100, 20); - - expect(a.x + a.y + a.z).toEqual(_newX + _newY + _newZ); - }); - - it("callback returns a vector value", function () { - const d = new ObservableVector3d(0, 0, 0, { - onUpdate: callback_with_ret.bind(this), - }); - d.set(100, 100, 100); - expect(d.x + d.y + d.z).toEqual(30); // 10 + 10 + 10 - }); - - it("add a vector triggers the callback", () => { - a.add(new Vector3d(10, 10, 10)); - - expect(a.y).toEqual(_oldY + 10); - }); - - it("sub a vector triggers the callback", () => { - a.sub(new Vector3d(10, 10, 10)); - - expect(a.x).toEqual(_oldX - 10); - }); - - it("scale a vector triggers the callback", () => { - a.scaleV(new Vector3d(10, 10, 10)); - - expect(a.x).toEqual(_oldX * 10); - expect(a.y).toEqual(_oldY * 10); - expect(a.z).toEqual(_oldZ * 10); - }); - - it("negate (1, 2, 3)", () => { - a.set(x, y, z); - - expect(a.negateSelf().toString()).toEqual( - "x:" + -x + ",y:" + -y + ",z:" + -z, - ); - }); - - it("dot Product (1, 2, 3) and (-1, -2, -3)", () => { - a.set(x, y, z); - b.set(-x, -y, -z); - - // calculate the dot product - expect(a.dot(b)).toEqual(-x * x - y * y - z * z); - }); - - it("cross Product (2, 3, 4) and (5, 6, 7)", () => { - a.set(2, 3, 4); - b.set(5, 6, 7); - - const crossed = new Vector3d(-3, 6, -3); - - // calculate the cross product - a.cross(b); - expect(Math.abs(a.x - crossed.x)).toBeCloseTo(0, 4); - expect(Math.abs(a.y - crossed.y)).toBeCloseTo(0, 4); - expect(Math.abs(a.z - crossed.z)).toBeCloseTo(0, 4); - }); - - it("length/lengthSqrt functions", () => { - a.set(x, 0, 0); - b.set(0, -y, 0); - c.set(0, 0, z); - d.set(0, 0, 0); - - expect(a.length()).toEqual(x); - expect(a.length2()).toEqual(x * x); - expect(b.length()).toEqual(y); - expect(b.length2()).toEqual(y * y); - expect(c.length()).toEqual(z); - expect(c.length2()).toEqual(z * z); - expect(d.length()).toEqual(0); - expect(d.length2()).toEqual(0); - - a.set(x, y, z); - - expect(a.length()).toEqual(Math.sqrt(x * x + y * y + z * z)); - expect(a.length2()).toEqual(x * x + y * y + z * z); - }); - - it("lerp functions", () => { - a.set(x, 0, z); - b.set(0, -y, 0); - - expect(a.clone().lerp(a, 0).equals(a.lerp(a, 0.5))).toEqual(true); - expect(a.clone().lerp(a, 0).equals(a.lerp(a, 1))).toEqual(true); - - expect(a.clone().lerp(b, 0).equals(a)).toEqual(true); - - expect(a.clone().lerp(b, 0.5).x).toEqual(x * 0.5); - expect(a.clone().lerp(b, 0.5).y).toEqual(-y * 0.5); - expect(a.clone().lerp(b, 0.5).z).toEqual(z * 0.5); - - expect(a.clone().lerp(b, 1).equals(b)).toEqual(true); - }); - - it("normalize function", () => { - a.set(x, 0, 0); - b.set(0, -y, 0); - c.set(0, 0, z); - - a.normalize(); - expect(a.length()).toEqual(1); - expect(a.x).toEqual(1); - - b.normalize(); - expect(b.length()).toEqual(1); - expect(b.y).toEqual(-1); - - c.normalize(); - expect(c.length()).toEqual(1); - expect(c.z).toEqual(1); - }); - - it("distance function", () => { - a.set(x, 0, 0); - b.set(0, -y, 0); - c.set(0, 0, z); - d.set(0, 0, 0); - - expect(a.distance(d)).toEqual(x); - expect(b.distance(d)).toEqual(y); - expect(c.distance(d)).toEqual(z); - }); - - it("min/max/clamp", () => { - a.set(x, y, z); - b.set(-x, -y, -z); - c.set(0, 0, 0); - - c.copy(a).minV(b); - expect(c.x).toEqual(-x); - expect(c.y).toEqual(-y); - expect(c.z).toEqual(-z); - - c.copy(a).maxV(b); - expect(c.x).toEqual(x); - expect(c.y).toEqual(y); - expect(c.z).toEqual(z); - - c.set(-2 * x, 2 * x, 2 * z); - c.clampSelf(-x, x); - expect(c.x).toEqual(-x); - expect(c.y).toEqual(x); - expect(c.z).toEqual(x); - }); - - it("ceil/floor", () => { - expect( - a - .set(-0.1, 0.1, 0.3) - .floorSelf() - .equals(new Vector3d(-1, 0, 0)), - ).toEqual(true); - expect( - a - .set(-0.5, 0.5, 0.6) - .floorSelf() - .equals(new Vector3d(-1, 0, 0)), - ).toEqual(true); - expect( - a - .set(-0.9, 0.9, 0.8) - .floorSelf() - .equals(new Vector3d(-1, 0, 0)), - ).toEqual(true); - - expect( - a - .set(-0.1, 0.1, 0.3) - .ceilSelf() - .equals(new Vector3d(0, 1, 1)), - ).toEqual(true); - expect( - a - .set(-0.5, 0.5, 0.6) - .ceilSelf() - .equals(new Vector3d(0, 1, 1)), - ).toEqual(true); - expect( - a - .set(-0.9, 0.9, 0.9) - .ceilSelf() - .equals(new Vector3d(0, 1, 1)), - ).toEqual(true); - }); - - it("project a on b", () => { - a.set(x, y, z); - b.set(-x, -y, -z); - - // the following only works with (-)1, (-)2, (-)3 style of values - expect(a.project(b).equals(b)).toEqual(true); - }); - - it("angle between a and b", () => { - a.set(0, -0.18851655680720186, 0.9820700116639124); - b.set(0, 0.18851655680720186, -0.9820700116639124); - - expect(a.angle(a)).toEqual(0); - expect(a.angle(b)).toEqual(Math.PI); - - a.set(x, y, 0); - b.set(-x, -y, 0); - - // why is this not perfectly 180 degrees ? - expect(math.round(math.radToDeg(a.angle(b)))).toEqual(180); - - b.set(4 * x, -y, 0); - expect(a.angle(b)).toEqual(Math.PI / 2); - }); - - it("perp and rotate function", () => { - a.set(x, y, z); - b.copy(a).perp(); - // perp rotate the vector by 90 degree clockwise on the z axis - c.copy(a).rotate(Math.PI / 2); - - expect(a.angle(b)).toEqual(a.angle(c)); - }); -}); diff --git a/packages/melonjs/tests/vect2d.spec.js b/packages/melonjs/tests/vector2d.spec.ts similarity index 91% rename from packages/melonjs/tests/vect2d.spec.js rename to packages/melonjs/tests/vector2d.spec.ts index 325929b8e..211b56db9 100644 --- a/packages/melonjs/tests/vect2d.spec.js +++ b/packages/melonjs/tests/vector2d.spec.ts @@ -1,13 +1,14 @@ import { describe, expect, it } from "vitest"; -import { Vector2d, math } from "../src/index.js"; +import * as math from "../src/math/math.js"; +import { Vector2d } from "../src/math/vector2d.js"; describe("Vector2d", () => { const x = 1; const y = 2; - let a; - let b; - let c; + let a: Vector2d; + let b: Vector2d; + let c: Vector2d; it("should be initialized to a (0, 0) 2d vector", () => { a = new Vector2d(); @@ -28,7 +29,7 @@ describe("Vector2d", () => { it("set (1, 2) into a defined vector", () => { a.set(x, y); - expect(a.toString()).toEqual("x:" + x + ",y:" + y); + expect(a.toString()).toEqual(`x:${x},y:${y}`); }); it("add (1, 2) to (-1, -2)", () => { @@ -42,20 +43,20 @@ describe("Vector2d", () => { a.set(x, y); b.set(-x, -y); - expect(a.sub(b).toString()).toEqual("x:" + (x - -x) + ",y:" + (y - -y)); + expect(a.sub(b).toString()).toEqual(`x:${x - -x},y:${y - -y}`); }); it("scale (1, 2) by (-1, -2)", () => { a.set(x, y); b.set(-x, -y); - expect(a.scaleV(b).toString()).toEqual("x:" + x * -x + ",y:" + y * -y); + expect(a.scaleV(b).toString()).toEqual(`x:${x * -x},y:${y * -y}`); }); it("negate (1, 2)", () => { a.set(x, y); - expect(a.negateSelf().toString()).toEqual("x:" + -x + ",y:" + -y); + expect(a.negateSelf().toString()).toEqual(`x:${-x},y:${-y}`); }); it("dot Product (1, 2) and (-1, -2)", () => { @@ -95,7 +96,7 @@ describe("Vector2d", () => { a.set(x, 0); b.set(0, -y); - expect(a.clone().lerp(a, 0).equals(a.lerp(a, 0.5))).toEqual(true); + expect(a.clone().lerp(a, 0)).toEqual(a.lerp(a, 0.5)); expect(a.clone().lerp(a, 0).equals(a.lerp(a, 1))).toEqual(true); expect(a.clone().lerp(b, 0).equals(a)).toEqual(true); diff --git a/packages/melonjs/tests/vect3d.spec.js b/packages/melonjs/tests/vector3d.spec.ts similarity index 93% rename from packages/melonjs/tests/vect3d.spec.js rename to packages/melonjs/tests/vector3d.spec.ts index cfb5b4436..1494db973 100644 --- a/packages/melonjs/tests/vect3d.spec.js +++ b/packages/melonjs/tests/vector3d.spec.ts @@ -6,10 +6,10 @@ describe("Vector3d", () => { const y = 2; const z = 3; - let a; - let b; - let c; - let d; + let a: Vector3d; + let b: Vector3d; + let c: Vector3d; + let d: Vector3d; it("should be initialized to a (0, 0, 0) 3d vector", () => { a = new Vector3d(); @@ -34,16 +34,16 @@ describe("Vector3d", () => { it("set (1, 2, 3) into a defined vector", () => { a.set(x, y, z); - expect(a.toString()).toEqual("x:" + x + ",y:" + y + ",z:" + z); + expect(a.toString()).toEqual(`x:${x},y:${y},z:${z}`); }); it("use a 2d vector to set this vector", () => { const vec2 = new Vector2d(x, y); a.setV(vec2); - expect(a.toString()).toEqual("x:" + x + ",y:" + y + ",z:0"); + expect(a.toString()).toEqual(`x:${x},y:${y},z:0`); a.set(y, x); - expect(a.toString()).toEqual("x:" + y + ",y:" + x + ",z:0"); + expect(a.toString()).toEqual(`x:${y},y:${x},z:0`); }); it("add (1, 2, 3) to (-1, -2, -3)", () => { @@ -57,9 +57,7 @@ describe("Vector3d", () => { a.set(x, y, z); b.set(-x, -y, -z); - expect(a.sub(b).toString()).toEqual( - "x:" + (x - -x) + ",y:" + (y - -y) + ",z:" + (z - -z), - ); + expect(a.sub(b).toString()).toEqual(`x:${x - -x},y:${y - -y},z:${z - -z}`); }); it("scale (1, 2, 3) by (-1, -2, -3)", () => { @@ -67,7 +65,7 @@ describe("Vector3d", () => { b.set(-x, -y, -z); expect(a.scaleV(b).toString()).toEqual( - "x:" + x * -x + ",y:" + y * -y + ",z:" + z * -z, + `x:${x * -x},y:${y * -y},z:${z * -z}`, ); a.set(x, y, z); @@ -78,9 +76,7 @@ describe("Vector3d", () => { it("negate (1, 2, 3)", () => { a.set(x, y, z); - expect(a.negateSelf().toString()).toEqual( - "x:" + -x + ",y:" + -y + ",z:" + -z, - ); + expect(a.negateSelf().toString()).toEqual(`x:${-x},y:${-y},z:${-z}`); }); it("dot Product (1, 2, 3) and (-1, -2, -3)", () => { diff --git a/packages/melonjs/vitest.config.ts b/packages/melonjs/vitest.config.ts index 7d4ba2e4f..ed2c5bbca 100644 --- a/packages/melonjs/vitest.config.ts +++ b/packages/melonjs/vitest.config.ts @@ -21,6 +21,7 @@ export default defineConfig({ name: "chromium", provider: "playwright", headless: true, + screenshotFailures: false, }, }, publicDir: "./tests/public", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f048c899c..f72559508 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^20.14.10 version: 20.14.10 '@vitest/browser': - specifier: ^2.0.1 - version: 2.0.1(playwright@1.45.1)(typescript@5.5.3)(vitest@2.0.1) + specifier: ^2.0.2 + version: 2.0.2(playwright@1.45.1)(typescript@5.5.3)(vitest@2.0.2) eslint: specifier: ^9.6.0 version: 9.6.0 @@ -48,8 +48,8 @@ importers: specifier: ^8.0.0-alpha.41 version: 8.0.0-alpha.41(eslint@9.6.0)(typescript@5.5.3) vitest: - specifier: ^2.0.1 - version: 2.0.1(@types/node@20.14.10)(@vitest/browser@2.0.1) + specifier: ^2.0.2 + version: 2.0.2(@types/node@20.14.10)(@vitest/browser@2.0.2) packages/debug-plugin: devDependencies: @@ -673,10 +673,6 @@ packages: resolution: {integrity: sha512-AjOqykVyjdJQvtfkNDGUyMYGF8xN50VUxftCQWsOyIo4DFRLr6VQhW0VItGI1JIyQGCGgIpKa7hMMwNhZb4OIw==} engines: {node: '>=18'} - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -827,9 +823,6 @@ packages: '@shikijs/core@1.10.3': resolution: {integrity: sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==} - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - '@teppeis/multimaps@3.0.0': resolution: {integrity: sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q==} engines: {node: '>=14'} @@ -977,12 +970,12 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 - '@vitest/browser@2.0.1': - resolution: {integrity: sha512-5ceTJI+5yYYcCq2195TkQMNd5N3WHBnz4VSVlu2tU4c7bXIbfImK2lKz3qQBhH6kS74HWWkyPuPgM1N5woJCmQ==} + '@vitest/browser@2.0.2': + resolution: {integrity: sha512-0U0LY7Yq5INXwS1+CDlKEntgtWGYu5pdVmuzD9alXEBDeNnjMD0fKL4dO7V7uIWnzMgzVjKxE205y4IoRBPn/A==} peerDependencies: playwright: '*' safaridriver: '*' - vitest: 2.0.1 + vitest: 2.0.2 webdriverio: '*' peerDependenciesMeta: playwright: @@ -992,20 +985,23 @@ packages: webdriverio: optional: true - '@vitest/expect@2.0.1': - resolution: {integrity: sha512-yw70WL3ZwzbI2O3MOXYP2Shf4vqVkS3q5FckLJ6lhT9VMMtDyWdofD53COZcoeuHwsBymdOZp99r5bOr5g+oeA==} + '@vitest/expect@2.0.2': + resolution: {integrity: sha512-nKAvxBYqcDugYZ4nJvnm5OR8eDJdgWjk4XM9owQKUjzW70q0icGV2HVnQOyYsp906xJaBDUXw0+9EHw2T8e0mQ==} + + '@vitest/pretty-format@2.0.2': + resolution: {integrity: sha512-SBCyOXfGVvddRd9r2PwoVR0fonQjh9BMIcBMlSzbcNwFfGr6ZhOhvBzurjvi2F4ryut2HcqiFhNeDVGwru8tLg==} - '@vitest/runner@2.0.1': - resolution: {integrity: sha512-XfcSXOGGxgR2dQ466ZYqf0ZtDLLDx9mZeQcKjQDLQ9y6Cmk2Wl7wxMuhiYK4Fo1VxCtLcFEGW2XpcfMuiD1Maw==} + '@vitest/runner@2.0.2': + resolution: {integrity: sha512-OCh437Vi8Wdbif1e0OvQcbfM3sW4s2lpmOjAE7qfLrpzJX2M7J1IQlNvEcb/fu6kaIB9n9n35wS0G2Q3en5kHg==} - '@vitest/snapshot@2.0.1': - resolution: {integrity: sha512-rst79a4Q+J5vrvHRapdfK4BdqpMH0eF58jVY1vYeBo/1be+nkyenGI5SCSohmjf6MkCkI20/yo5oG+0R8qrAnA==} + '@vitest/snapshot@2.0.2': + resolution: {integrity: sha512-Yc2ewhhZhx+0f9cSUdfzPRcsM6PhIb+S43wxE7OG0kTxqgqzo8tHkXFuFlndXeDMp09G3sY/X5OAo/RfYydf1g==} - '@vitest/spy@2.0.1': - resolution: {integrity: sha512-NLkdxbSefAtJN56GtCNcB4GiHFb5i9q1uh4V229lrlTZt2fnwsTyjLuWIli1xwK2fQspJJmHXHyWx0Of3KTXWA==} + '@vitest/spy@2.0.2': + resolution: {integrity: sha512-MgwJ4AZtCgqyp2d7WcQVE8aNG5vQ9zu9qMPYQHjsld/QVsrvg78beNrXdO4HYkP0lDahCO3P4F27aagIag+SGQ==} - '@vitest/utils@2.0.1': - resolution: {integrity: sha512-STH+2fHZxlveh1mpU4tKzNgRk7RZJyr6kFGJYCI5vocdfqfPsQrgVC6k7dBWHfin5QNB4TLvRS0Ckly3Dt1uWw==} + '@vitest/utils@2.0.2': + resolution: {integrity: sha512-pxCY1v7kmOCWYWjzc0zfjGTA3Wmn8PKnlPvSrsA643P1NHl1fOyXj2Q9SaNlrlFE+ivCsxM80Ov3AR82RmHCWQ==} '@zeit/schemas@2.36.0': resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} @@ -1301,10 +1297,6 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2034,10 +2026,6 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -2072,9 +2060,6 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -2315,6 +2300,10 @@ packages: resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==} engines: {node: ^18.0.0 || >=20.0.0} + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + tinyspy@3.0.0: resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==} engines: {node: '>=14.0.0'} @@ -2458,8 +2447,8 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vite-node@2.0.1: - resolution: {integrity: sha512-nVd6kyhPAql0s+xIVJzuF+RSRH8ZimNrm6U8ZvTA4MXv8CHI17TFaQwRaFiK75YX6XeFqZD4IoAaAfi9OR1XvQ==} + vite-node@2.0.2: + resolution: {integrity: sha512-w4vkSz1Wo+NIQg8pjlEn0jQbcM/0D+xVaYjhw3cvarTanLLBh54oNiRbsT8PNK5GfuST0IlVXjsNRoNlqvY/fw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -2497,15 +2486,15 @@ packages: terser: optional: true - vitest@2.0.1: - resolution: {integrity: sha512-PBPvNXRJiywtI9NmbnEqHIhcXlk8mB0aKf6REQIaYGY4JtWF1Pg8Am+N0vAuxdg/wUSlxPSVJr8QdjwcVxc2Hg==} + vitest@2.0.2: + resolution: {integrity: sha512-WlpZ9neRIjNBIOQwBYfBSr0+of5ZCbxT2TVGKW4Lv0c8+srCFIiRdsP7U009t8mMn821HQ4XKgkx5dVWpyoyLw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.0.1 - '@vitest/ui': 2.0.1 + '@vitest/browser': 2.0.2 + '@vitest/ui': 2.0.2 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -3015,10 +3004,6 @@ snapshots: dependencies: mute-stream: 1.0.0 - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -3134,8 +3119,6 @@ snapshots: dependencies: '@types/hast': 3.0.4 - '@sinclair/typebox@0.27.8': {} - '@teppeis/multimaps@3.0.0': {} '@testing-library/dom@10.3.1': @@ -3320,15 +3303,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/browser@2.0.1(playwright@1.45.1)(typescript@5.5.3)(vitest@2.0.1)': + '@vitest/browser@2.0.2(playwright@1.45.1)(typescript@5.5.3)(vitest@2.0.2)': dependencies: '@testing-library/dom': 10.3.1 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.3.1) - '@vitest/utils': 2.0.1 + '@vitest/utils': 2.0.2 magic-string: 0.30.10 msw: 2.3.1(typescript@5.5.3) sirv: 2.0.4 - vitest: 2.0.1(@types/node@20.14.10)(@vitest/browser@2.0.1) + vitest: 2.0.2(@types/node@20.14.10)(@vitest/browser@2.0.2) ws: 8.18.0 optionalDependencies: playwright: 1.45.1 @@ -3337,33 +3320,38 @@ snapshots: - typescript - utf-8-validate - '@vitest/expect@2.0.1': + '@vitest/expect@2.0.2': dependencies: - '@vitest/spy': 2.0.1 - '@vitest/utils': 2.0.1 + '@vitest/spy': 2.0.2 + '@vitest/utils': 2.0.2 chai: 5.1.1 + tinyrainbow: 1.2.0 - '@vitest/runner@2.0.1': + '@vitest/pretty-format@2.0.2': dependencies: - '@vitest/utils': 2.0.1 + tinyrainbow: 1.2.0 + + '@vitest/runner@2.0.2': + dependencies: + '@vitest/utils': 2.0.2 pathe: 1.1.2 - '@vitest/snapshot@2.0.1': + '@vitest/snapshot@2.0.2': dependencies: + '@vitest/pretty-format': 2.0.2 magic-string: 0.30.10 pathe: 1.1.2 - pretty-format: 29.7.0 - '@vitest/spy@2.0.1': + '@vitest/spy@2.0.2': dependencies: tinyspy: 3.0.0 - '@vitest/utils@2.0.1': + '@vitest/utils@2.0.2': dependencies: - diff-sequences: 29.6.3 + '@vitest/pretty-format': 2.0.2 estree-walker: 3.0.3 loupe: 3.1.1 - pretty-format: 29.7.0 + tinyrainbow: 1.2.0 '@zeit/schemas@2.36.0': {} @@ -3645,8 +3633,6 @@ snapshots: dequal@2.0.3: {} - diff-sequences@29.6.3: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -4367,12 +4353,6 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - punycode.js@2.3.1: {} punycode@1.4.1: {} @@ -4400,8 +4380,6 @@ snapshots: react-is@17.0.2: {} - react-is@18.3.1: {} - react-refresh@0.14.2: {} react-router-dom@6.24.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -4649,6 +4627,8 @@ snapshots: tinypool@1.0.0: {} + tinyrainbow@1.2.0: {} + tinyspy@3.0.0: {} to-fast-properties@2.0.0: {} @@ -4767,12 +4747,12 @@ snapshots: vary@1.1.2: {} - vite-node@2.0.1(@types/node@20.14.10): + vite-node@2.0.2(@types/node@20.14.10): dependencies: cac: 6.7.14 debug: 4.3.5 pathe: 1.1.2 - picocolors: 1.0.1 + tinyrainbow: 1.2.0 vite: 5.3.3(@types/node@20.14.10) transitivePeerDependencies: - '@types/node' @@ -4800,29 +4780,30 @@ snapshots: '@types/node': 20.14.10 fsevents: 2.3.3 - vitest@2.0.1(@types/node@20.14.10)(@vitest/browser@2.0.1): + vitest@2.0.2(@types/node@20.14.10)(@vitest/browser@2.0.2): dependencies: '@ampproject/remapping': 2.3.0 - '@vitest/expect': 2.0.1 - '@vitest/runner': 2.0.1 - '@vitest/snapshot': 2.0.1 - '@vitest/spy': 2.0.1 - '@vitest/utils': 2.0.1 + '@vitest/expect': 2.0.2 + '@vitest/pretty-format': 2.0.2 + '@vitest/runner': 2.0.2 + '@vitest/snapshot': 2.0.2 + '@vitest/spy': 2.0.2 + '@vitest/utils': 2.0.2 chai: 5.1.1 debug: 4.3.5 execa: 8.0.1 magic-string: 0.30.10 pathe: 1.1.2 - picocolors: 1.0.1 std-env: 3.7.0 tinybench: 2.8.0 tinypool: 1.0.0 + tinyrainbow: 1.2.0 vite: 5.3.3(@types/node@20.14.10) - vite-node: 2.0.1(@types/node@20.14.10) + vite-node: 2.0.2(@types/node@20.14.10) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.14.10 - '@vitest/browser': 2.0.1(playwright@1.45.1)(typescript@5.5.3)(vitest@2.0.1) + '@vitest/browser': 2.0.2(playwright@1.45.1)(typescript@5.5.3)(vitest@2.0.2) transitivePeerDependencies: - less - lightningcss From f0c1c20fa85dc29e8a83e71883e24efad5f70cf6 Mon Sep 17 00:00:00 2001 From: hornta Date: Tue, 16 Jul 2024 00:02:08 +0200 Subject: [PATCH 2/2] refactor: move color to typescript --- eslint.config.mjs | 4 +- packages/examples/src/examples/text/text.ts | 18 +- packages/melonjs/src/camera/camera2d.js | 11 +- packages/melonjs/src/index.js | 5 +- .../melonjs/src/level/tiled/TMXTileMap.js | 5 +- .../melonjs/src/math/{color.js => color.ts} | 319 ++++++++++-------- packages/melonjs/src/pool.ts | 2 + packages/melonjs/src/renderable/colorlayer.js | 8 +- packages/melonjs/src/renderable/container.js | 7 +- packages/melonjs/src/renderable/light2d.js | 7 +- .../melonjs/src/renderable/nineslicesprite.js | 2 +- packages/melonjs/src/renderable/renderable.js | 6 +- packages/melonjs/src/renderable/sprite.js | 2 +- .../melonjs/src/renderable/text/bitmaptext.js | 2 +- packages/melonjs/src/renderable/text/text.js | 14 +- packages/melonjs/src/state/stage.js | 2 +- .../src/video/canvas/canvas_renderer.js | 2 +- packages/melonjs/src/video/renderer.js | 2 +- .../melonjs/src/video/webgl/webgl_renderer.js | 11 +- .../tests/{color.spec.js => color.spec.ts} | 7 +- 20 files changed, 242 insertions(+), 194 deletions(-) rename packages/melonjs/src/math/{color.js => color.ts} (61%) rename packages/melonjs/tests/{color.spec.js => color.spec.ts} (99%) diff --git a/eslint.config.mjs b/eslint.config.mjs index ff98c577a..d434f1d9c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -161,6 +161,7 @@ export default tseslint.config( rules: { "no-undef": "off", "no-unused-vars": "off", + "prefer-template": "error", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-dynamic-delete": "off", @@ -174,8 +175,9 @@ export default tseslint.config( "error", { allowNumber: true }, ], - "prefer-template": "error", ...jsDocConfig.rules, + "jsdoc/require-jsdoc": "off", + "jsdoc/no-defaults": "off", }, languageOptions: { parserOptions: { diff --git a/packages/examples/src/examples/text/text.ts b/packages/examples/src/examples/text/text.ts index e44f6fe8d..9b389265d 100644 --- a/packages/examples/src/examples/text/text.ts +++ b/packages/examples/src/examples/text/text.ts @@ -1,13 +1,23 @@ -import { BitmapText, Renderable, Text, Tween, pool, video } from "melonjs"; +import { + BitmapText, + type Color, + Renderable, + Text, + Tween, + getPool, + video, +} from "melonjs"; export class TextTest extends Renderable { + color: Color; + constructor() { super(0, 0, 640, 480); this.anchorPoint.set(0, 0); // a default white color object - this.color = pool.pull("me.Color", 255, 255, 255); + this.color = getPool("color").get(255, 255, 255); // define a tween to cycle the font color this.tween = new Tween(this.color) @@ -176,4 +186,8 @@ export class TextTest extends Renderable { this.fancyBFont.textAlign = "left"; this.fancyBFont.textBaseline = "top"; } + + destroy() { + getPool("color").release(this.color); + } } diff --git a/packages/melonjs/src/camera/camera2d.js b/packages/melonjs/src/camera/camera2d.js index a9f0c12fb..6ab0df483 100644 --- a/packages/melonjs/src/camera/camera2d.js +++ b/packages/melonjs/src/camera/camera2d.js @@ -16,10 +16,11 @@ import { VIEWPORT_ONRESIZE, } from "../system/event.ts"; import { boundsPool } from "./../physics/bounds.ts"; +import { colorPool } from "../math/color.ts"; /** * @import {Bounds} from "./../physics/bounds.ts"; - * @import Color from "./../math/color.js"; + * @import {Color} from "./../math/color.ts"; * @import Entity from "./../renderable/entity/entity.js"; * @import Sprite from "./../renderable/sprite.js"; * @import NineSliceSprite from "./../renderable/nineslicesprite.js"; @@ -519,7 +520,7 @@ export default class Camera2d extends Renderable { * }); */ fadeOut(color, duration = 1000, onComplete) { - this._fadeOut.color = pool.pull("Color").copy(color); + this._fadeOut.color = colorPool.get().copy(color); this._fadeOut.tween = pool .pull("Tween", this._fadeOut.color) .to({ alpha: 0.0 }, { duration }) @@ -539,7 +540,7 @@ export default class Camera2d extends Renderable { * me.game.viewport.fadeIn("#FFFFFF", 75); */ fadeIn(color, duration = 1000, onComplete) { - this._fadeIn.color = pool.pull("Color").copy(color); + this._fadeIn.color = colorPool.get().copy(color); const _alpha = this._fadeIn.color.alpha; this._fadeIn.color.alpha = 0.0; this._fadeIn.tween = pool @@ -629,7 +630,7 @@ export default class Camera2d extends Renderable { // remove the tween if over if (this._fadeIn.color.alpha === 1.0) { this._fadeIn.tween = null; - pool.push(this._fadeIn.color); + colorPool.release(this._fadeIn.color); this._fadeIn.color = null; } } @@ -646,7 +647,7 @@ export default class Camera2d extends Renderable { // remove the tween if over if (this._fadeOut.color.alpha === 0.0) { this._fadeOut.tween = null; - pool.push(this._fadeOut.color); + colorPool.release(this._fadeOut.color); this._fadeOut.color = null; } } diff --git a/packages/melonjs/src/index.js b/packages/melonjs/src/index.js index d12f3bb46..121a8ad39 100644 --- a/packages/melonjs/src/index.js +++ b/packages/melonjs/src/index.js @@ -2,7 +2,6 @@ import "./polyfill/index.ts"; // class definition -import Color from "./math/color.js"; import Polygon from "./geometries/poly.js"; import Line from "./geometries/line.js"; import Ellipse from "./geometries/ellipse.js"; @@ -91,6 +90,7 @@ export { Vector2d } from "./math/vector2d.ts"; export { Vector3d } from "./math/vector3d.ts"; export { Matrix2d } from "./math/matrix2d.ts"; export { Matrix3d } from "./math/matrix3d.ts"; +export { Color } from "./math/color.ts"; export { Point } from "./geometries/point.ts"; export { Bounds } from "./physics/bounds.ts"; export { createObservableVector2d } from "./math/observableVector2d.ts"; @@ -99,7 +99,6 @@ export { getPool } from "./pool.ts"; // export all class definition export { - Color, Polygon, Line, Ellipse, @@ -209,7 +208,6 @@ export function boot() { pool.register("me.Trigger", Trigger); pool.register("me.Light2d", Light2d); pool.register("me.Tween", Tween, true); - pool.register("me.Color", Color, true); pool.register("me.Particle", Particle, true); pool.register("me.Sprite", Sprite); pool.register("me.NineSliceSprite", NineSliceSprite); @@ -231,7 +229,6 @@ export function boot() { pool.register("Trigger", Trigger); pool.register("Light2d", Light2d); pool.register("Tween", Tween, true); - pool.register("Color", Color, true); pool.register("Particle", Particle, true); pool.register("Sprite", Sprite); pool.register("NineSliceSprite", NineSliceSprite); diff --git a/packages/melonjs/src/level/tiled/TMXTileMap.js b/packages/melonjs/src/level/tiled/TMXTileMap.js index c006fa94f..f9949caf4 100644 --- a/packages/melonjs/src/level/tiled/TMXTileMap.js +++ b/packages/melonjs/src/level/tiled/TMXTileMap.js @@ -14,6 +14,7 @@ import { getNewTMXRenderer } from "./renderer/autodetect.js"; import { warning } from "../../lang/console.js"; import { eventEmitter, VIEWPORT_ONRESIZE } from "../../system/event.ts"; import { vector2dPool } from "../../math/vector2d.ts"; +import { colorPool } from "../../math/color.ts"; /** * read the layer Data @@ -53,7 +54,7 @@ function readImageLayer(map, data, z) { // convert to melonJS color format (note: this should be done earlier when parsing data) tint: typeof data.tintcolor !== "undefined" - ? pool.pull("Color").parseHex(data.tintcolor, true) + ? colorPool.get().parseHex(data.tintcolor, true) : undefined, z: z, }, @@ -446,7 +447,7 @@ export default class TMXTileMap { } // convert to melonJS renderable argument name if (typeof settings.tintcolor !== "undefined") { - settings.tint = pool.pull("Color"); + settings.tint = colorPool.get(); settings.tint.parseHex(settings.tintcolor, true); } diff --git a/packages/melonjs/src/math/color.js b/packages/melonjs/src/math/color.ts similarity index 61% rename from packages/melonjs/src/math/color.js rename to packages/melonjs/src/math/color.ts index ec70a2a48..7ce30010c 100644 --- a/packages/melonjs/src/math/color.js +++ b/packages/melonjs/src/math/color.ts @@ -1,5 +1,5 @@ import { clamp, random } from "./math.ts"; -import pool from "./../system/pooling.js"; +import { createPool } from "../system/pool.ts"; // convert a give color component to it hexadecimal value const charLookup = [ @@ -21,11 +21,11 @@ const charLookup = [ "F", ]; -function toHex(component) { +function toHex(component: number) { return charLookup[(component & 0xf0) >> 4] + charLookup[component & 0x0f]; } -function hue2rgb(p, q, t) { +function hue2rgb(p: number, q: number, t: number) { if (t < 0) { t += 1; } @@ -44,16 +44,14 @@ function hue2rgb(p, q, t) { return p; } -const rgbaRx = /^rgba?\((\d+), ?(\d+), ?(\d+)(, ?([\d\.]+))?\)$/; +const rgbaRx = /^rgba?\((\d+), ?(\d+), ?(\d+)(, ?([\d.]+))?\)$/; const hex3Rx = /^#([\da-fA-F])([\da-fA-F])([\da-fA-F])$/; const hex4Rx = /^#([\da-fA-F])([\da-fA-F])([\da-fA-F])([\da-fA-F])$/; const hex6Rx = /^#([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})$/; const hex8Rx = /^#([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})$/; -const cssToRGB = new Map(); - -[ +const CSS_COLORS = [ // CSS1 ["black", [0, 0, 0]], ["silver", [192, 192, 129]], @@ -204,91 +202,106 @@ const cssToRGB = new Map(); ["wheat", [245, 222, 179]], ["whitesmoke", [245, 245, 245]], ["yellowgreen", [154, 205, 50]], -].forEach((value) => { - cssToRGB.set(value[0], value[1]); -}); +] as const; + +type ColorName = (typeof CSS_COLORS)[number][0]; + +const cssToRGB = new Map(); +for (const [name, rgb] of CSS_COLORS) { + cssToRGB.set(name, rgb); +} /** * A color manipulation object. */ -export default class Color { - /** - * @param {number} [r=0] - red component [0 .. 255] - * @param {number} [g=0] - green component [0 .. 255] - * @param {number} [b=0] - blue component [0 .. 255] - * @param {number} [alpha=1.0] - alpha value [0.0 .. 1.0] - */ - constructor(r = 0, g = 0, b = 0, alpha = 1.0) { - this.onResetEvent(r, g, b, alpha); - } +export class Color { + private glArray: Float32Array; /** - * @ignore + * Creates a new Color instance. + * @param [r] - The red component [0 .. 255]. Defaults to 0. + * @param [g] - The green component [0 .. 255]. Defaults to 0. + * @param [b] - The blue component [0 .. 255]. Defaults to 0. + * @param [alpha] - The alpha value [0.0 .. 1.0]. Defaults to 1. */ - onResetEvent(r = 0, g = 0, b = 0, alpha = 1.0) { - if (typeof this.glArray === "undefined") { - // Color components in a Float32Array suitable for WebGL - this.glArray = new Float32Array([0.0, 0.0, 0.0, 1.0]); - } + constructor(r = 0, g = 0, b = 0, alpha = 1.0) { + this.glArray = new Float32Array([0, 0, 0, 1]); this.setColor(r, g, b, alpha); } /** - * Color Red Component [0 .. 255] - * @type {number} + * Gets the red component of the color. + * @returns The red component [0 .. 255]. */ get r() { return ~~(this.glArray[0] * 255); } + /** + * Sets the red component of the color. + * @param value - The red component [0 .. 255]. + */ set r(value) { this.glArray[0] = clamp(~~value || 0, 0, 255) / 255.0; } /** - * Color Green Component [0 .. 255] - * @type {number} + * Gets the green component of the color. + * @returns The green component [0 .. 255]. */ get g() { return ~~(this.glArray[1] * 255); } + /** + * Sets the green component of the color. + * @param value - The green component [0 .. 255]. + */ set g(value) { this.glArray[1] = clamp(~~value || 0, 0, 255) / 255.0; } /** - * Color Blue Component [0 .. 255] - * @type {number} + * Gets the blue component of the color. + * @returns The blue component [0 .. 255]. */ get b() { return ~~(this.glArray[2] * 255); } + + /** + * Sets the blue component of the color. + * @param value - The blue component [0 .. 255]. + */ set b(value) { this.glArray[2] = clamp(~~value || 0, 0, 255) / 255.0; } /** - * Color Alpha Component [0.0 .. 1.0] - * @type {number} + * Gets the alpha component of the color. + * @returns The alpha component [0.0 .. 1.0]. */ get alpha() { return this.glArray[3]; } - set alpha(value = 1.0) { + /** + * Sets the alpha component of the color. + * @param value - The alpha component [0.0 .. 1.0]. + */ + set alpha(value) { this.glArray[3] = clamp(+value, 0, 1.0); } /** - * Set this color to the specified value. - * @param {number} r - red component [0 .. 255] - * @param {number} g - green component [0 .. 255] - * @param {number} b - blue component [0 .. 255] - * @param {number} [alpha=1.0] - alpha value [0.0 .. 1.0] - * @returns {Color} Reference to this object for method chaining + * Sets the color to the specified values. + * @param r - The red component [0 .. 255]. + * @param g - The green component [0 .. 255]. + * @param b - The blue component [0 .. 255]. + * @param [alpha] - The alpha value [0.0 .. 1.0]. Defaults to 1. + * @returns Reference to this object for method chaining. */ - setColor(r, g, b, alpha = 1.0) { + setColor(r: number, g: number, b: number, alpha = 1.0) { this.r = r; this.g = g; this.b = b; @@ -297,14 +310,14 @@ export default class Color { } /** - * set this color to the specified normalized float values - * @param {number} r - red component [0.0 .. 1.0] - * @param {number} g - green component [0.0 .. 1.0] - * @param {number} b - blue component [0.0 .. 1.0] - * @param {number} [alpha=1.0] - alpha value [0.0 .. 1.0] - * @returns {Color} Reference to this object for method chaining + * Sets the color to the specified normalized float values. + * @param r - The red component [0.0 .. 1.0]. + * @param g - The green component [0.0 .. 1.0]. + * @param b - The blue component [0.0 .. 1.0]. + * @param [alpha=1.0] - The alpha value [0.0 .. 1.0]. Defaults to 1. + * @returns Reference to this object for method chaining. */ - setFloat(r, g, b, alpha = 1.0) { + setFloat(r: number, g: number, b: number, alpha = 1.0) { const a = this.glArray; a[0] = clamp(+r, 0, 1.0); a[1] = clamp(+g, 0, 1.0); @@ -314,16 +327,16 @@ export default class Color { } /** - * set this color to the specified HSV value - * @param {number} h - hue (a value from 0 to 1) - * @param {number} s - saturation (a value from 0 to 1) - * @param {number} v - value (a value from 0 to 1) - * @returns {Color} Reference to this object for method chaining + * Sets the color to the specified HSV values. + * @param h - The hue [0 .. 1]. + * @param s - The saturation [0 .. 1]. + * @param v - The value [0 .. 1]. + * @returns Reference to this object for method chaining. */ - setHSV(h, s, v) { - let r; - let g; - let b; + setHSV(h: number, s: number, v: number) { + let r: number; + let g: number; + let b: number; const i = Math.floor(h * 6); const f = h * 6 - i; @@ -331,7 +344,7 @@ export default class Color { const q = v * (1 - f * s); const t = v * (1 - (1 - f) * s); - switch (i % 6) { + switch ((i % 6) as 0 | 1 | 2 | 3 | 4 | 5) { case 0: r = v; g = t; @@ -367,13 +380,13 @@ export default class Color { } /** - * set this color to the specified HSL value - * @param {number} h - hue (a value from 0 to 1) - * @param {number} s - saturation (a value from 0 to 1) - * @param {number} l - lightness (a value from 0 to 1) - * @returns {Color} Reference to this object for method chaining + * Sets the color to the specified HSL values. + * @param h - The hue [0 .. 1]. + * @param s - The saturation [0 .. 1]. + * @param l - The lightness [0 .. 1]. + * @returns Reference to this object for method chaining. */ - setHSL(h, s, l) { + setHSL(h: number, s: number, l: number) { let r; let g; let b; @@ -393,19 +406,19 @@ export default class Color { } /** - * Create a new copy of this color object. - * @returns {Color} Reference to the newly cloned object + * Creates a new copy of this color object. + * @returns Reference to the newly cloned object. */ clone() { - return pool.pull("Color").copy(this); + return colorPool.get().copy(this); } /** - * Copy a color object or CSS color into this one. - * @param {Color|string} color - * @returns {Color} Reference to this object for method chaining + * Copies a color object or CSS color into this one. + * @param color - The color to copy. + * @returns Reference to this object for method chaining. */ - copy(color) { + copy(color: Color) { if (typeof color === "string") { return this.parseCSS(color); } else { @@ -415,11 +428,11 @@ export default class Color { } /** - * Blend this color with the given one using addition. - * @param {Color} color - * @returns {Color} Reference to this object for method chaining + * Blends this color with the given one using addition. + * @param color - The color to blend with. + * @returns Reference to this object for method chaining. */ - add(color) { + add(color: Color) { this.glArray[0] = clamp(this.glArray[0] + color.glArray[0], 0, 1); this.glArray[1] = clamp(this.glArray[1] + color.glArray[1], 0, 1); this.glArray[2] = clamp(this.glArray[2] + color.glArray[2], 0, 1); @@ -429,11 +442,11 @@ export default class Color { } /** - * Darken this color value by 0..1 - * @param {number} scale - * @returns {Color} Reference to this object for method chaining + * Darkens this color value by a given scale. + * @param scale - The scale to darken the color by [0 .. 1]. + * @returns Reference to this object for method chaining. */ - darken(scale) { + darken(scale: number) { scale = clamp(scale, 0, 1); this.glArray[0] *= scale; this.glArray[1] *= scale; @@ -443,12 +456,12 @@ export default class Color { } /** - * Linearly interpolate between this color and the given one. - * @param {Color} color - * @param {number} alpha - with alpha = 0 being this color, and alpha = 1 being the given one. - * @returns {Color} Reference to this object for method chaining + * Linearly interpolates between this color and the given one. + * @param color - The color to interpolate with. + * @param alpha - The interpolation factor, with alpha = 0 being this color, and alpha = 1 being the given one. + * @returns Reference to this object for method chaining. */ - lerp(color, alpha) { + lerp(color: Color, alpha: number) { alpha = clamp(alpha, 0, 1); this.glArray[0] += (color.glArray[0] - this.glArray[0]) * alpha; this.glArray[1] += (color.glArray[1] - this.glArray[1]) * alpha; @@ -458,11 +471,11 @@ export default class Color { } /** - * Lighten this color value by 0..1 - * @param {number} scale - * @returns {Color} Reference to this object for method chaining + * Lightens this color value by a given scale + * @param scale - The scale to lighten the color by [0 .. 1]. + * @returns Reference to this object for method chaining. */ - lighten(scale) { + lighten(scale: number) { scale = clamp(scale, 0, 1); this.glArray[0] = clamp( this.glArray[0] + (1 - this.glArray[0]) * scale, @@ -485,9 +498,9 @@ export default class Color { /** * Generate random r,g,b values for this color object - * @param {number} [min=0] - minimum value for the random range - * @param {number} [max=255] - maxmium value for the random range - * @returns {Color} Reference to this object for method chaining + * @param [min] - minimum value for the random range + * @param [max] - maxmium value for the random range + * @returns Reference to this object for method chaining */ random(min = 0, max = 255) { if (min < 0) { @@ -506,12 +519,11 @@ export default class Color { } /** - * Return true if the r,g,b,a values of this color are equal with the - * given one. - * @param {Color} color - * @returns {boolean} + * Checks if this color is equal to another. + * @param color - The color to compare with. + * @returns True if the colors are equal, otherwise false. */ - equals(color) { + equals(color: Color) { return ( this.glArray[0] === color.glArray[0] && this.glArray[1] === color.glArray[1] && @@ -521,57 +533,55 @@ export default class Color { } /** - * Parse a CSS color string and set this color to the corresponding - * r,g,b values - * @param {string} cssColor - * @returns {Color} Reference to this object for method chaining + * Parse a CSS color name and set this color to the corresponding r,g,b values + * @param cssColor - The CSS color name + * @returns Reference to this object for method chaining */ - parseCSS(cssColor) { - // TODO : Memoize this function by caching its input - - if (cssToRGB.has(cssColor)) { - return this.setColor.apply(this, cssToRGB.get(cssColor)); + parseCSS(cssColor: ColorName) { + const rgb = cssToRGB.get(cssColor); + if (!rgb) { + return this.parseRGB(cssColor); } - - return this.parseRGB(cssColor); + return this.setColor(...rgb); } /** * Parse an RGB or RGBA CSS color string - * @param {string} rgbColor - * @returns {Color} Reference to this object for method chaining + * @param rgbColor - The RGB or RGBA color string to parse + * @returns Reference to this object for method chaining */ - parseRGB(rgbColor) { + parseRGB(rgbColor: string) { // TODO : Memoize this function by caching its input const match = rgbaRx.exec(rgbColor); - if (match) { - return this.setColor(+match[1], +match[2], +match[3], +match[5]); + if (!match) { + return this.parseHex(rgbColor as `#${string}`); } - - return this.parseHex(rgbColor); + return this.setColor(+match[1], +match[2], +match[3], +match[5]); } /** * Parse a Hex color ("#RGB", "#RGBA" or "#RRGGBB", "#RRGGBBAA" format) and set this color to * the corresponding r,g,b,a values - * @param {string} hexColor - * @param {boolean} [argb = false] - true if format is #ARGB, or #AARRGGBB (as opposed to #RGBA or #RGGBBAA) - * @returns {Color} Reference to this object for method chaining + * @param hexColor - The Hex color string to parse + * @param [argb] - true if format is #ARGB, or #AARRGGBB (as opposed to #RGBA or #RGGBBAA) + * @returns Reference to this object for method chaining */ - parseHex(hexColor, argb = false) { + parseHex(hexColor: `#${string}`, argb = false) { // TODO : Memoize this function by caching its input - let match; + let match: RegExpExecArray | null; if ((match = hex8Rx.exec(hexColor))) { // #AARRGGBB or #RRGGBBAA return this.setColor( - parseInt(match[argb === false ? 1 : 2], 16), // r - parseInt(match[argb === false ? 2 : 3], 16), // g - parseInt(match[argb === false ? 3 : 4], 16), // b - ( - clamp(parseInt(match[argb === false ? 4 : 1], 16), 0, 255) / 255.0 - ).toFixed(1), // a + parseInt(match[!argb ? 1 : 2], 16), // r + parseInt(match[!argb ? 2 : 3], 16), // g + parseInt(match[!argb ? 3 : 4], 16), // b + Number( + (clamp(parseInt(match[!argb ? 4 : 1], 16), 0, 255) / 255.0).toFixed( + 1, + ), + ), // a ); } @@ -586,15 +596,15 @@ export default class Color { if ((match = hex4Rx.exec(hexColor))) { // #ARGB or #RGBA - const r = match[argb === false ? 1 : 2]; - const g = match[argb === false ? 2 : 3]; - const b = match[argb === false ? 3 : 4]; - const a = match[argb === false ? 4 : 1]; + const r = match[!argb ? 1 : 2]; + const g = match[!argb ? 2 : 3]; + const b = match[!argb ? 3 : 4]; + const a = match[!argb ? 4 : 1]; return this.setColor( parseInt(r + r, 16), // r parseInt(g + g, 16), // g parseInt(b + b, 16), // b - (clamp(parseInt(a + a, 16), 0, 255) / 255.0).toFixed(1), // a + Number((clamp(parseInt(a + a, 16), 0, 255) / 255.0).toFixed(1)), // a ); } @@ -607,13 +617,13 @@ export default class Color { ); } - throw new Error("invalid parameter: " + hexColor); + throw new Error(`invalid parameter: ${hexColor}`); } /** * Pack this color RGB components into a Uint32 ARGB representation - * @param {number} [alpha=1.0] - alpha value [0.0 .. 1.0] - * @returns {number} + * @param [alpha] - alpha value [0.0 .. 1.0] + * @returns A Uint32 ARGB representation of this color */ toUint32(alpha = 1.0) { const a = this.glArray; @@ -627,7 +637,7 @@ export default class Color { /** * return an Float Array representation of this object - * @returns {Float32Array} + * @returns A Float Array representation of this color */ toArray() { return this.glArray; @@ -635,48 +645,65 @@ export default class Color { /** * return the color in "#RRGGBB" format - * @returns {string} + * @returns The color in "#RRGGBB" format */ toHex() { // TODO : Memoize this function by caching its result until any of // the r,g,b,a values are changed - return "#" + toHex(this.r) + toHex(this.g) + toHex(this.b); + return `#${toHex(this.r)}${toHex(this.g)}${toHex(this.b)}`; } /** * Get the color in "#RRGGBBAA" format - * @returns {string} + * @param alpha - The alpha value [0.0 .. 1.0] to use in the output string. + * @returns The color in "#RRGGBBAA" format */ toHex8(alpha = this.alpha) { // TODO : Memoize this function by caching its result until any of // the r,g,b,a values are changed - return ( - "#" + toHex(this.r) + toHex(this.g) + toHex(this.b) + toHex(alpha * 255) - ); + return `#${toHex(this.r)}${toHex(this.g)}${toHex(this.b)}${toHex(alpha * 255)}`; } /** * Get the color in "rgb(R,G,B)" format - * @returns {string} + * @returns The color in "rgb(R,G,B)" format */ toRGB() { // TODO : Memoize this function by caching its result until any of // the r,g,b,a values are changed - return "rgb(" + this.r + "," + this.g + "," + this.b + ")"; + return `rgb(${this.r},${this.g},${this.b})` as const; } /** * Get the color in "rgba(R,G,B,A)" format - * @param {number} [alpha=1.0] - alpha value [0.0 .. 1.0] - * @returns {string} + * @param [alpha] - alpha value [0.0 .. 1.0] + * @returns The color in "rgba(R,G,B,A)" format */ toRGBA(alpha = this.alpha) { // TODO : Memoize this function by caching its result until any of // the r,g,b,a values are changed - return "rgba(" + this.r + "," + this.g + "," + this.b + "," + alpha + ")"; + return `rgba(${this.r},${this.g},${this.b},${alpha})` as const; } } + +export const colorPool = createPool< + Color, + [ + r?: number | undefined, + g?: number | undefined, + b?: number | undefined, + alpha?: number | undefined, + ] +>((r, g, b, alpha) => { + const color = new Color(r, g, b, alpha); + return { + instance: color, + reset(r = 0, g = 0, b = 0, alpha = 1) { + color.setColor(r, g, b, alpha); + }, + }; +}); diff --git a/packages/melonjs/src/pool.ts b/packages/melonjs/src/pool.ts index 8e22b7712..eb3772f47 100644 --- a/packages/melonjs/src/pool.ts +++ b/packages/melonjs/src/pool.ts @@ -1,4 +1,5 @@ import { pointPool } from "./geometries/point"; +import { colorPool } from "./math/color"; import { matrix2dPool } from "./math/matrix2d"; import { matrix3dPool } from "./math/matrix3d"; import { vector2dPool } from "./math/vector2d"; @@ -12,6 +13,7 @@ const pools = { matrix2d: matrix2dPool, matrix3d: matrix3dPool, bounds: boundsPool, + color: colorPool, } as const; type PoolKey = keyof typeof pools; diff --git a/packages/melonjs/src/renderable/colorlayer.js b/packages/melonjs/src/renderable/colorlayer.js index e2d76a6d4..35e60cb93 100644 --- a/packages/melonjs/src/renderable/colorlayer.js +++ b/packages/melonjs/src/renderable/colorlayer.js @@ -1,9 +1,9 @@ -import pool from "./../system/pooling.js"; +import { colorPool } from "../math/color.ts"; import Renderable from "./renderable.js"; /** * additional import for TypeScript - * @import Color from "./../math/color.js"; + * @import {Color} from "./../math/color.ts"; * @import CanvasRenderer from "./../video/canvas/canvas_renderer.js"; * @import WebGLRenderer from "./../video/webgl/webgl_renderer.js"; * @import Camera2d from "./../camera/camera2d.js"; @@ -26,7 +26,7 @@ export default class ColorLayer extends Renderable { * the layer color component * @type {Color} */ - this.color = pool.pull("Color").parseCSS(color); + this.color = colorPool.get().parseCSS(color); this.onResetEvent(name, color, z); } @@ -57,7 +57,7 @@ export default class ColorLayer extends Renderable { * @ignore */ destroy() { - pool.push(this.color); + colorPool.release(this.color); this.color = undefined; super.destroy(); } diff --git a/packages/melonjs/src/renderable/container.js b/packages/melonjs/src/renderable/container.js index 9a8a71d0d..d54f530bb 100644 --- a/packages/melonjs/src/renderable/container.js +++ b/packages/melonjs/src/renderable/container.js @@ -6,6 +6,7 @@ import pool from "../system/pooling.js"; import state from "../state/state.js"; import Body from "../physics/body.js"; import { CANVAS_ONRESIZE, eventEmitter } from "../system/event.ts"; +import { colorPool } from "../math/color.ts"; /** * Private function to re-use for object removal in a defer @@ -19,7 +20,7 @@ let globalFloatingCounter = 0; /** * additional import for TypeScript - * @import Color from "./../math/color.js"; + * @import {Color} from "./../math/color.ts"; * @import Entity from "./entity/entity.js"; * @import Sprite from "./sprite.js"; * @import Collectable from "./collectable.js"; @@ -140,7 +141,7 @@ export default class Container extends Renderable { * // add a red background color to this container * this.backgroundColor.setColor(255, 0, 0); */ - this.backgroundColor = pool.pull("Color", 0, 0, 0, 0.0); + this.backgroundColor = colorPool.get(0, 0, 0, 0.0); /** * Used by the debug panel plugin @@ -897,6 +898,8 @@ export default class Container extends Renderable { this.reset(); // call the parent destroy method super.destroy(arguments); + + colorPool.release(this.backgroundColor); } /** diff --git a/packages/melonjs/src/renderable/light2d.js b/packages/melonjs/src/renderable/light2d.js index 3e192a5b9..94793d55c 100644 --- a/packages/melonjs/src/renderable/light2d.js +++ b/packages/melonjs/src/renderable/light2d.js @@ -1,9 +1,10 @@ +import { colorPool } from "./../math/color.ts"; import pool from "./../system/pooling.js"; import Renderable from "./renderable.js"; /** * additional import for TypeScript - * @import Color from "./../math/color.js"; + * @import {Color} from "./../math/color.ts"; * @import Ellipse from "./../geometries/ellipse.js"; * @import CanvasRenderer from "./../video/canvas/canvas_renderer.js"; * @import WebGLRenderer from "./../video/webgl/webgl_renderer.js"; @@ -101,7 +102,7 @@ export default class Light2d extends Renderable { * @type {Color} * @default "#FFF" */ - this.color = pool.pull("Color").parseCSS(color); + this.color = colorPool.get().parseCSS(color); /** * The horizontal radius of the light @@ -190,7 +191,7 @@ export default class Light2d extends Renderable { * @ignore */ destroy() { - pool.push(this.color); + colorPool.release(this.color); this.color = undefined; pool.push(this.texture); this.texture = undefined; diff --git a/packages/melonjs/src/renderable/nineslicesprite.js b/packages/melonjs/src/renderable/nineslicesprite.js index c0e76db7b..3cec01ab1 100644 --- a/packages/melonjs/src/renderable/nineslicesprite.js +++ b/packages/melonjs/src/renderable/nineslicesprite.js @@ -2,7 +2,7 @@ import Sprite from "./sprite.js"; /** * additional import for TypeScript - * @import Color from "./../math/color.js"; + * @import {Color} from "./../math/color.ts"; * @import { TextureAtlas } from "./../video/texture/atlas.js"; */ diff --git a/packages/melonjs/src/renderable/renderable.js b/packages/melonjs/src/renderable/renderable.js index 496d09c8b..b153eff08 100644 --- a/packages/melonjs/src/renderable/renderable.js +++ b/packages/melonjs/src/renderable/renderable.js @@ -5,7 +5,7 @@ import { clamp } from "./../math/math.ts"; import Body from "./../physics/body.js"; import { Bounds, boundsPool } from "./../physics/bounds.ts"; import GLShader from "./../video/webgl/glshader.js"; -import Color from "./../math/color.js"; +import { Color, colorPool } from "./../math/color.ts"; import { observableVector3dPool } from "../math/observableVector3d.ts"; import { observableVector2dPool } from "../math/observableVector2d.ts"; import { vector2dPool } from "../math/vector2d.ts"; @@ -301,7 +301,7 @@ export default class Renderable extends Rect { * renderable cache tint value used by the getter/setter * @ignore */ - this._tint = pool.pull("Color", 255, 255, 255, 1.0); + this._tint = colorPool.get(255, 255, 255, 1.0); // ensure it's fully opaque by default this.setOpacity(1.0); @@ -847,7 +847,7 @@ export default class Renderable extends Rect { } if (this._tint instanceof Color) { - pool.push(this._tint); + colorPool.release(this._tint); this._tint = undefined; } diff --git a/packages/melonjs/src/renderable/sprite.js b/packages/melonjs/src/renderable/sprite.js index eaafc4f1f..1754d7c13 100644 --- a/packages/melonjs/src/renderable/sprite.js +++ b/packages/melonjs/src/renderable/sprite.js @@ -2,7 +2,7 @@ import { renderer } from "./../video/video.js"; import { getImage } from "./../loader/loader.js"; import { TextureAtlas } from "./../video/texture/atlas.js"; import Renderable from "./renderable.js"; -import Color from "../math/color.js"; +import { Color } from "../math/color.ts"; import { eventEmitter } from "../system/event.ts"; import { vector2dPool } from "../math/vector2d.ts"; diff --git a/packages/melonjs/src/renderable/text/bitmaptext.js b/packages/melonjs/src/renderable/text/bitmaptext.js index f1360efb4..86c1f990c 100644 --- a/packages/melonjs/src/renderable/text/bitmaptext.js +++ b/packages/melonjs/src/renderable/text/bitmaptext.js @@ -1,4 +1,4 @@ -import Color from "../../math/color.js"; +import { Color } from "../../math/color.ts"; import pool from "../../system/pooling.js"; import { getImage, getBinary } from "../../loader/loader.js"; import Renderable from "../renderable.js"; diff --git a/packages/melonjs/src/renderable/text/text.js b/packages/melonjs/src/renderable/text/text.js index 14509a6d1..13c0b4cd4 100644 --- a/packages/melonjs/src/renderable/text/text.js +++ b/packages/melonjs/src/renderable/text/text.js @@ -1,4 +1,4 @@ -import Color from "../../math/color.js"; +import { Color, colorPool } from "../../math/color.ts"; import { renderer as globalRenderer } from "../../video/video.js"; import pool from "../../system/pooling.js"; import Renderable from "../renderable.js"; @@ -48,14 +48,14 @@ export default class Text extends Renderable { * @type {Color} * @default black */ - this.fillStyle = pool.pull("Color", 0, 0, 0); + this.fillStyle = colorPool.get(0, 0, 0); /** * defines the color used to draw the font stroke.
* @type {Color} * @default black */ - this.strokeStyle = pool.pull("Color", 0, 0, 0); + this.strokeStyle = colorPool.get(0, 0, 0); /** * sets the current line width, in pixels, when drawing stroke @@ -116,11 +116,11 @@ export default class Text extends Renderable { /** @ignore */ onResetEvent(x, y, settings) { if (typeof this.fillStyle === "undefined") { - this.fillStyle = pool.pull("Color", 0, 0, 0); + this.fillStyle = colorPool.get(0, 0, 0); } if (typeof this.strokeStyle === "undefined") { - this.strokeStyle = pool.pull("Color", 0, 0, 0); + this.strokeStyle = colorPool.get(0, 0, 0); } if (typeof settings.fillStyle !== "undefined") { @@ -404,8 +404,8 @@ export default class Text extends Renderable { globalRenderer.cache.delete(this.canvasTexture.canvas); pool.push(this.canvasTexture); this.canvasTexture = undefined; - pool.push(this.fillStyle); - pool.push(this.strokeStyle); + colorPool.release(this.fillStyle); + colorPool.release(this.strokeStyle); this.fillStyle = this.strokeStyle = undefined; this.metrics = undefined; this._text.length = 0; diff --git a/packages/melonjs/src/state/stage.js b/packages/melonjs/src/state/stage.js index 6d1c4f4b9..022063df7 100644 --- a/packages/melonjs/src/state/stage.js +++ b/packages/melonjs/src/state/stage.js @@ -1,6 +1,6 @@ import { renderer } from "./../video/video.js"; import Camera2d from "./../camera/camera2d.js"; -import Color from "./../math/color.js"; +import { Color } from "./../math/color.ts"; import { eventEmitter, STAGE_RESET } from "../system/event.ts"; // a default camera instance to use across all stages diff --git a/packages/melonjs/src/video/canvas/canvas_renderer.js b/packages/melonjs/src/video/canvas/canvas_renderer.js index a19b0fc73..9323c87fd 100644 --- a/packages/melonjs/src/video/canvas/canvas_renderer.js +++ b/packages/melonjs/src/video/canvas/canvas_renderer.js @@ -4,7 +4,7 @@ import { ONCONTEXT_LOST, ONCONTEXT_RESTORED, } from "../../system/event.ts"; -import Color from "./../../math/color.js"; +import { Color } from "./../../math/color.ts"; import Renderer from "./../renderer.js"; import TextureCache from "./../texture/cache.js"; diff --git a/packages/melonjs/src/video/renderer.js b/packages/melonjs/src/video/renderer.js index eb62e59a3..98e431828 100644 --- a/packages/melonjs/src/video/renderer.js +++ b/packages/melonjs/src/video/renderer.js @@ -1,4 +1,4 @@ -import Color from "./../math/color.js"; +import { Color } from "./../math/color.ts"; import { Matrix3d } from "../math/matrix3d.ts"; import Path2D from "./../geometries/path2d.js"; import { Vector2d } from "../math/vector2d.ts"; diff --git a/packages/melonjs/src/video/webgl/webgl_renderer.js b/packages/melonjs/src/video/webgl/webgl_renderer.js index b2be387e4..3330989a9 100644 --- a/packages/melonjs/src/video/webgl/webgl_renderer.js +++ b/packages/melonjs/src/video/webgl/webgl_renderer.js @@ -1,4 +1,4 @@ -import Color from "./../../math/color.js"; +import { Color, colorPool } from "./../../math/color.ts"; import { Matrix2d, matrix2dPool } from "../../math/matrix2d.ts"; import QuadCompositor from "./compositors/quad_compositor"; import PrimitiveCompositor from "./compositors/primitive_compositor"; @@ -6,7 +6,6 @@ import Renderer from "./../renderer.js"; import TextureCache from "./../texture/cache.js"; import { TextureAtlas, createAtlas } from "./../texture/atlas.js"; import { renderer } from "./../video.js"; -import pool from "./../../system/pooling.js"; import { isPowerOfTwo } from "./../../math/math.ts"; import { CANVAS_ONRESIZE, @@ -296,7 +295,7 @@ export default class WebGLRenderer extends Renderer { // clear all stacks this._colorStack.forEach((color) => { - pool.push(color); + colorPool.release(color); }); this._matrixStack.forEach((matrix) => { matrix2dPool.release(matrix); @@ -499,10 +498,10 @@ export default class WebGLRenderer extends Renderer { if (color instanceof Color) { glArray = color.toArray(); } else { - const _color = pool.pull("me.Color"); + const _color = colorPool.get(); // reuse temporary the renderer default color object glArray = _color.parseCSS(color).toArray(); - pool.push(_color); + colorPool.release(_color); } // clear gl context with the specified color @@ -793,7 +792,7 @@ export default class WebGLRenderer extends Renderer { this.setBlendMode(this._blendStack.pop()); // recycle objects - pool.push(color); + colorPool.release(color); matrix2dPool.release(matrix); } diff --git a/packages/melonjs/tests/color.spec.js b/packages/melonjs/tests/color.spec.ts similarity index 99% rename from packages/melonjs/tests/color.spec.js rename to packages/melonjs/tests/color.spec.ts index 2aebdc3c6..3df0ec562 100644 --- a/packages/melonjs/tests/color.spec.js +++ b/packages/melonjs/tests/color.spec.ts @@ -2,9 +2,10 @@ import { beforeAll, describe, expect, it } from "vitest"; import { Color } from "../src/index.js"; describe("Color", () => { - let red_color; - let green_color; - let blue_color; + let red_color: Color; + let green_color: Color; + let blue_color: Color; + //ToDo changing this to 'beforeEach' shows that currently tests leak their state into other tests, which is not good beforeAll(() => { red_color = new Color(255, 0, 0, 0.5);