diff --git a/eslint.config.mjs b/eslint.config.mjs
index 787ab33af..d434f1d9c 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -161,18 +161,23 @@ 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",
"@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 },
],
- "prefer-template": "error",
...jsDocConfig.rules,
+ "jsdoc/require-jsdoc": "off",
+ "jsdoc/no-defaults": "off",
},
languageOptions: {
parserOptions: {
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/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 e4383dc9b..6ab0df483 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,10 +15,12 @@ import {
VIEWPORT_ONCHANGE,
VIEWPORT_ONRESIZE,
} from "../system/event.ts";
+import { boundsPool } from "./../physics/bounds.ts";
+import { colorPool } from "../math/color.ts";
/**
- * @import Bounds from "./../physics/bounds.js";
- * @import Color from "./../math/color.js";
+ * @import {Bounds} from "./../physics/bounds.ts";
+ * @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";
@@ -61,7 +61,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 +322,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");
@@ -525,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 })
@@ -545,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
@@ -593,7 +588,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 +605,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);
@@ -635,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;
}
}
@@ -652,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/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..121a8ad39 100644
--- a/packages/melonjs/src/index.js
+++ b/packages/melonjs/src/index.js
@@ -2,22 +2,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 +86,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 { Color } from "./math/color.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 +117,6 @@ export {
TextureAtlas,
Renderable,
Body,
- Bounds,
Text,
BitmapText,
BitmapTextData,
@@ -216,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);
@@ -226,19 +217,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);
@@ -246,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);
@@ -256,19 +238,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..f9949caf4 100644
--- a/packages/melonjs/src/level/tiled/TMXTileMap.js
+++ b/packages/melonjs/src/level/tiled/TMXTileMap.js
@@ -13,6 +13,8 @@ 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";
+import { colorPool } from "../../math/color.ts";
/**
* read the layer Data
@@ -48,15 +50,11 @@ 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"
- ? pool.pull("Color").parseHex(data.tintcolor, true)
+ ? colorPool.get().parseHex(data.tintcolor, true)
: undefined,
z: z,
},
@@ -449,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);
}
@@ -483,9 +481,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 +509,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/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/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..eb3772f47
--- /dev/null
+++ b/packages/melonjs/src/pool.ts
@@ -0,0 +1,23 @@
+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";
+import { vector3dPool } from "./math/vector3d";
+import { boundsPool } from "./physics/bounds";
+
+const pools = {
+ vector2d: vector2dPool,
+ vector3d: vector3dPool,
+ point: pointPool,
+ matrix2d: matrix2dPool,
+ matrix3d: matrix3dPool,
+ bounds: boundsPool,
+ color: colorPool,
+} 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/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 8410e5dc6..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";
@@ -35,7 +36,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";
*/
@@ -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
@@ -639,17 +640,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,
+ });
}
});
}
@@ -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/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/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 f4bcca766..b153eff08 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 { Color, colorPool } from "./../math/color.ts";
+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();
@@ -306,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);
@@ -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;
}
@@ -853,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 3562ab291..1754d7c13 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 { Color } from "../math/color.ts";
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..86c1f990c 100644
--- a/packages/melonjs/src/renderable/text/bitmaptext.js
+++ b/packages/melonjs/src/renderable/text/bitmaptext.js
@@ -1,8 +1,9 @@
-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";
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/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/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/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/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..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";
@@ -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..98e431828 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 { Color } from "./../math/color.ts";
+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..3330989a9 100644
--- a/packages/melonjs/src/video/webgl/webgl_renderer.js
+++ b/packages/melonjs/src/video/webgl/webgl_renderer.js
@@ -1,12 +1,11 @@
-import Color from "./../../math/color.js";
-import Matrix2d from "./../../math/matrix2.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";
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,
@@ -23,7 +22,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";
*/
@@ -296,10 +295,10 @@ export default class WebGLRenderer extends Renderer {
// clear all stacks
this._colorStack.forEach((color) => {
- pool.push(color);
+ colorPool.release(color);
});
this._matrixStack.forEach((matrix) => {
- pool.push(matrix);
+ matrix2dPool.release(matrix);
});
this._colorStack.length = 0;
this._matrixStack.length = 0;
@@ -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,8 +792,8 @@ export default class WebGLRenderer extends Renderer {
this.setBlendMode(this._blendStack.pop());
// recycle objects
- pool.push(color);
- pool.push(matrix);
+ colorPool.release(color);
+ matrix2dPool.release(matrix);
}
if (this._scissorStack.length !== 0) {
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);
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