diff --git a/README.md b/README.md index db00026d..9481bfdd 100644 --- a/README.md +++ b/README.md @@ -77,12 +77,22 @@ system.insert(box2); Manipulate body attributes and update the collision system: ```ts -box.setPosition(x, y); -box.setScale(scaleX, scaleY); -box.setAngle(angle); -box.setOffset({ x, y }); -system.update(); // Update the system after manipulation -box.group = group; // Immediate effect, no system.update needed +// if omitted updateNow is true +const updateNow = false; + +// teleport +box.setPosition(x, y, updateNow); +box.setScale(scaleX, scaleY, updateNow); +box.setAngle(angle, updateNow); +box.move(1, updateNow); +box.setOffset({ x, y }, updateNow); +console.log(box.dirty); // true + +box.updateBody(); // Update the body once, when all manipulations are done +console.log(box.dirty); // false + +box.group = group; // Immediate effect, no body/system update needed +console.log(box.dirty); // false ``` ### Step 5: Collision Detection and Resolution @@ -90,7 +100,11 @@ box.group = group; // Immediate effect, no system.update needed Detect collisions and respond accordingly: ```ts -if (system.checkAll()) { +if (system.checkAll(callback)) { + // Do something yourself +} + +if (system.checkOne(body, callback)) { // Do something yourself } diff --git a/dist/base-system.d.ts b/dist/base-system.d.ts index 20ac2c0f..03822b77 100644 --- a/dist/base-system.d.ts +++ b/dist/base-system.d.ts @@ -1,14 +1,14 @@ +import { Body, BodyOptions, ChildrenData, Data, InTest, Leaf, PotentialVector, RBush, TraverseFunction, Vector } from "./model"; import { Box } from "./bodies/box"; import { Circle } from "./bodies/circle"; import { Ellipse } from "./bodies/ellipse"; import { Line } from "./bodies/line"; import { Point } from "./bodies/point"; import { Polygon } from "./bodies/polygon"; -import { Body, BodyOptions, ChildrenData, Data, InTest, Leaf, PotentialVector, RBush, TraverseFunction, Vector } from "./model"; /** * very base collision system (create, insert, update, draw, remove) */ -export declare class BaseSystem extends RBush implements Data { +export declare class BaseSystem extends RBush implements Data { data: ChildrenData; /** * create point at position with options and add to system @@ -38,7 +38,7 @@ export declare class BaseSystem extends RBush * re-insert body into collision tree and update its bbox * every body can be part of only one system */ - insert(body: TBody): RBush; + insert(body: TBody): this; /** * updates body in collision tree */ @@ -58,7 +58,7 @@ export declare class BaseSystem extends RBush /** * remove body aabb from collision tree */ - remove(body: TBody, equals?: InTest): RBush; + remove(body: TBody, equals?: InTest): this; /** * get object potential colliders * @deprecated because it's slower to use than checkOne() or checkAll() diff --git a/dist/base-system.js b/dist/base-system.js index 31ab2320..725f9302 100644 --- a/dist/base-system.js +++ b/dist/base-system.js @@ -1,15 +1,15 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseSystem = void 0; +const model_1 = require("./model"); +const utils_1 = require("./utils"); +const optimized_1 = require("./optimized"); const box_1 = require("./bodies/box"); const circle_1 = require("./bodies/circle"); const ellipse_1 = require("./bodies/ellipse"); const line_1 = require("./bodies/line"); const point_1 = require("./bodies/point"); const polygon_1 = require("./bodies/polygon"); -const model_1 = require("./model"); -const optimized_1 = require("./optimized"); -const utils_1 = require("./utils"); /** * very base collision system (create, insert, update, draw, remove) */ diff --git a/dist/benchmarks/insertion.bench.js b/dist/benchmarks/insertion.bench.js index a751f7bd..6f682f7b 100644 --- a/dist/benchmarks/insertion.bench.js +++ b/dist/benchmarks/insertion.bench.js @@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.insertionBenchmark = void 0; /* tslint:disable:no-implicit-dependencies */ const tinybench_1 = require("tinybench"); -const circle_1 = require("../bodies/circle"); -const polygon_1 = require("../bodies/polygon"); -const model_1 = require("../model"); -const system_1 = require("../system"); +const circle_js_1 = require("../bodies/circle.js"); +const polygon_js_1 = require("../bodies/polygon.js"); +const model_js_1 = require("../model.js"); +const system_js_1 = require("../system.js"); const insertionBenchmark = () => { const benchmark = new tinybench_1.Bench({}); const nonoverlappingBodies = []; @@ -17,64 +17,64 @@ const insertionBenchmark = () => { const overlappingRectangles = []; const BODY_COUNT = 1000; for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - nonoverlappingBodies.push(new circle_1.Circle(new model_1.SATVector(ndx, 0), 0.25)); - overlappingBodies.push(new circle_1.Circle(new model_1.SATVector(0, 0), 0.25)); - nonoverlappingTriangles.push(new polygon_1.Polygon(new model_1.SATVector(ndx * 2, 0), [ - new model_1.SATVector(0, 0), - new model_1.SATVector(0, 1), - new model_1.SATVector(1, 0) + nonoverlappingBodies.push(new circle_js_1.Circle(new model_js_1.SATVector(ndx, 0), 0.25)); + overlappingBodies.push(new circle_js_1.Circle(new model_js_1.SATVector(0, 0), 0.25)); + nonoverlappingTriangles.push(new polygon_js_1.Polygon(new model_js_1.SATVector(ndx * 2, 0), [ + new model_js_1.SATVector(0, 0), + new model_js_1.SATVector(0, 1), + new model_js_1.SATVector(1, 0) ])); - overlappingTriangles.push(new polygon_1.Polygon(new model_1.SATVector(0, 0), [ - new model_1.SATVector(0, 0), - new model_1.SATVector(0, 1), - new model_1.SATVector(1, 0) + overlappingTriangles.push(new polygon_js_1.Polygon(new model_js_1.SATVector(0, 0), [ + new model_js_1.SATVector(0, 0), + new model_js_1.SATVector(0, 1), + new model_js_1.SATVector(1, 0) ])); - nonoverlappingRectangles.push(new polygon_1.Polygon(new model_1.SATVector(0, 0), [ - new model_1.SATVector(0, 0), - new model_1.SATVector(0, 1), - new model_1.SATVector(1, 1), - new model_1.SATVector(1, 0) + nonoverlappingRectangles.push(new polygon_js_1.Polygon(new model_js_1.SATVector(0, 0), [ + new model_js_1.SATVector(0, 0), + new model_js_1.SATVector(0, 1), + new model_js_1.SATVector(1, 1), + new model_js_1.SATVector(1, 0) ])); - overlappingRectangles.push(new polygon_1.Polygon(new model_1.SATVector(0, 0), [ - new model_1.SATVector(0, 0), - new model_1.SATVector(0, 1), - new model_1.SATVector(1, 1), - new model_1.SATVector(1, 0) + overlappingRectangles.push(new polygon_js_1.Polygon(new model_js_1.SATVector(0, 0), [ + new model_js_1.SATVector(0, 0), + new model_js_1.SATVector(0, 1), + new model_js_1.SATVector(1, 1), + new model_js_1.SATVector(1, 0) ])); } benchmark .add("non overlapping circles", () => { - const uut = new system_1.System(BODY_COUNT); + const uut = new system_js_1.System(BODY_COUNT); for (let ndx = 0; ndx < BODY_COUNT; ndx++) { uut.insert(nonoverlappingBodies[ndx]); } }) .add("overlapping circles", () => { - const uut = new system_1.System(BODY_COUNT); + const uut = new system_js_1.System(BODY_COUNT); for (let ndx = 0; ndx < BODY_COUNT; ndx++) { uut.insert(overlappingBodies[ndx]); } }) .add("non-overlapping triangles", () => { - const uut = new system_1.System(BODY_COUNT); + const uut = new system_js_1.System(BODY_COUNT); for (let ndx = 0; ndx < BODY_COUNT; ndx++) { uut.insert(nonoverlappingTriangles[ndx]); } }) .add("overlapping triangles", () => { - const uut = new system_1.System(BODY_COUNT); + const uut = new system_js_1.System(BODY_COUNT); for (let ndx = 0; ndx < BODY_COUNT; ndx++) { uut.insert(overlappingTriangles[ndx]); } }) .add("non-overlapping quad", () => { - const uut = new system_1.System(BODY_COUNT); + const uut = new system_js_1.System(BODY_COUNT); for (let ndx = 0; ndx < BODY_COUNT; ndx++) { uut.insert(nonoverlappingRectangles[ndx]); } }) .add("overlapping quad", () => { - const uut = new system_1.System(BODY_COUNT); + const uut = new system_js_1.System(BODY_COUNT); for (let ndx = 0; ndx < BODY_COUNT; ndx++) { uut.insert(overlappingRectangles[ndx]); } diff --git a/dist/benchmarks/stress.bench.js b/dist/benchmarks/stress.bench.js index dece0758..393185cd 100644 --- a/dist/benchmarks/stress.bench.js +++ b/dist/benchmarks/stress.bench.js @@ -36,7 +36,7 @@ exports.stressBenchmark = void 0; /* tslint:disable:no-implicit-dependencies variable-name no-any */ const tinybench_1 = require("tinybench"); const stressBenchmark = () => __awaiter(void 0, void 0, void 0, function* () { - const { default: Stress } = yield Promise.resolve().then(() => __importStar(require("../demo/stress"))); + const { default: Stress } = yield Promise.resolve().then(() => __importStar(require("../demo/stress.js"))); let stressTest; const benchmark = new tinybench_1.Bench({ time: 1000, diff --git a/dist/bodies/box.js b/dist/bodies/box.js index be1e1fbb..b00d2de2 100644 --- a/dist/bodies/box.js +++ b/dist/bodies/box.js @@ -2,8 +2,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Box = void 0; const model_1 = require("../model"); -const utils_1 = require("../utils"); const polygon_1 = require("./polygon"); +const utils_1 = require("../utils"); /** * collider - box */ diff --git a/dist/bodies/circle.d.ts b/dist/bodies/circle.d.ts index 427848f3..7d20ad88 100644 --- a/dist/bodies/circle.d.ts +++ b/dist/bodies/circle.d.ts @@ -1,7 +1,6 @@ -import { BBox } from "rbush"; +import { BBox, BodyGroup, BodyOptions, BodyProps, BodyType, PotentialVector, SATVector, Vector } from "../model"; import { Circle as SATCircle } from "sat"; import { System } from "../system"; -import { BodyGroup, BodyOptions, BodyProps, BodyType, PotentialVector, SATVector, Vector } from "../model"; /** * collider - circle */ @@ -121,21 +120,25 @@ export declare class Circle extends SATCircle implements BBox, BodyProps { get group(): number; set group(group: number); /** - * update position + * update position BY MOVING FORWARD IN ANGLE DIRECTION */ - setPosition(x: number, y: number, update?: boolean): Circle; + move(speed?: number, updateNow?: boolean): Circle; + /** + * update position BY TELEPORTING + */ + setPosition(x: number, y: number, updateNow?: boolean): Circle; /** * update scale */ - setScale(scaleX: number, _scaleY?: number, update?: boolean): Circle; + setScale(scaleX: number, _scaleY?: number, updateNow?: boolean): Circle; /** * set rotation */ - setAngle(angle: number, update?: boolean): Circle; + setAngle(angle: number, updateNow?: boolean): Circle; /** * set offset from center */ - setOffset(offset: Vector, update?: boolean): Circle; + setOffset(offset: Vector, updateNow?: boolean): Circle; /** * get body bounding box, without padding */ @@ -151,11 +154,11 @@ export declare class Circle extends SATCircle implements BBox, BodyProps { /** * inner function for after position change update aabb in system */ - updateBody(update?: boolean): void; + updateBody(updateNow?: boolean): void; /** * update instantly or mark as dirty */ - protected markAsDirty(update?: boolean): void; + protected markAsDirty(updateNow?: boolean): void; /** * internal for getting offset with applied angle */ diff --git a/dist/bodies/circle.js b/dist/bodies/circle.js index cafe344a..e58e7143 100644 --- a/dist/bodies/circle.js +++ b/dist/bodies/circle.js @@ -1,9 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Circle = void 0; -const sat_1 = require("sat"); const model_1 = require("../model"); const utils_1 = require("../utils"); +const sat_1 = require("sat"); /** * collider - circle */ @@ -100,43 +100,50 @@ class Circle extends sat_1.Circle { this._group = (0, utils_1.getGroup)(group); } /** - * update position + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true) { + (0, utils_1.move)(this, speed, updateNow); + return this; + } + /** + * update position BY TELEPORTING */ - setPosition(x, y, update = true) { + setPosition(x, y, updateNow = true) { this.pos.x = x; this.pos.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * update scale */ - setScale(scaleX, _scaleY = scaleX, update = true) { + setScale(scaleX, _scaleY = scaleX, updateNow = true) { this.r = this.unscaledRadius * Math.abs(scaleX); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * set rotation */ - setAngle(angle, update = true) { + setAngle(angle, updateNow = true) { this.angle = angle; const { x, y } = this.getOffsetWithAngle(); this.offset.x = x; this.offset.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * set offset from center */ - setOffset(offset, update = true) { + setOffset(offset, updateNow = true) { this.offsetCopy.x = offset.x; this.offsetCopy.y = offset.y; const { x, y } = this.getOffsetWithAngle(); this.offset.x = x; this.offset.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** @@ -185,9 +192,9 @@ class Circle extends sat_1.Circle { /** * inner function for after position change update aabb in system */ - updateBody(update = this.dirty) { + updateBody(updateNow = this.dirty) { var _a; - if (update) { + if (updateNow) { (_a = this.system) === null || _a === void 0 ? void 0 : _a.insert(this); this.dirty = false; } @@ -195,8 +202,8 @@ class Circle extends sat_1.Circle { /** * update instantly or mark as dirty */ - markAsDirty(update = false) { - if (update) { + markAsDirty(updateNow = false) { + if (updateNow) { this.updateBody(true); } else { diff --git a/dist/bodies/ellipse.js b/dist/bodies/ellipse.js index 2df107bd..81c473da 100644 --- a/dist/bodies/ellipse.js +++ b/dist/bodies/ellipse.js @@ -2,8 +2,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Ellipse = void 0; const model_1 = require("../model"); -const utils_1 = require("../utils"); const polygon_1 = require("./polygon"); +const utils_1 = require("../utils"); /** * collider - ellipse */ diff --git a/dist/bodies/line.d.ts b/dist/bodies/line.d.ts index 9ecf1d44..676169e5 100644 --- a/dist/bodies/line.d.ts +++ b/dist/bodies/line.d.ts @@ -1,6 +1,6 @@ -import { Vector as SATVector } from "sat"; import { BodyGroup, BodyOptions, BodyType, Vector } from "../model"; import { Polygon } from "./polygon"; +import { Vector as SATVector } from "sat"; /** * collider - line */ diff --git a/dist/bodies/line.js b/dist/bodies/line.js index 81af2456..c1d1eac3 100644 --- a/dist/bodies/line.js +++ b/dist/bodies/line.js @@ -1,9 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Line = void 0; -const sat_1 = require("sat"); const model_1 = require("../model"); const polygon_1 = require("./polygon"); +const sat_1 = require("sat"); /** * collider - line */ diff --git a/dist/bodies/point.js b/dist/bodies/point.js index 342d8424..9540ed92 100644 --- a/dist/bodies/point.js +++ b/dist/bodies/point.js @@ -2,8 +2,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Point = void 0; const model_1 = require("../model"); -const utils_1 = require("../utils"); const box_1 = require("./box"); +const utils_1 = require("../utils"); /** * collider - point (very tiny box) */ diff --git a/dist/bodies/polygon.d.ts b/dist/bodies/polygon.d.ts index 9e624b53..c710f90e 100644 --- a/dist/bodies/polygon.d.ts +++ b/dist/bodies/polygon.d.ts @@ -1,7 +1,6 @@ +import { BBox, BodyGroup, BodyOptions, BodyProps, BodyType, DecompPolygon, PotentialVector, SATVector, Vector } from "../model"; import { isSimple } from "poly-decomp-es"; -import { BBox } from "rbush"; import { Polygon as SATPolygon } from "sat"; -import { BodyGroup, BodyOptions, BodyProps, BodyType, DecompPolygon, PotentialVector, SATVector, Vector } from "../model"; import { System } from "../system"; export { isSimple }; /** @@ -124,15 +123,19 @@ export declare class Polygon extends SATPolygon implements BBox, BodyProps { get group(): number; set group(group: number); /** - * update position + * update position BY MOVING FORWARD IN ANGLE DIRECTION */ - setPosition(x: number, y: number, update?: boolean): SATPolygon; + move(speed?: number, updateNow?: boolean): SATPolygon; + /** + * update position BY TELEPORTING + */ + setPosition(x: number, y: number, updateNow?: boolean): SATPolygon; /** * update scale */ - setScale(x: number, y?: number, update?: boolean): SATPolygon; - setAngle(angle: number, update?: boolean): SATPolygon; - setOffset(offset: SATVector, update?: boolean): SATPolygon; + setScale(x: number, y?: number, updateNow?: boolean): SATPolygon; + setAngle(angle: number, updateNow?: boolean): SATPolygon; + setOffset(offset: SATVector, updateNow?: boolean): SATPolygon; /** * get body bounding box, without padding */ @@ -168,12 +171,12 @@ export declare class Polygon extends SATPolygon implements BBox, BodyProps { /** * inner function for after position change update aabb in system and convex inner polygons */ - updateBody(update?: boolean): void; + updateBody(updateNow?: boolean): void; protected retranslate(isCentered?: boolean): void; /** * update instantly or mark as dirty */ - protected markAsDirty(update?: boolean): void; + protected markAsDirty(updateNow?: boolean): void; /** * update the position of the decomposed convex polygons (if any), called * after the position of the body has changed diff --git a/dist/bodies/polygon.js b/dist/bodies/polygon.js index fe11e542..91c28b88 100644 --- a/dist/bodies/polygon.js +++ b/dist/bodies/polygon.js @@ -1,12 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Polygon = exports.isSimple = void 0; +const model_1 = require("../model"); +const utils_1 = require("../utils"); +const optimized_1 = require("../optimized"); const poly_decomp_es_1 = require("poly-decomp-es"); Object.defineProperty(exports, "isSimple", { enumerable: true, get: function () { return poly_decomp_es_1.isSimple; } }); const sat_1 = require("sat"); -const model_1 = require("../model"); -const optimized_1 = require("../optimized"); -const utils_1 = require("../utils"); /** * collider - polygon */ @@ -116,18 +116,25 @@ class Polygon extends sat_1.Polygon { this._group = (0, utils_1.getGroup)(group); } /** - * update position + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true) { + (0, utils_1.move)(this, speed, updateNow); + return this; + } + /** + * update position BY TELEPORTING */ - setPosition(x, y, update = true) { + setPosition(x, y, updateNow = true) { this.pos.x = x; this.pos.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * update scale */ - setScale(x, y = x, update = true) { + setScale(x, y = x, updateNow = true) { this.scaleVector.x = Math.abs(x); this.scaleVector.y = Math.abs(y); super.setPoints((0, optimized_1.map)(this.points, (point, index) => { @@ -135,17 +142,17 @@ class Polygon extends sat_1.Polygon { point.y = this.pointsBackup[index].y * this.scaleVector.y; return point; })); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } - setAngle(angle, update = true) { + setAngle(angle, updateNow = true) { super.setAngle(angle); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } - setOffset(offset, update = true) { + setOffset(offset, updateNow = true) { super.setOffset(offset); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** @@ -223,9 +230,9 @@ class Polygon extends sat_1.Polygon { /** * inner function for after position change update aabb in system and convex inner polygons */ - updateBody(update = this.dirty) { + updateBody(updateNow = this.dirty) { var _a; - if (update) { + if (updateNow) { this.updateConvexPolygonPositions(); (_a = this.system) === null || _a === void 0 ? void 0 : _a.insert(this); this.dirty = false; @@ -242,8 +249,8 @@ class Polygon extends sat_1.Polygon { /** * update instantly or mark as dirty */ - markAsDirty(update = false) { - if (update) { + markAsDirty(updateNow = false) { + if (updateNow) { this.updateBody(true); } else { diff --git a/dist/demo/demo.js b/dist/demo/demo.js index e315e139..1678a7a2 100644 --- a/dist/demo/demo.js +++ b/dist/demo/demo.js @@ -1,10 +1,10 @@ /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ -/***/ "./node_modules/.pnpm/json-stringify-safe@5.0.1/node_modules/json-stringify-safe/stringify.js": -/*!****************************************************************************************************!*\ - !*** ./node_modules/.pnpm/json-stringify-safe@5.0.1/node_modules/json-stringify-safe/stringify.js ***! - \****************************************************************************************************/ +/***/ "./node_modules/json-stringify-safe/stringify.js": +/*!*******************************************************!*\ + !*** ./node_modules/json-stringify-safe/stringify.js ***! + \*******************************************************/ /***/ ((module, exports) => { exports = module.exports = stringify @@ -38,10 +38,10 @@ function serializer(replacer, cycleReplacer) { /***/ }), -/***/ "./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js": -/*!****************************************************************************************************!*\ - !*** ./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js ***! - \****************************************************************************************************/ +/***/ "./node_modules/poly-decomp-es/dist/poly-decomp-es.js": +/*!************************************************************!*\ + !*** ./node_modules/poly-decomp-es/dist/poly-decomp-es.js ***! + \************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; @@ -694,10 +694,79 @@ function removeDuplicatePoints(polygon, precision) { /***/ }), -/***/ "./node_modules/.pnpm/random-seed@0.3.0/node_modules/random-seed/index.js": -/*!********************************************************************************!*\ - !*** ./node_modules/.pnpm/random-seed@0.3.0/node_modules/random-seed/index.js ***! - \********************************************************************************/ +/***/ "./node_modules/quickselect/index.js": +/*!*******************************************!*\ + !*** ./node_modules/quickselect/index.js ***! + \*******************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ quickselect) +/* harmony export */ }); + +function quickselect(arr, k, left, right, compare) { + quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare); +} + +function quickselectStep(arr, k, left, right, compare) { + + while (right > left) { + if (right - left > 600) { + var n = right - left + 1; + var m = k - left + 1; + var z = Math.log(n); + var s = 0.5 * Math.exp(2 * z / 3); + var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); + var newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); + var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); + quickselectStep(arr, k, newLeft, newRight, compare); + } + + var t = arr[k]; + var i = left; + var j = right; + + swap(arr, left, k); + if (compare(arr[right], t) > 0) swap(arr, left, right); + + while (i < j) { + swap(arr, i, j); + i++; + j--; + while (compare(arr[i], t) < 0) i++; + while (compare(arr[j], t) > 0) j--; + } + + if (compare(arr[left], t) === 0) swap(arr, left, j); + else { + j++; + swap(arr, j, right); + } + + if (j <= k) left = j + 1; + if (k <= j) right = j - 1; + } +} + +function swap(arr, i, j) { + var tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} + + +/***/ }), + +/***/ "./node_modules/random-seed/index.js": +/*!*******************************************!*\ + !*** ./node_modules/random-seed/index.js ***! + \*******************************************/ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; @@ -755,7 +824,7 @@ function removeDuplicatePoints(polygon, precision) { 1460910 and 1768863. (We use the largest one that's < 2^21) ============================================================================ */ -var stringify = __webpack_require__(/*! json-stringify-safe */ "./node_modules/.pnpm/json-stringify-safe@5.0.1/node_modules/json-stringify-safe/stringify.js"); +var stringify = __webpack_require__(/*! json-stringify-safe */ "./node_modules/json-stringify-safe/stringify.js"); /* ============================================================================ This is based upon Johannes Baagoe's carefully designed and efficient hash @@ -973,21 +1042,10 @@ module.exports = uheprng; /***/ }), -/***/ "./node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/rbush.min.js": -/*!************************************************************************!*\ - !*** ./node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/rbush.min.js ***! - \************************************************************************/ -/***/ (function(module) { - -!function(t,i){ true?module.exports=i():0}(this,function(){"use strict";function t(t,r,e,a,h){!function t(n,r,e,a,h){for(;a>e;){if(a-e>600){var o=a-e+1,s=r-e+1,l=Math.log(o),f=.5*Math.exp(2*l/3),u=.5*Math.sqrt(l*f*(o-f)/o)*(s-o/2<0?-1:1),m=Math.max(e,Math.floor(r-s*f/o+u)),c=Math.min(a,Math.floor(r+(o-s)*f/o+u));t(n,r,m,c,h)}var p=n[r],d=e,x=a;for(i(n,e,r),h(n[a],p)>0&&i(n,e,a);d0;)x--}0===h(n[e],p)?i(n,e,x):i(n,++x,a),x<=r&&(e=x+1),r<=x&&(a=x-1)}}(t,r,e||0,a||t.length-1,h||n)}function i(t,i,n){var r=t[i];t[i]=t[n],t[n]=r}function n(t,i){return ti?1:0}var r=function(t){void 0===t&&(t=9),this._maxEntries=Math.max(4,t),this._minEntries=Math.max(2,Math.ceil(.4*this._maxEntries)),this.clear()};function e(t,i,n){if(!n)return i.indexOf(t);for(var r=0;r=t.minX&&i.maxY>=t.minY}function p(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function d(i,n,r,e,a){for(var h=[n,r];h.length;)if(!((r=h.pop())-(n=h.pop())<=e)){var o=n+Math.ceil((r-n)/e/2)*e;t(i,o,n,r,a),h.push(n,o,o,r)}}return r.prototype.all=function(){return this._all(this.data,[])},r.prototype.search=function(t){var i=this.data,n=[];if(!c(t,i))return n;for(var r=this.toBBox,e=[];i;){for(var a=0;a=0&&e[i].children.length>this._maxEntries;)this._split(e,i),i--;this._adjustParentBBoxes(r,e,i)},r.prototype._split=function(t,i){var n=t[i],r=n.children.length,e=this._minEntries;this._chooseSplitAxis(n,e,r);var h=this._chooseSplitIndex(n,e,r),o=p(n.children.splice(h,n.children.length-h));o.height=n.height,o.leaf=n.leaf,a(n,this.toBBox),a(o,this.toBBox),i?t[i-1].children.push(o):this._splitRoot(n,o)},r.prototype._splitRoot=function(t,i){this.data=p([t,i]),this.data.height=t.height+1,this.data.leaf=!1,a(this.data,this.toBBox)},r.prototype._chooseSplitIndex=function(t,i,n){for(var r,e,a,o,s,l,u,m=1/0,c=1/0,p=i;p<=n-i;p++){var d=h(t,0,p,this.toBBox),x=h(t,p,n,this.toBBox),v=(e=d,a=x,o=void 0,s=void 0,l=void 0,u=void 0,o=Math.max(e.minX,a.minX),s=Math.max(e.minY,a.minY),l=Math.min(e.maxX,a.maxX),u=Math.min(e.maxY,a.maxY),Math.max(0,l-o)*Math.max(0,u-s)),M=f(d)+f(x);v=i;c--){var p=t.children[c];o(s,t.leaf?e(p):p),l+=u(s)}return l},r.prototype._adjustParentBBoxes=function(t,i,n){for(var r=n;r>=0;r--)o(i[r],t)},r.prototype._condense=function(t){for(var i=t.length-1,n=void 0;i>=0;i--)0===t[i].children.length?i>0?(n=t[i-1].children).splice(n.indexOf(t[i]),1):this.clear():a(t[i],this.toBBox)},r}); - - -/***/ }), - -/***/ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js": -/*!**************************************************************!*\ - !*** ./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js ***! - \**************************************************************/ +/***/ "./node_modules/sat/SAT.js": +/*!*********************************!*\ + !*** ./node_modules/sat/SAT.js ***! + \*********************************/ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Version 0.9.0 - Copyright 2012 - 2021 - Jim Riecken @@ -2062,15 +2120,15 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Version 0.9 Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BaseSystem = void 0; +const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); +const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); +const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); const box_1 = __webpack_require__(/*! ./bodies/box */ "./src/bodies/box.ts"); const circle_1 = __webpack_require__(/*! ./bodies/circle */ "./src/bodies/circle.ts"); const ellipse_1 = __webpack_require__(/*! ./bodies/ellipse */ "./src/bodies/ellipse.ts"); const line_1 = __webpack_require__(/*! ./bodies/line */ "./src/bodies/line.ts"); const point_1 = __webpack_require__(/*! ./bodies/point */ "./src/bodies/point.ts"); const polygon_1 = __webpack_require__(/*! ./bodies/polygon */ "./src/bodies/polygon.ts"); -const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); -const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); -const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); /** * very base collision system (create, insert, update, draw, remove) */ @@ -2228,8 +2286,8 @@ exports.BaseSystem = BaseSystem; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Box = void 0; const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); -const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); const polygon_1 = __webpack_require__(/*! ./polygon */ "./src/bodies/polygon.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); /** * collider - box */ @@ -2315,9 +2373,9 @@ exports.Box = Box; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Circle = void 0; -const sat_1 = __webpack_require__(/*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js"); const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); /** * collider - circle */ @@ -2414,43 +2472,50 @@ class Circle extends sat_1.Circle { this._group = (0, utils_1.getGroup)(group); } /** - * update position + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true) { + (0, utils_1.move)(this, speed, updateNow); + return this; + } + /** + * update position BY TELEPORTING */ - setPosition(x, y, update = true) { + setPosition(x, y, updateNow = true) { this.pos.x = x; this.pos.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * update scale */ - setScale(scaleX, _scaleY = scaleX, update = true) { + setScale(scaleX, _scaleY = scaleX, updateNow = true) { this.r = this.unscaledRadius * Math.abs(scaleX); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * set rotation */ - setAngle(angle, update = true) { + setAngle(angle, updateNow = true) { this.angle = angle; const { x, y } = this.getOffsetWithAngle(); this.offset.x = x; this.offset.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * set offset from center */ - setOffset(offset, update = true) { + setOffset(offset, updateNow = true) { this.offsetCopy.x = offset.x; this.offsetCopy.y = offset.y; const { x, y } = this.getOffsetWithAngle(); this.offset.x = x; this.offset.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** @@ -2499,9 +2564,9 @@ class Circle extends sat_1.Circle { /** * inner function for after position change update aabb in system */ - updateBody(update = this.dirty) { + updateBody(updateNow = this.dirty) { var _a; - if (update) { + if (updateNow) { (_a = this.system) === null || _a === void 0 ? void 0 : _a.insert(this); this.dirty = false; } @@ -2509,8 +2574,8 @@ class Circle extends sat_1.Circle { /** * update instantly or mark as dirty */ - markAsDirty(update = false) { - if (update) { + markAsDirty(updateNow = false) { + if (updateNow) { this.updateBody(true); } else { @@ -2547,8 +2612,8 @@ exports.Circle = Circle; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Ellipse = void 0; const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); -const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); const polygon_1 = __webpack_require__(/*! ./polygon */ "./src/bodies/polygon.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); /** * collider - ellipse */ @@ -2651,9 +2716,9 @@ exports.Ellipse = Ellipse; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Line = void 0; -const sat_1 = __webpack_require__(/*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js"); const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); const polygon_1 = __webpack_require__(/*! ./polygon */ "./src/bodies/polygon.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); /** * collider - line */ @@ -2730,8 +2795,8 @@ exports.Line = Line; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Point = void 0; const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); -const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); const box_1 = __webpack_require__(/*! ./box */ "./src/bodies/box.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); /** * collider - point (very tiny box) */ @@ -2766,12 +2831,12 @@ exports.Point = Point; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Polygon = exports.isSimple = void 0; -const poly_decomp_es_1 = __webpack_require__(/*! poly-decomp-es */ "./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js"); -Object.defineProperty(exports, "isSimple", ({ enumerable: true, get: function () { return poly_decomp_es_1.isSimple; } })); -const sat_1 = __webpack_require__(/*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js"); const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); -const optimized_1 = __webpack_require__(/*! ../optimized */ "./src/optimized.ts"); const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +const optimized_1 = __webpack_require__(/*! ../optimized */ "./src/optimized.ts"); +const poly_decomp_es_1 = __webpack_require__(/*! poly-decomp-es */ "./node_modules/poly-decomp-es/dist/poly-decomp-es.js"); +Object.defineProperty(exports, "isSimple", ({ enumerable: true, get: function () { return poly_decomp_es_1.isSimple; } })); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); /** * collider - polygon */ @@ -2881,18 +2946,25 @@ class Polygon extends sat_1.Polygon { this._group = (0, utils_1.getGroup)(group); } /** - * update position + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true) { + (0, utils_1.move)(this, speed, updateNow); + return this; + } + /** + * update position BY TELEPORTING */ - setPosition(x, y, update = true) { + setPosition(x, y, updateNow = true) { this.pos.x = x; this.pos.y = y; - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** * update scale */ - setScale(x, y = x, update = true) { + setScale(x, y = x, updateNow = true) { this.scaleVector.x = Math.abs(x); this.scaleVector.y = Math.abs(y); super.setPoints((0, optimized_1.map)(this.points, (point, index) => { @@ -2900,17 +2972,17 @@ class Polygon extends sat_1.Polygon { point.y = this.pointsBackup[index].y * this.scaleVector.y; return point; })); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } - setAngle(angle, update = true) { + setAngle(angle, updateNow = true) { super.setAngle(angle); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } - setOffset(offset, update = true) { + setOffset(offset, updateNow = true) { super.setOffset(offset); - this.markAsDirty(update); + this.markAsDirty(updateNow); return this; } /** @@ -2988,9 +3060,9 @@ class Polygon extends sat_1.Polygon { /** * inner function for after position change update aabb in system and convex inner polygons */ - updateBody(update = this.dirty) { + updateBody(updateNow = this.dirty) { var _a; - if (update) { + if (updateNow) { this.updateConvexPolygonPositions(); (_a = this.system) === null || _a === void 0 ? void 0 : _a.insert(this); this.dirty = false; @@ -3007,8 +3079,8 @@ class Polygon extends sat_1.Polygon { /** * update instantly or mark as dirty */ - markAsDirty(update = false) { - if (update) { + markAsDirty(updateNow = false) { + if (updateNow) { this.updateBody(true); } else { @@ -3091,10 +3163,21 @@ exports.Polygon = Polygon; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.intersectLinePolygon = exports.intersectLineLine = exports.intersectLineLineFast = exports.intersectLineCircle = exports.circleOutsidePolygon = exports.circleInPolygon = exports.circleInCircle = exports.pointOnCircle = exports.polygonInPolygon = exports.pointInPolygon = exports.polygonInCircle = exports.ensureConvex = void 0; -const sat_1 = __webpack_require__(/*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js"); +exports.ensureConvex = ensureConvex; +exports.polygonInCircle = polygonInCircle; +exports.pointInPolygon = pointInPolygon; +exports.polygonInPolygon = polygonInPolygon; +exports.pointOnCircle = pointOnCircle; +exports.circleInCircle = circleInCircle; +exports.circleInPolygon = circleInPolygon; +exports.circleOutsidePolygon = circleOutsidePolygon; +exports.intersectLineCircle = intersectLineCircle; +exports.intersectLineLineFast = intersectLineLineFast; +exports.intersectLineLine = intersectLineLine; +exports.intersectLinePolygon = intersectLinePolygon; const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); /** * replace body with array of related convex polygons */ @@ -3104,19 +3187,15 @@ function ensureConvex(body) { } return body.convexPolygons; } -exports.ensureConvex = ensureConvex; function polygonInCircle(polygon, circle) { return (0, optimized_1.every)(polygon.calcPoints, p => (0, sat_1.pointInCircle)({ x: p.x + polygon.pos.x, y: p.y + polygon.pos.y }, circle)); } -exports.polygonInCircle = polygonInCircle; function pointInPolygon(point, polygon) { return (0, optimized_1.some)(ensureConvex(polygon), convex => (0, sat_1.pointInPolygon)(point, convex)); } -exports.pointInPolygon = pointInPolygon; function polygonInPolygon(polygonA, polygonB) { return (0, optimized_1.every)(polygonA.calcPoints, point => pointInPolygon({ x: point.x + polygonA.pos.x, y: point.y + polygonA.pos.y }, polygonB)); } -exports.polygonInPolygon = polygonInPolygon; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -3125,7 +3204,6 @@ function pointOnCircle(point, circle) { (point.y - circle.pos.y) * (point.y - circle.pos.y) === circle.r * circle.r); } -exports.pointOnCircle = pointOnCircle; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -3139,7 +3217,6 @@ function circleInCircle(bodyA, bodyB) { const distSq = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); return distSq + r2 === r1 || distSq + r2 < r1; } -exports.circleInCircle = circleInCircle; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -3178,7 +3255,6 @@ function circleInPolygon(circle, polygon) { } return true; } -exports.circleInPolygon = circleInPolygon; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -3217,7 +3293,6 @@ function circleOutsidePolygon(circle, polygon) { } return true; } -exports.circleOutsidePolygon = circleOutsidePolygon; /** * https://stackoverflow.com/a/37225895/1749528 */ @@ -3244,7 +3319,6 @@ function intersectLineCircle(line, { pos, r }) { } return results; } -exports.intersectLineCircle = intersectLineCircle; /** * helper for intersectLineLineFast */ @@ -3263,7 +3337,6 @@ function intersectLineLineFast(line1, line2) { isTurn(line1.start, line1.end, line2.start) !== isTurn(line1.start, line1.end, line2.end)); } -exports.intersectLineLineFast = intersectLineLineFast; /** * returns the point of intersection * https://stackoverflow.com/a/24392281/1749528 @@ -3287,7 +3360,6 @@ function intersectLineLine(line1, line2) { } return { x: line1.start.x + lambda * dX, y: line1.start.y + lambda * dY }; } -exports.intersectLineLine = intersectLineLine; function intersectLinePolygon(line, polygon) { const results = []; (0, optimized_1.forEach)(polygon.calcPoints, (to, index) => { @@ -3305,7 +3377,6 @@ function intersectLinePolygon(line, polygon) { }); return results; } -exports.intersectLinePolygon = intersectLinePolygon; /***/ }), @@ -3323,14 +3394,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BodyGroup = exports.BodyType = exports.SATCircle = exports.SATPolygon = exports.SATVector = exports.Response = exports.RBush = exports.isSimple = void 0; -const rbush_1 = __importDefault(__webpack_require__(/*! rbush */ "./node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/rbush.min.js")); -Object.defineProperty(exports, "RBush", ({ enumerable: true, get: function () { return rbush_1.default; } })); -const sat_1 = __webpack_require__(/*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); Object.defineProperty(exports, "SATCircle", ({ enumerable: true, get: function () { return sat_1.Circle; } })); Object.defineProperty(exports, "SATPolygon", ({ enumerable: true, get: function () { return sat_1.Polygon; } })); Object.defineProperty(exports, "Response", ({ enumerable: true, get: function () { return sat_1.Response; } })); Object.defineProperty(exports, "SATVector", ({ enumerable: true, get: function () { return sat_1.Vector; } })); -var poly_decomp_es_1 = __webpack_require__(/*! poly-decomp-es */ "./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js"); +// version 4.0.0 1=1 copy +const rbush_1 = __importDefault(__webpack_require__(/*! ./rbush */ "./src/rbush.js")); +exports.RBush = rbush_1.default; +var poly_decomp_es_1 = __webpack_require__(/*! poly-decomp-es */ "./node_modules/poly-decomp-es/dist/poly-decomp-es.js"); Object.defineProperty(exports, "isSimple", ({ enumerable: true, get: function () { return poly_decomp_es_1.isSimple; } })); /** * types @@ -3343,7 +3415,7 @@ var BodyType; BodyType["Box"] = "Box"; BodyType["Line"] = "Line"; BodyType["Point"] = "Point"; -})(BodyType = exports.BodyType || (exports.BodyType = {})); +})(BodyType || (exports.BodyType = BodyType = {})); /** * for groups */ @@ -3355,7 +3427,7 @@ var BodyGroup; BodyGroup[BodyGroup["Box"] = 4] = "Box"; BodyGroup[BodyGroup["Line"] = 2] = "Line"; BodyGroup[BodyGroup["Point"] = 1] = "Point"; -})(BodyGroup = exports.BodyGroup || (exports.BodyGroup = {})); +})(BodyGroup || (exports.BodyGroup = BodyGroup = {})); /***/ }), @@ -3453,12 +3525,12 @@ exports.map = map; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.System = void 0; -const base_system_1 = __webpack_require__(/*! ./base-system */ "./src/base-system.ts"); -const line_1 = __webpack_require__(/*! ./bodies/line */ "./src/bodies/line.ts"); -const intersect_1 = __webpack_require__(/*! ./intersect */ "./src/intersect.ts"); const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); -const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); +const intersect_1 = __webpack_require__(/*! ./intersect */ "./src/intersect.ts"); +const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); +const base_system_1 = __webpack_require__(/*! ./base-system */ "./src/base-system.ts"); +const line_1 = __webpack_require__(/*! ./bodies/line */ "./src/bodies/line.ts"); /** * collision system */ @@ -3545,7 +3617,7 @@ class System extends base_system_1.BaseSystem { */ checkCollision(bodyA, bodyB, response = this.response) { const { bbox: bboxA } = bodyA; - const { bbox: bboxB } = bodyA; + const { bbox: bboxB } = bodyB; // assess the bodies real aabb without padding if (!(0, utils_1.canInteract)(bodyA, bodyB) || !bboxA || @@ -3637,10 +3709,39 @@ exports.System = System; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.groupBits = exports.ensureNumber = exports.bin2dec = exports.getGroup = exports.returnTrue = exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.dashLineTo = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.clonePointsArray = exports.checkAInB = exports.canInteract = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; -const sat_1 = __webpack_require__(/*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js"); -const intersect_1 = __webpack_require__(/*! ./intersect */ "./src/intersect.ts"); +exports.RAD2DEG = exports.DEG2RAD = void 0; +exports.deg2rad = deg2rad; +exports.rad2deg = rad2deg; +exports.createEllipse = createEllipse; +exports.createBox = createBox; +exports.ensureVectorPoint = ensureVectorPoint; +exports.ensurePolygonPoints = ensurePolygonPoints; +exports.distance = distance; +exports.clockwise = clockwise; +exports.extendBody = extendBody; +exports.bodyMoved = bodyMoved; +exports.notIntersectAABB = notIntersectAABB; +exports.intersectAABB = intersectAABB; +exports.canInteract = canInteract; +exports.checkAInB = checkAInB; +exports.clonePointsArray = clonePointsArray; +exports.mapVectorToArray = mapVectorToArray; +exports.mapArrayToVector = mapArrayToVector; +exports.getBounceDirection = getBounceDirection; +exports.getSATTest = getSATTest; +exports.dashLineTo = dashLineTo; +exports.drawPolygon = drawPolygon; +exports.drawBVH = drawBVH; +exports.cloneResponse = cloneResponse; +exports.returnTrue = returnTrue; +exports.getGroup = getGroup; +exports.bin2dec = bin2dec; +exports.ensureNumber = ensureNumber; +exports.groupBits = groupBits; +exports.move = move; const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); +const intersect_1 = __webpack_require__(/*! ./intersect */ "./src/intersect.ts"); const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); /* helpers for faster getSATTest() and checkAInB() */ const testMap = { @@ -3670,14 +3771,12 @@ exports.RAD2DEG = 180 / Math.PI; function deg2rad(degrees) { return degrees * exports.DEG2RAD; } -exports.deg2rad = deg2rad; /** * convert from radians to degrees */ function rad2deg(radians) { return radians * exports.RAD2DEG; } -exports.rad2deg = rad2deg; /** * creates ellipse-shaped polygon based on params */ @@ -3693,7 +3792,6 @@ function createEllipse(radiusX, radiusY = radiusX, step = 1) { } return ellipse; } -exports.createEllipse = createEllipse; /** * creates box shaped polygon points */ @@ -3705,7 +3803,6 @@ function createBox(width, height) { new sat_1.Vector(0, height) ]; } -exports.createBox = createBox; /** * ensure SATVector type point result */ @@ -3714,7 +3811,6 @@ function ensureVectorPoint(point = {}) { ? point : new sat_1.Vector(point.x || 0, point.y || 0); } -exports.ensureVectorPoint = ensureVectorPoint; /** * ensure Vector points (for polygon) in counter-clockwise order */ @@ -3722,7 +3818,6 @@ function ensurePolygonPoints(points = []) { const polygonPoints = (0, optimized_1.map)(points, ensureVectorPoint); return clockwise(polygonPoints) ? polygonPoints.reverse() : polygonPoints; } -exports.ensurePolygonPoints = ensurePolygonPoints; /** * get distance between two Vector points */ @@ -3731,7 +3826,6 @@ function distance(bodyA, bodyB) { const yDiff = bodyA.y - bodyB.y; return Math.hypot(xDiff, yDiff); } -exports.distance = distance; /** * check [is clockwise] direction of polygon */ @@ -3744,7 +3838,6 @@ function clockwise(points) { }); return sum > 0; } -exports.clockwise = clockwise; /** * used for all types of bodies in constructor */ @@ -3758,7 +3851,6 @@ function extendBody(body, options = {}) { } body.setAngle(options.angle || 0); } -exports.extendBody = extendBody; /** * check if body moved outside of its padding */ @@ -3766,7 +3858,6 @@ function bodyMoved(body) { const { bbox, minX, minY, maxX, maxY } = body; return (bbox.minX < minX || bbox.minY < minY || bbox.maxX > maxX || bbox.maxY > maxY); } -exports.bodyMoved = bodyMoved; /** * returns true if two boxes not intersect */ @@ -3776,14 +3867,12 @@ function notIntersectAABB(bodyA, bodyB) { bodyB.maxX < bodyA.minX || bodyB.maxY < bodyA.minY); } -exports.notIntersectAABB = notIntersectAABB; /** * checks if two boxes intersect */ function intersectAABB(bodyA, bodyB) { return !notIntersectAABB(bodyA, bodyB); } -exports.intersectAABB = intersectAABB; /** * checks if two bodies can interact (for collision filtering) */ @@ -3791,7 +3880,6 @@ function canInteract(bodyA, bodyB) { return (((bodyA.group >> 16) & (bodyB.group & 0xFFFF) && (bodyB.group >> 16) & (bodyA.group & 0xFFFF)) !== 0); } -exports.canInteract = canInteract; /** * checks if body a is in body b */ @@ -3801,28 +3889,24 @@ function checkAInB(bodyA, bodyB) { : polygonInFunctions; return check[bodyB.type](bodyA, bodyB); } -exports.checkAInB = checkAInB; /** * clone sat vector points array into vector points array */ function clonePointsArray(points) { return (0, optimized_1.map)(points, ({ x, y }) => ({ x, y })); } -exports.clonePointsArray = clonePointsArray; /** * change format from SAT.js to poly-decomp */ function mapVectorToArray({ x, y } = { x: 0, y: 0 }) { return [x, y]; } -exports.mapVectorToArray = mapVectorToArray; /** * change format from poly-decomp to SAT.js */ function mapArrayToVector([x, y] = [0, 0]) { return { x, y }; } -exports.mapArrayToVector = mapArrayToVector; /** * given 2 bodies calculate vector of bounce assuming equal mass and they are circles */ @@ -3832,7 +3916,6 @@ function getBounceDirection(body, collider) { const len = v1.dot(v2.normalize()) * 2; return new sat_1.Vector(v2.x * len - v1.x, v2.y * len - v1.y).normalize(); } -exports.getBounceDirection = getBounceDirection; /** * returns correct sat.js testing function based on body types */ @@ -3842,7 +3925,6 @@ function getSATTest(bodyA, bodyB) { : polygonSATFunctions; return check[bodyB.type]; } -exports.getSATTest = getSATTest; /** * draws dashed line on canvas context */ @@ -3864,7 +3946,6 @@ function dashLineTo(context, fromX, fromY, toX, toY, dash = 2, gap = 4) { dist -= dash + gap; } } -exports.dashLineTo = dashLineTo; /** * draw polygon */ @@ -3890,7 +3971,6 @@ function drawPolygon(context, { pos, calcPoints }, isTrigger = false) { } }); } -exports.drawPolygon = drawPolygon; /** * draw body bounding body box */ @@ -3900,7 +3980,6 @@ function drawBVH(context, body) { calcPoints: createBox(body.maxX - body.minX, body.maxY - body.minY) }); } -exports.drawBVH = drawBVH; /** * clone response object returning new response with previous ones values */ @@ -3916,28 +3995,24 @@ function cloneResponse(response) { clone.bInA = bInA; return clone; } -exports.cloneResponse = cloneResponse; /** * dummy fn used as default, for optimization */ function returnTrue() { return true; } -exports.returnTrue = returnTrue; /** * for groups */ function getGroup(group) { return Math.max(0, Math.min(group, 0x7FFFFFFF)); } -exports.getGroup = getGroup; /** * binary string to decimal number */ function bin2dec(binary) { return Number(`0b${binary}`.replace(/\s/g, "")); } -exports.bin2dec = bin2dec; /** * helper for groupBits() * @@ -3946,7 +4021,6 @@ exports.bin2dec = bin2dec; function ensureNumber(input) { return typeof input === "number" ? input : bin2dec(input); } -exports.ensureNumber = ensureNumber; /** * create group bits from category and mask * @@ -3956,7 +4030,14 @@ exports.ensureNumber = ensureNumber; function groupBits(category, mask = category) { return (ensureNumber(category) << 16) | ensureNumber(mask); } -exports.groupBits = groupBits; +function move(body, speed = 1, updateNow = true) { + if (!speed) { + return; + } + const moveX = Math.cos(body.angle) * speed; + const moveY = Math.sin(body.angle) * speed; + body.setPosition(body.x + moveX, body.y + moveY, updateNow); +} /***/ }), @@ -4074,7 +4155,7 @@ const { BodyGroup } = __webpack_require__(/*! ../model */ "./src/model.ts"); const { System } = __webpack_require__(/*! ../system */ "./src/system.ts"); const { getBounceDirection, groupBits } = __webpack_require__(/*! ../utils */ "./src/utils.ts"); const { width, height, loop } = __webpack_require__(/*! ./canvas */ "./src/demo/canvas.js"); -const seededRandom = (__webpack_require__(/*! random-seed */ "./node_modules/.pnpm/random-seed@0.3.0/node_modules/random-seed/index.js").create)("@Prozi").random; +const seededRandom = (__webpack_require__(/*! random-seed */ "./node_modules/random-seed/index.js").create)("@Prozi").random; function random(min, max) { return Math.floor(seededRandom() * max) + min; @@ -4588,7 +4669,7 @@ class Tank { return this.physics.createPolygon( { x: this.scaleX(x), y: this.scaleY(y) }, scaledPoints, - { angle }, + { angle, isStatic: true }, ); } @@ -4726,6 +4807,534 @@ class Tank { module.exports = Tank; +/***/ }), + +/***/ "./src/rbush.js": +/*!**********************!*\ + !*** ./src/rbush.js ***! + \**********************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ RBush) +/* harmony export */ }); +/* harmony import */ var quickselect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! quickselect */ "./node_modules/quickselect/index.js"); + + +class RBush { + constructor(maxEntries = 9) { + // max entries in a node is 9 by default; min node fill is 40% for best performance + this._maxEntries = Math.max(4, maxEntries); + this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); + this.clear(); + } + + all() { + return this._all(this.data, []); + } + + search(bbox) { + let node = this.data; + const result = []; + + if (!intersects(bbox, node)) return result; + + const toBBox = this.toBBox; + const nodesToSearch = []; + + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? toBBox(child) : child; + + if (intersects(bbox, childBBox)) { + if (node.leaf) result.push(child); + else if (contains(bbox, childBBox)) this._all(child, result); + else nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + + return result; + } + + collides(bbox) { + let node = this.data; + + if (!intersects(bbox, node)) return false; + + const nodesToSearch = []; + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? this.toBBox(child) : child; + + if (intersects(bbox, childBBox)) { + if (node.leaf || contains(bbox, childBBox)) return true; + nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + + return false; + } + + load(data) { + if (!(data && data.length)) return this; + + if (data.length < this._minEntries) { + for (let i = 0; i < data.length; i++) { + this.insert(data[i]); + } + return this; + } + + // recursively build the tree with the given data from scratch using OMT algorithm + let node = this._build(data.slice(), 0, data.length - 1, 0); + + if (!this.data.children.length) { + // save as is if tree is empty + this.data = node; + + } else if (this.data.height === node.height) { + // split root if trees have the same height + this._splitRoot(this.data, node); + + } else { + if (this.data.height < node.height) { + // swap trees if inserted one is bigger + const tmpNode = this.data; + this.data = node; + node = tmpNode; + } + + // insert the small tree into the large tree at appropriate level + this._insert(node, this.data.height - node.height - 1, true); + } + + return this; + } + + insert(item) { + if (item) this._insert(item, this.data.height - 1); + return this; + } + + clear() { + this.data = createNode([]); + return this; + } + + remove(item, equalsFn) { + if (!item) return this; + + let node = this.data; + const bbox = this.toBBox(item); + const path = []; + const indexes = []; + let i, parent, goingUp; + + // depth-first iterative tree traversal + while (node || path.length) { + + if (!node) { // go up + node = path.pop(); + parent = path[path.length - 1]; + i = indexes.pop(); + goingUp = true; + } + + if (node.leaf) { // check current node + const index = findItem(item, node.children, equalsFn); + + if (index !== -1) { + // item found, remove the item and condense tree upwards + node.children.splice(index, 1); + path.push(node); + this._condense(path); + return this; + } + } + + if (!goingUp && !node.leaf && contains(node, bbox)) { // go down + path.push(node); + indexes.push(i); + i = 0; + parent = node; + node = node.children[0]; + + } else if (parent) { // go right + i++; + node = parent.children[i]; + goingUp = false; + + } else node = null; // nothing found + } + + return this; + } + + toBBox(item) { return item; } + + compareMinX(a, b) { return a.minX - b.minX; } + compareMinY(a, b) { return a.minY - b.minY; } + + toJSON() { return this.data; } + + fromJSON(data) { + this.data = data; + return this; + } + + _all(node, result) { + const nodesToSearch = []; + while (node) { + if (node.leaf) result.push(...node.children); + else nodesToSearch.push(...node.children); + + node = nodesToSearch.pop(); + } + return result; + } + + _build(items, left, right, height) { + + const N = right - left + 1; + let M = this._maxEntries; + let node; + + if (N <= M) { + // reached leaf level; return leaf + node = createNode(items.slice(left, right + 1)); + calcBBox(node, this.toBBox); + return node; + } + + if (!height) { + // target height of the bulk-loaded tree + height = Math.ceil(Math.log(N) / Math.log(M)); + + // target number of root entries to maximize storage utilization + M = Math.ceil(N / Math.pow(M, height - 1)); + } + + node = createNode([]); + node.leaf = false; + node.height = height; + + // split the items into M mostly square tiles + + const N2 = Math.ceil(N / M); + const N1 = N2 * Math.ceil(Math.sqrt(M)); + + multiSelect(items, left, right, N1, this.compareMinX); + + for (let i = left; i <= right; i += N1) { + + const right2 = Math.min(i + N1 - 1, right); + + multiSelect(items, i, right2, N2, this.compareMinY); + + for (let j = i; j <= right2; j += N2) { + + const right3 = Math.min(j + N2 - 1, right2); + + // pack each entry recursively + node.children.push(this._build(items, j, right3, height - 1)); + } + } + + calcBBox(node, this.toBBox); + + return node; + } + + _chooseSubtree(bbox, node, level, path) { + while (true) { + path.push(node); + + if (node.leaf || path.length - 1 === level) break; + + let minArea = Infinity; + let minEnlargement = Infinity; + let targetNode; + + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const area = bboxArea(child); + const enlargement = enlargedArea(bbox, child) - area; + + // choose entry with the least area enlargement + if (enlargement < minEnlargement) { + minEnlargement = enlargement; + minArea = area < minArea ? area : minArea; + targetNode = child; + + } else if (enlargement === minEnlargement) { + // otherwise choose one with the smallest area + if (area < minArea) { + minArea = area; + targetNode = child; + } + } + } + + node = targetNode || node.children[0]; + } + + return node; + } + + _insert(item, level, isNode) { + const bbox = isNode ? item : this.toBBox(item); + const insertPath = []; + + // find the best node for accommodating the item, saving all nodes along the path too + const node = this._chooseSubtree(bbox, this.data, level, insertPath); + + // put the item into the node + node.children.push(item); + extend(node, bbox); + + // split on node overflow; propagate upwards if necessary + while (level >= 0) { + if (insertPath[level].children.length > this._maxEntries) { + this._split(insertPath, level); + level--; + } else break; + } + + // adjust bboxes along the insertion path + this._adjustParentBBoxes(bbox, insertPath, level); + } + + // split overflowed node into two + _split(insertPath, level) { + const node = insertPath[level]; + const M = node.children.length; + const m = this._minEntries; + + this._chooseSplitAxis(node, m, M); + + const splitIndex = this._chooseSplitIndex(node, m, M); + + const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex)); + newNode.height = node.height; + newNode.leaf = node.leaf; + + calcBBox(node, this.toBBox); + calcBBox(newNode, this.toBBox); + + if (level) insertPath[level - 1].children.push(newNode); + else this._splitRoot(node, newNode); + } + + _splitRoot(node, newNode) { + // split root node + this.data = createNode([node, newNode]); + this.data.height = node.height + 1; + this.data.leaf = false; + calcBBox(this.data, this.toBBox); + } + + _chooseSplitIndex(node, m, M) { + let index; + let minOverlap = Infinity; + let minArea = Infinity; + + for (let i = m; i <= M - m; i++) { + const bbox1 = distBBox(node, 0, i, this.toBBox); + const bbox2 = distBBox(node, i, M, this.toBBox); + + const overlap = intersectionArea(bbox1, bbox2); + const area = bboxArea(bbox1) + bboxArea(bbox2); + + // choose distribution with minimum overlap + if (overlap < minOverlap) { + minOverlap = overlap; + index = i; + + minArea = area < minArea ? area : minArea; + + } else if (overlap === minOverlap) { + // otherwise choose distribution with minimum area + if (area < minArea) { + minArea = area; + index = i; + } + } + } + + return index || M - m; + } + + // sorts node children by the best axis for split + _chooseSplitAxis(node, m, M) { + const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX; + const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY; + const xMargin = this._allDistMargin(node, m, M, compareMinX); + const yMargin = this._allDistMargin(node, m, M, compareMinY); + + // if total distributions margin value is minimal for x, sort by minX, + // otherwise it's already sorted by minY + if (xMargin < yMargin) node.children.sort(compareMinX); + } + + // total margin of all possible split distributions where each node is at least m full + _allDistMargin(node, m, M, compare) { + node.children.sort(compare); + + const toBBox = this.toBBox; + const leftBBox = distBBox(node, 0, m, toBBox); + const rightBBox = distBBox(node, M - m, M, toBBox); + let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox); + + for (let i = m; i < M - m; i++) { + const child = node.children[i]; + extend(leftBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(leftBBox); + } + + for (let i = M - m - 1; i >= m; i--) { + const child = node.children[i]; + extend(rightBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(rightBBox); + } + + return margin; + } + + _adjustParentBBoxes(bbox, path, level) { + // adjust bboxes along the given tree path + for (let i = level; i >= 0; i--) { + extend(path[i], bbox); + } + } + + _condense(path) { + // go through the path, removing empty nodes and updating bboxes + for (let i = path.length - 1, siblings; i >= 0; i--) { + if (path[i].children.length === 0) { + if (i > 0) { + siblings = path[i - 1].children; + siblings.splice(siblings.indexOf(path[i]), 1); + + } else this.clear(); + + } else calcBBox(path[i], this.toBBox); + } + } +} + +function findItem(item, items, equalsFn) { + if (!equalsFn) return items.indexOf(item); + + for (let i = 0; i < items.length; i++) { + if (equalsFn(item, items[i])) return i; + } + return -1; +} + +// calculate node's bbox from bboxes of its children +function calcBBox(node, toBBox) { + distBBox(node, 0, node.children.length, toBBox, node); +} + +// min bounding rectangle of node children from k to p-1 +function distBBox(node, k, p, toBBox, destNode) { + if (!destNode) destNode = createNode(null); + destNode.minX = Infinity; + destNode.minY = Infinity; + destNode.maxX = -Infinity; + destNode.maxY = -Infinity; + + for (let i = k; i < p; i++) { + const child = node.children[i]; + extend(destNode, node.leaf ? toBBox(child) : child); + } + + return destNode; +} + +function extend(a, b) { + a.minX = Math.min(a.minX, b.minX); + a.minY = Math.min(a.minY, b.minY); + a.maxX = Math.max(a.maxX, b.maxX); + a.maxY = Math.max(a.maxY, b.maxY); + return a; +} + +function compareNodeMinX(a, b) { return a.minX - b.minX; } +function compareNodeMinY(a, b) { return a.minY - b.minY; } + +function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); } +function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); } + +function enlargedArea(a, b) { + return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * + (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY)); +} + +function intersectionArea(a, b) { + const minX = Math.max(a.minX, b.minX); + const minY = Math.max(a.minY, b.minY); + const maxX = Math.min(a.maxX, b.maxX); + const maxY = Math.min(a.maxY, b.maxY); + + return Math.max(0, maxX - minX) * + Math.max(0, maxY - minY); +} + +function contains(a, b) { + return a.minX <= b.minX && + a.minY <= b.minY && + b.maxX <= a.maxX && + b.maxY <= a.maxY; +} + +function intersects(a, b) { + return b.minX <= a.maxX && + b.minY <= a.maxY && + b.maxX >= a.minX && + b.maxY >= a.minY; +} + +function createNode(children) { + return { + children, + height: 1, + leaf: true, + minX: Infinity, + minY: Infinity, + maxX: -Infinity, + maxY: -Infinity + }; +} + +// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; +// combines selection algorithm with binary divide & conquer approach + +function multiSelect(arr, left, right, n, compare) { + const stack = [left, right]; + + while (stack.length) { + right = stack.pop(); + left = stack.pop(); + + if (right - left <= n) continue; + + const mid = left + Math.ceil((right - left) / n / 2) * n; + (0,quickselect__WEBPACK_IMPORTED_MODULE_0__["default"])(arr, mid, left, right, compare); + + stack.push(left, mid, mid, right); + } +} + + /***/ }) /******/ }); diff --git a/dist/intersect.d.ts b/dist/intersect.d.ts index 8204d148..8407ed64 100644 --- a/dist/intersect.d.ts +++ b/dist/intersect.d.ts @@ -1,9 +1,8 @@ -/// +import { Body, SATPolygon, Vector } from "./model"; import { Circle } from "./bodies/circle"; import { Line } from "./bodies/line"; import { Point } from "./bodies/point"; import { Polygon } from "./bodies/polygon"; -import { Body, SATPolygon, Vector } from "./model"; /** * replace body with array of related convex polygons */ diff --git a/dist/intersect.js b/dist/intersect.js index 7088c04f..965bc574 100644 --- a/dist/intersect.js +++ b/dist/intersect.js @@ -1,9 +1,20 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.intersectLinePolygon = exports.intersectLineLine = exports.intersectLineLineFast = exports.intersectLineCircle = exports.circleOutsidePolygon = exports.circleInPolygon = exports.circleInCircle = exports.pointOnCircle = exports.polygonInPolygon = exports.pointInPolygon = exports.polygonInCircle = exports.ensureConvex = void 0; -const sat_1 = require("sat"); +exports.ensureConvex = ensureConvex; +exports.polygonInCircle = polygonInCircle; +exports.pointInPolygon = pointInPolygon; +exports.polygonInPolygon = polygonInPolygon; +exports.pointOnCircle = pointOnCircle; +exports.circleInCircle = circleInCircle; +exports.circleInPolygon = circleInPolygon; +exports.circleOutsidePolygon = circleOutsidePolygon; +exports.intersectLineCircle = intersectLineCircle; +exports.intersectLineLineFast = intersectLineLineFast; +exports.intersectLineLine = intersectLineLine; +exports.intersectLinePolygon = intersectLinePolygon; const model_1 = require("./model"); const optimized_1 = require("./optimized"); +const sat_1 = require("sat"); /** * replace body with array of related convex polygons */ @@ -13,19 +24,15 @@ function ensureConvex(body) { } return body.convexPolygons; } -exports.ensureConvex = ensureConvex; function polygonInCircle(polygon, circle) { return (0, optimized_1.every)(polygon.calcPoints, p => (0, sat_1.pointInCircle)({ x: p.x + polygon.pos.x, y: p.y + polygon.pos.y }, circle)); } -exports.polygonInCircle = polygonInCircle; function pointInPolygon(point, polygon) { return (0, optimized_1.some)(ensureConvex(polygon), convex => (0, sat_1.pointInPolygon)(point, convex)); } -exports.pointInPolygon = pointInPolygon; function polygonInPolygon(polygonA, polygonB) { return (0, optimized_1.every)(polygonA.calcPoints, point => pointInPolygon({ x: point.x + polygonA.pos.x, y: point.y + polygonA.pos.y }, polygonB)); } -exports.polygonInPolygon = polygonInPolygon; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -34,7 +41,6 @@ function pointOnCircle(point, circle) { (point.y - circle.pos.y) * (point.y - circle.pos.y) === circle.r * circle.r); } -exports.pointOnCircle = pointOnCircle; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -48,7 +54,6 @@ function circleInCircle(bodyA, bodyB) { const distSq = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); return distSq + r2 === r1 || distSq + r2 < r1; } -exports.circleInCircle = circleInCircle; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -87,7 +92,6 @@ function circleInPolygon(circle, polygon) { } return true; } -exports.circleInPolygon = circleInPolygon; /** * https://stackoverflow.com/a/68197894/1749528 */ @@ -126,7 +130,6 @@ function circleOutsidePolygon(circle, polygon) { } return true; } -exports.circleOutsidePolygon = circleOutsidePolygon; /** * https://stackoverflow.com/a/37225895/1749528 */ @@ -153,7 +156,6 @@ function intersectLineCircle(line, { pos, r }) { } return results; } -exports.intersectLineCircle = intersectLineCircle; /** * helper for intersectLineLineFast */ @@ -172,7 +174,6 @@ function intersectLineLineFast(line1, line2) { isTurn(line1.start, line1.end, line2.start) !== isTurn(line1.start, line1.end, line2.end)); } -exports.intersectLineLineFast = intersectLineLineFast; /** * returns the point of intersection * https://stackoverflow.com/a/24392281/1749528 @@ -196,7 +197,6 @@ function intersectLineLine(line1, line2) { } return { x: line1.start.x + lambda * dX, y: line1.start.y + lambda * dY }; } -exports.intersectLineLine = intersectLineLine; function intersectLinePolygon(line, polygon) { const results = []; (0, optimized_1.forEach)(polygon.calcPoints, (to, index) => { @@ -214,4 +214,3 @@ function intersectLinePolygon(line, polygon) { }); return results; } -exports.intersectLinePolygon = intersectLinePolygon; diff --git a/dist/model.d.ts b/dist/model.d.ts index 6212d4be..cbd8df5d 100644 --- a/dist/model.d.ts +++ b/dist/model.d.ts @@ -1,4 +1,3 @@ -import { BBox, default as RBush } from "rbush"; import { Circle as SATCircle, Polygon as SATPolygon, Response, Vector as SATVector } from "sat"; import { System } from "./system"; import { Box } from "./bodies/box"; @@ -7,8 +6,15 @@ import { Ellipse } from "./bodies/ellipse"; import { Line } from "./bodies/line"; import { Point } from "./bodies/point"; import { Polygon } from "./bodies/polygon"; +import RBush from "./rbush"; export { Polygon as DecompPolygon, Point as DecompPoint, isSimple } from "poly-decomp-es"; -export { RBush, BBox, Response, SATVector, SATPolygon, SATCircle }; +export interface BBox { + minX: number; + minY: number; + maxX: number; + maxY: number; +} +export { RBush, Response, SATVector, SATPolygon, SATCircle }; export type CollisionCallback = (response: Response) => boolean | void; /** * types @@ -155,21 +161,25 @@ export interface BodyProps extends Required { */ get scaleY(): number; /** - * update position, and cached convexes positions + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed: number, updateNow?: boolean): Circle | SATPolygon; + /** + * update position BY TELEPORTING */ - setPosition(x: number, y: number, update?: boolean): Circle | SATPolygon; + setPosition(x: number, y: number, updateNow?: boolean): Circle | SATPolygon; /** * for setting scale */ - setScale(x: number, y: number, update?: boolean): Circle | SATPolygon; + setScale(x: number, y: number, updateNow?: boolean): Circle | SATPolygon; /** * for setting angle */ - setAngle(angle: number, update?: boolean): Circle | SATPolygon; + setAngle(angle: number, updateNow?: boolean): Circle | SATPolygon; /** * for setting offset from center */ - setOffset(offset: Vector, update?: boolean): Circle | SATPolygon; + setOffset(offset: Vector, updateNow?: boolean): Circle | SATPolygon; /** * draw the bounding box */ diff --git a/dist/model.js b/dist/model.js index 754e9273..c5f35be0 100644 --- a/dist/model.js +++ b/dist/model.js @@ -4,13 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BodyGroup = exports.BodyType = exports.SATCircle = exports.SATPolygon = exports.SATVector = exports.Response = exports.RBush = exports.isSimple = void 0; -const rbush_1 = __importDefault(require("rbush")); -Object.defineProperty(exports, "RBush", { enumerable: true, get: function () { return rbush_1.default; } }); const sat_1 = require("sat"); Object.defineProperty(exports, "SATCircle", { enumerable: true, get: function () { return sat_1.Circle; } }); Object.defineProperty(exports, "SATPolygon", { enumerable: true, get: function () { return sat_1.Polygon; } }); Object.defineProperty(exports, "Response", { enumerable: true, get: function () { return sat_1.Response; } }); Object.defineProperty(exports, "SATVector", { enumerable: true, get: function () { return sat_1.Vector; } }); +// version 4.0.0 1=1 copy +const rbush_1 = __importDefault(require("./rbush")); +exports.RBush = rbush_1.default; var poly_decomp_es_1 = require("poly-decomp-es"); Object.defineProperty(exports, "isSimple", { enumerable: true, get: function () { return poly_decomp_es_1.isSimple; } }); /** @@ -24,7 +25,7 @@ var BodyType; BodyType["Box"] = "Box"; BodyType["Line"] = "Line"; BodyType["Point"] = "Point"; -})(BodyType = exports.BodyType || (exports.BodyType = {})); +})(BodyType || (exports.BodyType = BodyType = {})); /** * for groups */ @@ -36,4 +37,4 @@ var BodyGroup; BodyGroup[BodyGroup["Box"] = 4] = "Box"; BodyGroup[BodyGroup["Line"] = 2] = "Line"; BodyGroup[BodyGroup["Point"] = 1] = "Point"; -})(BodyGroup = exports.BodyGroup || (exports.BodyGroup = {})); +})(BodyGroup || (exports.BodyGroup = BodyGroup = {})); diff --git a/dist/rbush.d.ts b/dist/rbush.d.ts new file mode 100644 index 00000000..71459bdb --- /dev/null +++ b/dist/rbush.d.ts @@ -0,0 +1,37 @@ +export default class RBush { + constructor(maxEntries?: number); + _maxEntries: number; + _minEntries: number; + all(): any; + search(bbox: any): any[]; + collides(bbox: any): boolean; + load(data: any): this; + data: any; + insert(item: any): this; + clear(): this; + remove(item: any, equalsFn: any): this; + toBBox(item: any): any; + compareMinX(a: any, b: any): number; + compareMinY(a: any, b: any): number; + toJSON(): any; + fromJSON(data: any): this; + _all(node: any, result: any): any; + _build(items: any, left: any, right: any, height: any): { + children: any; + height: number; + leaf: boolean; + minX: number; + minY: number; + maxX: number; + maxY: number; + }; + _chooseSubtree(bbox: any, node: any, level: any, path: any): any; + _insert(item: any, level: any, isNode: any): void; + _split(insertPath: any, level: any): void; + _splitRoot(node: any, newNode: any): void; + _chooseSplitIndex(node: any, m: any, M: any): any; + _chooseSplitAxis(node: any, m: any, M: any): void; + _allDistMargin(node: any, m: any, M: any, compare: any): number; + _adjustParentBBoxes(bbox: any, path: any, level: any): void; + _condense(path: any): void; +} diff --git a/dist/rbush.js b/dist/rbush.js new file mode 100644 index 00000000..e2e58bf8 --- /dev/null +++ b/dist/rbush.js @@ -0,0 +1,435 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const quickselect_1 = __importDefault(require("quickselect")); +class RBush { + constructor(maxEntries = 9) { + // max entries in a node is 9 by default; min node fill is 40% for best performance + this._maxEntries = Math.max(4, maxEntries); + this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); + this.clear(); + } + all() { + return this._all(this.data, []); + } + search(bbox) { + let node = this.data; + const result = []; + if (!intersects(bbox, node)) + return result; + const toBBox = this.toBBox; + const nodesToSearch = []; + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? toBBox(child) : child; + if (intersects(bbox, childBBox)) { + if (node.leaf) + result.push(child); + else if (contains(bbox, childBBox)) + this._all(child, result); + else + nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + return result; + } + collides(bbox) { + let node = this.data; + if (!intersects(bbox, node)) + return false; + const nodesToSearch = []; + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? this.toBBox(child) : child; + if (intersects(bbox, childBBox)) { + if (node.leaf || contains(bbox, childBBox)) + return true; + nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + return false; + } + load(data) { + if (!(data && data.length)) + return this; + if (data.length < this._minEntries) { + for (let i = 0; i < data.length; i++) { + this.insert(data[i]); + } + return this; + } + // recursively build the tree with the given data from scratch using OMT algorithm + let node = this._build(data.slice(), 0, data.length - 1, 0); + if (!this.data.children.length) { + // save as is if tree is empty + this.data = node; + } + else if (this.data.height === node.height) { + // split root if trees have the same height + this._splitRoot(this.data, node); + } + else { + if (this.data.height < node.height) { + // swap trees if inserted one is bigger + const tmpNode = this.data; + this.data = node; + node = tmpNode; + } + // insert the small tree into the large tree at appropriate level + this._insert(node, this.data.height - node.height - 1, true); + } + return this; + } + insert(item) { + if (item) + this._insert(item, this.data.height - 1); + return this; + } + clear() { + this.data = createNode([]); + return this; + } + remove(item, equalsFn) { + if (!item) + return this; + let node = this.data; + const bbox = this.toBBox(item); + const path = []; + const indexes = []; + let i, parent, goingUp; + // depth-first iterative tree traversal + while (node || path.length) { + if (!node) { // go up + node = path.pop(); + parent = path[path.length - 1]; + i = indexes.pop(); + goingUp = true; + } + if (node.leaf) { // check current node + const index = findItem(item, node.children, equalsFn); + if (index !== -1) { + // item found, remove the item and condense tree upwards + node.children.splice(index, 1); + path.push(node); + this._condense(path); + return this; + } + } + if (!goingUp && !node.leaf && contains(node, bbox)) { // go down + path.push(node); + indexes.push(i); + i = 0; + parent = node; + node = node.children[0]; + } + else if (parent) { // go right + i++; + node = parent.children[i]; + goingUp = false; + } + else + node = null; // nothing found + } + return this; + } + toBBox(item) { return item; } + compareMinX(a, b) { return a.minX - b.minX; } + compareMinY(a, b) { return a.minY - b.minY; } + toJSON() { return this.data; } + fromJSON(data) { + this.data = data; + return this; + } + _all(node, result) { + const nodesToSearch = []; + while (node) { + if (node.leaf) + result.push(...node.children); + else + nodesToSearch.push(...node.children); + node = nodesToSearch.pop(); + } + return result; + } + _build(items, left, right, height) { + const N = right - left + 1; + let M = this._maxEntries; + let node; + if (N <= M) { + // reached leaf level; return leaf + node = createNode(items.slice(left, right + 1)); + calcBBox(node, this.toBBox); + return node; + } + if (!height) { + // target height of the bulk-loaded tree + height = Math.ceil(Math.log(N) / Math.log(M)); + // target number of root entries to maximize storage utilization + M = Math.ceil(N / Math.pow(M, height - 1)); + } + node = createNode([]); + node.leaf = false; + node.height = height; + // split the items into M mostly square tiles + const N2 = Math.ceil(N / M); + const N1 = N2 * Math.ceil(Math.sqrt(M)); + multiSelect(items, left, right, N1, this.compareMinX); + for (let i = left; i <= right; i += N1) { + const right2 = Math.min(i + N1 - 1, right); + multiSelect(items, i, right2, N2, this.compareMinY); + for (let j = i; j <= right2; j += N2) { + const right3 = Math.min(j + N2 - 1, right2); + // pack each entry recursively + node.children.push(this._build(items, j, right3, height - 1)); + } + } + calcBBox(node, this.toBBox); + return node; + } + _chooseSubtree(bbox, node, level, path) { + while (true) { + path.push(node); + if (node.leaf || path.length - 1 === level) + break; + let minArea = Infinity; + let minEnlargement = Infinity; + let targetNode; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const area = bboxArea(child); + const enlargement = enlargedArea(bbox, child) - area; + // choose entry with the least area enlargement + if (enlargement < minEnlargement) { + minEnlargement = enlargement; + minArea = area < minArea ? area : minArea; + targetNode = child; + } + else if (enlargement === minEnlargement) { + // otherwise choose one with the smallest area + if (area < minArea) { + minArea = area; + targetNode = child; + } + } + } + node = targetNode || node.children[0]; + } + return node; + } + _insert(item, level, isNode) { + const bbox = isNode ? item : this.toBBox(item); + const insertPath = []; + // find the best node for accommodating the item, saving all nodes along the path too + const node = this._chooseSubtree(bbox, this.data, level, insertPath); + // put the item into the node + node.children.push(item); + extend(node, bbox); + // split on node overflow; propagate upwards if necessary + while (level >= 0) { + if (insertPath[level].children.length > this._maxEntries) { + this._split(insertPath, level); + level--; + } + else + break; + } + // adjust bboxes along the insertion path + this._adjustParentBBoxes(bbox, insertPath, level); + } + // split overflowed node into two + _split(insertPath, level) { + const node = insertPath[level]; + const M = node.children.length; + const m = this._minEntries; + this._chooseSplitAxis(node, m, M); + const splitIndex = this._chooseSplitIndex(node, m, M); + const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex)); + newNode.height = node.height; + newNode.leaf = node.leaf; + calcBBox(node, this.toBBox); + calcBBox(newNode, this.toBBox); + if (level) + insertPath[level - 1].children.push(newNode); + else + this._splitRoot(node, newNode); + } + _splitRoot(node, newNode) { + // split root node + this.data = createNode([node, newNode]); + this.data.height = node.height + 1; + this.data.leaf = false; + calcBBox(this.data, this.toBBox); + } + _chooseSplitIndex(node, m, M) { + let index; + let minOverlap = Infinity; + let minArea = Infinity; + for (let i = m; i <= M - m; i++) { + const bbox1 = distBBox(node, 0, i, this.toBBox); + const bbox2 = distBBox(node, i, M, this.toBBox); + const overlap = intersectionArea(bbox1, bbox2); + const area = bboxArea(bbox1) + bboxArea(bbox2); + // choose distribution with minimum overlap + if (overlap < minOverlap) { + minOverlap = overlap; + index = i; + minArea = area < minArea ? area : minArea; + } + else if (overlap === minOverlap) { + // otherwise choose distribution with minimum area + if (area < minArea) { + minArea = area; + index = i; + } + } + } + return index || M - m; + } + // sorts node children by the best axis for split + _chooseSplitAxis(node, m, M) { + const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX; + const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY; + const xMargin = this._allDistMargin(node, m, M, compareMinX); + const yMargin = this._allDistMargin(node, m, M, compareMinY); + // if total distributions margin value is minimal for x, sort by minX, + // otherwise it's already sorted by minY + if (xMargin < yMargin) + node.children.sort(compareMinX); + } + // total margin of all possible split distributions where each node is at least m full + _allDistMargin(node, m, M, compare) { + node.children.sort(compare); + const toBBox = this.toBBox; + const leftBBox = distBBox(node, 0, m, toBBox); + const rightBBox = distBBox(node, M - m, M, toBBox); + let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox); + for (let i = m; i < M - m; i++) { + const child = node.children[i]; + extend(leftBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(leftBBox); + } + for (let i = M - m - 1; i >= m; i--) { + const child = node.children[i]; + extend(rightBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(rightBBox); + } + return margin; + } + _adjustParentBBoxes(bbox, path, level) { + // adjust bboxes along the given tree path + for (let i = level; i >= 0; i--) { + extend(path[i], bbox); + } + } + _condense(path) { + // go through the path, removing empty nodes and updating bboxes + for (let i = path.length - 1, siblings; i >= 0; i--) { + if (path[i].children.length === 0) { + if (i > 0) { + siblings = path[i - 1].children; + siblings.splice(siblings.indexOf(path[i]), 1); + } + else + this.clear(); + } + else + calcBBox(path[i], this.toBBox); + } + } +} +exports.default = RBush; +function findItem(item, items, equalsFn) { + if (!equalsFn) + return items.indexOf(item); + for (let i = 0; i < items.length; i++) { + if (equalsFn(item, items[i])) + return i; + } + return -1; +} +// calculate node's bbox from bboxes of its children +function calcBBox(node, toBBox) { + distBBox(node, 0, node.children.length, toBBox, node); +} +// min bounding rectangle of node children from k to p-1 +function distBBox(node, k, p, toBBox, destNode) { + if (!destNode) + destNode = createNode(null); + destNode.minX = Infinity; + destNode.minY = Infinity; + destNode.maxX = -Infinity; + destNode.maxY = -Infinity; + for (let i = k; i < p; i++) { + const child = node.children[i]; + extend(destNode, node.leaf ? toBBox(child) : child); + } + return destNode; +} +function extend(a, b) { + a.minX = Math.min(a.minX, b.minX); + a.minY = Math.min(a.minY, b.minY); + a.maxX = Math.max(a.maxX, b.maxX); + a.maxY = Math.max(a.maxY, b.maxY); + return a; +} +function compareNodeMinX(a, b) { return a.minX - b.minX; } +function compareNodeMinY(a, b) { return a.minY - b.minY; } +function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); } +function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); } +function enlargedArea(a, b) { + return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * + (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY)); +} +function intersectionArea(a, b) { + const minX = Math.max(a.minX, b.minX); + const minY = Math.max(a.minY, b.minY); + const maxX = Math.min(a.maxX, b.maxX); + const maxY = Math.min(a.maxY, b.maxY); + return Math.max(0, maxX - minX) * + Math.max(0, maxY - minY); +} +function contains(a, b) { + return a.minX <= b.minX && + a.minY <= b.minY && + b.maxX <= a.maxX && + b.maxY <= a.maxY; +} +function intersects(a, b) { + return b.minX <= a.maxX && + b.minY <= a.maxY && + b.maxX >= a.minX && + b.maxY >= a.minY; +} +function createNode(children) { + return { + children, + height: 1, + leaf: true, + minX: Infinity, + minY: Infinity, + maxX: -Infinity, + maxY: -Infinity + }; +} +// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; +// combines selection algorithm with binary divide & conquer approach +function multiSelect(arr, left, right, n, compare) { + const stack = [left, right]; + while (stack.length) { + right = stack.pop(); + left = stack.pop(); + if (right - left <= n) + continue; + const mid = left + Math.ceil((right - left) / n / 2) * n; + (0, quickselect_1.default)(arr, mid, left, right, compare); + stack.push(left, mid, mid, right); + } +} diff --git a/dist/system.d.ts b/dist/system.d.ts index 1abd33af..2c79be1c 100644 --- a/dist/system.d.ts +++ b/dist/system.d.ts @@ -1,7 +1,6 @@ -/// +import { BBox, Body, CollisionCallback, RaycastHit, Response, Vector } from "./model"; import { BaseSystem } from "./base-system"; import { Line } from "./bodies/line"; -import { BBox, Body, CollisionCallback, RBush, RaycastHit, Response, Vector } from "./model"; /** * collision system */ @@ -18,7 +17,7 @@ export declare class System extends BaseSystem * re-insert body into collision tree and update its bbox * every body can be part of only one system */ - insert(body: TBody): RBush; + insert(body: TBody): this; /** * separate (move away) bodies */ diff --git a/dist/system.js b/dist/system.js index fdbbd3f2..e3509a6f 100644 --- a/dist/system.js +++ b/dist/system.js @@ -1,12 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.System = void 0; -const base_system_1 = require("./base-system"); -const line_1 = require("./bodies/line"); -const intersect_1 = require("./intersect"); const model_1 = require("./model"); -const optimized_1 = require("./optimized"); const utils_1 = require("./utils"); +const intersect_1 = require("./intersect"); +const optimized_1 = require("./optimized"); +const base_system_1 = require("./base-system"); +const line_1 = require("./bodies/line"); /** * collision system */ @@ -93,7 +93,7 @@ class System extends base_system_1.BaseSystem { */ checkCollision(bodyA, bodyB, response = this.response) { const { bbox: bboxA } = bodyA; - const { bbox: bboxB } = bodyA; + const { bbox: bboxB } = bodyB; // assess the bodies real aabb without padding if (!(0, utils_1.canInteract)(bodyA, bodyB) || !bboxA || diff --git a/dist/utils.d.ts b/dist/utils.d.ts index 220ec9c4..f8e1ed04 100644 --- a/dist/utils.d.ts +++ b/dist/utils.d.ts @@ -1,8 +1,7 @@ -import { Point as DecompPoint } from "poly-decomp-es"; -import { BBox } from "rbush"; +import { BBox, Body, BodyOptions, PotentialVector, SATPolygon, SATTest, Vector } from "./model"; import { Response, Vector as SATVector } from "sat"; +import { Point as DecompPoint } from "poly-decomp-es"; import { Polygon } from "./bodies/polygon"; -import { Body, BodyOptions, PotentialVector, SATPolygon, SATTest, Vector } from "./model"; export declare const DEG2RAD: number; export declare const RAD2DEG: number; /** @@ -124,3 +123,4 @@ export declare function ensureNumber(input: number | string): number; * @param mask - mask bits (default: category) */ export declare function groupBits(category: number | string, mask?: number | string): number; +export declare function move(body: Body, speed?: number, updateNow?: boolean): void; diff --git a/dist/utils.js b/dist/utils.js index 7b5f8c81..1a902a54 100644 --- a/dist/utils.js +++ b/dist/utils.js @@ -1,9 +1,38 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.groupBits = exports.ensureNumber = exports.bin2dec = exports.getGroup = exports.returnTrue = exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.dashLineTo = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.clonePointsArray = exports.checkAInB = exports.canInteract = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; +exports.RAD2DEG = exports.DEG2RAD = void 0; +exports.deg2rad = deg2rad; +exports.rad2deg = rad2deg; +exports.createEllipse = createEllipse; +exports.createBox = createBox; +exports.ensureVectorPoint = ensureVectorPoint; +exports.ensurePolygonPoints = ensurePolygonPoints; +exports.distance = distance; +exports.clockwise = clockwise; +exports.extendBody = extendBody; +exports.bodyMoved = bodyMoved; +exports.notIntersectAABB = notIntersectAABB; +exports.intersectAABB = intersectAABB; +exports.canInteract = canInteract; +exports.checkAInB = checkAInB; +exports.clonePointsArray = clonePointsArray; +exports.mapVectorToArray = mapVectorToArray; +exports.mapArrayToVector = mapArrayToVector; +exports.getBounceDirection = getBounceDirection; +exports.getSATTest = getSATTest; +exports.dashLineTo = dashLineTo; +exports.drawPolygon = drawPolygon; +exports.drawBVH = drawBVH; +exports.cloneResponse = cloneResponse; +exports.returnTrue = returnTrue; +exports.getGroup = getGroup; +exports.bin2dec = bin2dec; +exports.ensureNumber = ensureNumber; +exports.groupBits = groupBits; +exports.move = move; +const model_1 = require("./model"); const sat_1 = require("sat"); const intersect_1 = require("./intersect"); -const model_1 = require("./model"); const optimized_1 = require("./optimized"); /* helpers for faster getSATTest() and checkAInB() */ const testMap = { @@ -33,14 +62,12 @@ exports.RAD2DEG = 180 / Math.PI; function deg2rad(degrees) { return degrees * exports.DEG2RAD; } -exports.deg2rad = deg2rad; /** * convert from radians to degrees */ function rad2deg(radians) { return radians * exports.RAD2DEG; } -exports.rad2deg = rad2deg; /** * creates ellipse-shaped polygon based on params */ @@ -56,7 +83,6 @@ function createEllipse(radiusX, radiusY = radiusX, step = 1) { } return ellipse; } -exports.createEllipse = createEllipse; /** * creates box shaped polygon points */ @@ -68,7 +94,6 @@ function createBox(width, height) { new sat_1.Vector(0, height) ]; } -exports.createBox = createBox; /** * ensure SATVector type point result */ @@ -77,7 +102,6 @@ function ensureVectorPoint(point = {}) { ? point : new sat_1.Vector(point.x || 0, point.y || 0); } -exports.ensureVectorPoint = ensureVectorPoint; /** * ensure Vector points (for polygon) in counter-clockwise order */ @@ -85,7 +109,6 @@ function ensurePolygonPoints(points = []) { const polygonPoints = (0, optimized_1.map)(points, ensureVectorPoint); return clockwise(polygonPoints) ? polygonPoints.reverse() : polygonPoints; } -exports.ensurePolygonPoints = ensurePolygonPoints; /** * get distance between two Vector points */ @@ -94,7 +117,6 @@ function distance(bodyA, bodyB) { const yDiff = bodyA.y - bodyB.y; return Math.hypot(xDiff, yDiff); } -exports.distance = distance; /** * check [is clockwise] direction of polygon */ @@ -107,7 +129,6 @@ function clockwise(points) { }); return sum > 0; } -exports.clockwise = clockwise; /** * used for all types of bodies in constructor */ @@ -121,7 +142,6 @@ function extendBody(body, options = {}) { } body.setAngle(options.angle || 0); } -exports.extendBody = extendBody; /** * check if body moved outside of its padding */ @@ -129,7 +149,6 @@ function bodyMoved(body) { const { bbox, minX, minY, maxX, maxY } = body; return (bbox.minX < minX || bbox.minY < minY || bbox.maxX > maxX || bbox.maxY > maxY); } -exports.bodyMoved = bodyMoved; /** * returns true if two boxes not intersect */ @@ -139,14 +158,12 @@ function notIntersectAABB(bodyA, bodyB) { bodyB.maxX < bodyA.minX || bodyB.maxY < bodyA.minY); } -exports.notIntersectAABB = notIntersectAABB; /** * checks if two boxes intersect */ function intersectAABB(bodyA, bodyB) { return !notIntersectAABB(bodyA, bodyB); } -exports.intersectAABB = intersectAABB; /** * checks if two bodies can interact (for collision filtering) */ @@ -154,7 +171,6 @@ function canInteract(bodyA, bodyB) { return (((bodyA.group >> 16) & (bodyB.group & 0xFFFF) && (bodyB.group >> 16) & (bodyA.group & 0xFFFF)) !== 0); } -exports.canInteract = canInteract; /** * checks if body a is in body b */ @@ -164,28 +180,24 @@ function checkAInB(bodyA, bodyB) { : polygonInFunctions; return check[bodyB.type](bodyA, bodyB); } -exports.checkAInB = checkAInB; /** * clone sat vector points array into vector points array */ function clonePointsArray(points) { return (0, optimized_1.map)(points, ({ x, y }) => ({ x, y })); } -exports.clonePointsArray = clonePointsArray; /** * change format from SAT.js to poly-decomp */ function mapVectorToArray({ x, y } = { x: 0, y: 0 }) { return [x, y]; } -exports.mapVectorToArray = mapVectorToArray; /** * change format from poly-decomp to SAT.js */ function mapArrayToVector([x, y] = [0, 0]) { return { x, y }; } -exports.mapArrayToVector = mapArrayToVector; /** * given 2 bodies calculate vector of bounce assuming equal mass and they are circles */ @@ -195,7 +207,6 @@ function getBounceDirection(body, collider) { const len = v1.dot(v2.normalize()) * 2; return new sat_1.Vector(v2.x * len - v1.x, v2.y * len - v1.y).normalize(); } -exports.getBounceDirection = getBounceDirection; /** * returns correct sat.js testing function based on body types */ @@ -205,7 +216,6 @@ function getSATTest(bodyA, bodyB) { : polygonSATFunctions; return check[bodyB.type]; } -exports.getSATTest = getSATTest; /** * draws dashed line on canvas context */ @@ -227,7 +237,6 @@ function dashLineTo(context, fromX, fromY, toX, toY, dash = 2, gap = 4) { dist -= dash + gap; } } -exports.dashLineTo = dashLineTo; /** * draw polygon */ @@ -253,7 +262,6 @@ function drawPolygon(context, { pos, calcPoints }, isTrigger = false) { } }); } -exports.drawPolygon = drawPolygon; /** * draw body bounding body box */ @@ -263,7 +271,6 @@ function drawBVH(context, body) { calcPoints: createBox(body.maxX - body.minX, body.maxY - body.minY) }); } -exports.drawBVH = drawBVH; /** * clone response object returning new response with previous ones values */ @@ -279,28 +286,24 @@ function cloneResponse(response) { clone.bInA = bInA; return clone; } -exports.cloneResponse = cloneResponse; /** * dummy fn used as default, for optimization */ function returnTrue() { return true; } -exports.returnTrue = returnTrue; /** * for groups */ function getGroup(group) { return Math.max(0, Math.min(group, 0x7FFFFFFF)); } -exports.getGroup = getGroup; /** * binary string to decimal number */ function bin2dec(binary) { return Number(`0b${binary}`.replace(/\s/g, "")); } -exports.bin2dec = bin2dec; /** * helper for groupBits() * @@ -309,7 +312,6 @@ exports.bin2dec = bin2dec; function ensureNumber(input) { return typeof input === "number" ? input : bin2dec(input); } -exports.ensureNumber = ensureNumber; /** * create group bits from category and mask * @@ -319,4 +321,11 @@ exports.ensureNumber = ensureNumber; function groupBits(category, mask = category) { return (ensureNumber(category) << 16) | ensureNumber(mask); } -exports.groupBits = groupBits; +function move(body, speed = 1, updateNow = true) { + if (!speed) { + return; + } + const moveX = Math.cos(body.angle) * speed; + const moveY = Math.sin(body.angle) * speed; + body.setPosition(body.x + moveX, body.y + moveY, updateNow); +} diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css index f1615fed..a3bf868b 100644 --- a/docs/assets/highlight.css +++ b/docs/assets/highlight.css @@ -1,30 +1,27 @@ :root { - --light-hl-0: #795e26; - --dark-hl-0: #dcdcaa; - --light-hl-1: #000000; - --dark-hl-1: #d4d4d4; - --light-hl-2: #a31515; - --dark-hl-2: #ce9178; - --light-hl-3: #0000ff; - --dark-hl-3: #569cd6; - --light-hl-4: #0070c1; - --dark-hl-4: #4fc1ff; - --light-hl-5: #008000; - --dark-hl-5: #6a9955; - --light-hl-6: #001080; - --dark-hl-6: #9cdcfe; - --light-hl-7: #af00db; - --dark-hl-7: #c586c0; - --light-hl-8: #098658; - --dark-hl-8: #b5cea8; - --light-hl-9: #267f99; - --dark-hl-9: #4ec9b0; - --light-code-background: #ffffff; - --dark-code-background: #1e1e1e; + --light-hl-0: #795E26; + --dark-hl-0: #DCDCAA; + --light-hl-1: #000000; + --dark-hl-1: #D4D4D4; + --light-hl-2: #A31515; + --dark-hl-2: #CE9178; + --light-hl-3: #0000FF; + --dark-hl-3: #569CD6; + --light-hl-4: #0070C1; + --dark-hl-4: #4FC1FF; + --light-hl-5: #008000; + --dark-hl-5: #6A9955; + --light-hl-6: #001080; + --dark-hl-6: #9CDCFE; + --light-hl-7: #098658; + --dark-hl-7: #B5CEA8; + --light-hl-8: #AF00DB; + --dark-hl-8: #C586C0; + --light-code-background: #FFFFFF; + --dark-code-background: #1E1E1E; } -@media (prefers-color-scheme: light) { - :root { +@media (prefers-color-scheme: light) { :root { --hl-0: var(--light-hl-0); --hl-1: var(--light-hl-1); --hl-2: var(--light-hl-2); @@ -34,13 +31,10 @@ --hl-6: var(--light-hl-6); --hl-7: var(--light-hl-7); --hl-8: var(--light-hl-8); - --hl-9: var(--light-hl-9); --code-background: var(--light-code-background); - } -} +} } -@media (prefers-color-scheme: dark) { - :root { +@media (prefers-color-scheme: dark) { :root { --hl-0: var(--dark-hl-0); --hl-1: var(--dark-hl-1); --hl-2: var(--dark-hl-2); @@ -50,70 +44,42 @@ --hl-6: var(--dark-hl-6); --hl-7: var(--dark-hl-7); --hl-8: var(--dark-hl-8); - --hl-9: var(--dark-hl-9); --code-background: var(--dark-code-background); - } -} +} } -:root[data-theme="light"] { - --hl-0: var(--light-hl-0); - --hl-1: var(--light-hl-1); - --hl-2: var(--light-hl-2); - --hl-3: var(--light-hl-3); - --hl-4: var(--light-hl-4); - --hl-5: var(--light-hl-5); - --hl-6: var(--light-hl-6); - --hl-7: var(--light-hl-7); - --hl-8: var(--light-hl-8); - --hl-9: var(--light-hl-9); - --code-background: var(--light-code-background); +:root[data-theme='light'] { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --code-background: var(--light-code-background); } -:root[data-theme="dark"] { - --hl-0: var(--dark-hl-0); - --hl-1: var(--dark-hl-1); - --hl-2: var(--dark-hl-2); - --hl-3: var(--dark-hl-3); - --hl-4: var(--dark-hl-4); - --hl-5: var(--dark-hl-5); - --hl-6: var(--dark-hl-6); - --hl-7: var(--dark-hl-7); - --hl-8: var(--dark-hl-8); - --hl-9: var(--dark-hl-9); - --code-background: var(--dark-code-background); +:root[data-theme='dark'] { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --code-background: var(--dark-code-background); } -.hl-0 { - color: var(--hl-0); -} -.hl-1 { - color: var(--hl-1); -} -.hl-2 { - color: var(--hl-2); -} -.hl-3 { - color: var(--hl-3); -} -.hl-4 { - color: var(--hl-4); -} -.hl-5 { - color: var(--hl-5); -} -.hl-6 { - color: var(--hl-6); -} -.hl-7 { - color: var(--hl-7); -} -.hl-8 { - color: var(--hl-8); -} -.hl-9 { - color: var(--hl-9); -} -pre, -code { - background: var(--code-background); -} +.hl-0 { color: var(--hl-0); } +.hl-1 { color: var(--hl-1); } +.hl-2 { color: var(--hl-2); } +.hl-3 { color: var(--hl-3); } +.hl-4 { color: var(--hl-4); } +.hl-5 { color: var(--hl-5); } +.hl-6 { color: var(--hl-6); } +.hl-7 { color: var(--hl-7); } +.hl-8 { color: var(--hl-8); } +pre, code { background: var(--code-background); } diff --git a/docs/assets/icons.js b/docs/assets/icons.js index 5d8f27f2..e88e8ca7 100644 --- a/docs/assets/icons.js +++ b/docs/assets/icons.js @@ -1,20 +1,18 @@ -(function (svg) { - svg.innerHTML = ``; - svg.style.display = "none"; - if (location.protocol === "file:") { - if (document.readyState === "loading") - document.addEventListener("DOMContentLoaded", updateUseElements); - else updateUseElements(); +(function() { + addIcons(); + function addIcons() { + if (document.readyState === "loading") return document.addEventListener("DOMContentLoaded", addIcons); + const svg = document.body.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg")); + svg.innerHTML = `""`; + svg.style.display = "none"; + if (location.protocol === "file:") updateUseElements(); + } + function updateUseElements() { - document.querySelectorAll("use").forEach((el) => { - if (el.getAttribute("href").includes("#icon-")) { - el.setAttribute("href", el.getAttribute("href").replace(/.*#/, "#")); - } - }); + document.querySelectorAll("use").forEach(el => { + if (el.getAttribute("href").includes("#icon-")) { + el.setAttribute("href", el.getAttribute("href").replace(/.*#/, "#")); + } + }); } - } -})( - document.body.appendChild( - document.createElementNS("http://www.w3.org/2000/svg", "svg"), - ), -); +})() \ No newline at end of file diff --git a/docs/assets/icons.svg b/docs/assets/icons.svg index 7dead611..e371b8b5 100644 --- a/docs/assets/icons.svg +++ b/docs/assets/icons.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/assets/main.js b/docs/assets/main.js index 272f7269..35728810 100644 --- a/docs/assets/main.js +++ b/docs/assets/main.js @@ -1,2143 +1,9 @@ "use strict"; -"use strict"; -(() => { - var Ce = Object.create; - var ne = Object.defineProperty; - var Pe = Object.getOwnPropertyDescriptor; - var Oe = Object.getOwnPropertyNames; - var _e = Object.getPrototypeOf, - Re = Object.prototype.hasOwnProperty; - var Me = (t, e) => () => ( - e || t((e = { exports: {} }).exports, e), e.exports - ); - var Fe = (t, e, n, r) => { - if ((e && typeof e == "object") || typeof e == "function") - for (let i of Oe(e)) - !Re.call(t, i) && - i !== n && - ne(t, i, { - get: () => e[i], - enumerable: !(r = Pe(e, i)) || r.enumerable, - }); - return t; - }; - var De = (t, e, n) => ( - (n = t != null ? Ce(_e(t)) : {}), - Fe( - e || !t || !t.__esModule - ? ne(n, "default", { value: t, enumerable: !0 }) - : n, - t, - ) - ); - var ae = Me((se, oe) => { - (function () { - var t = function (e) { - var n = new t.Builder(); - return ( - n.pipeline.add(t.trimmer, t.stopWordFilter, t.stemmer), - n.searchPipeline.add(t.stemmer), - e.call(n, n), - n.build() - ); - }; - t.version = "2.3.9"; - (t.utils = {}), - (t.utils.warn = (function (e) { - return function (n) { - e.console && console.warn && console.warn(n); - }; - })(this)), - (t.utils.asString = function (e) { - return e == null ? "" : e.toString(); - }), - (t.utils.clone = function (e) { - if (e == null) return e; - for ( - var n = Object.create(null), r = Object.keys(e), i = 0; - i < r.length; - i++ - ) { - var s = r[i], - o = e[s]; - if (Array.isArray(o)) { - n[s] = o.slice(); - continue; - } - if ( - typeof o == "string" || - typeof o == "number" || - typeof o == "boolean" - ) { - n[s] = o; - continue; - } - throw new TypeError( - "clone is not deep and does not support nested objects", - ); - } - return n; - }), - (t.FieldRef = function (e, n, r) { - (this.docRef = e), (this.fieldName = n), (this._stringValue = r); - }), - (t.FieldRef.joiner = "/"), - (t.FieldRef.fromString = function (e) { - var n = e.indexOf(t.FieldRef.joiner); - if (n === -1) throw "malformed field ref string"; - var r = e.slice(0, n), - i = e.slice(n + 1); - return new t.FieldRef(i, r, e); - }), - (t.FieldRef.prototype.toString = function () { - return ( - this._stringValue == null && - (this._stringValue = - this.fieldName + t.FieldRef.joiner + this.docRef), - this._stringValue - ); - }); - (t.Set = function (e) { - if (((this.elements = Object.create(null)), e)) { - this.length = e.length; - for (var n = 0; n < this.length; n++) this.elements[e[n]] = !0; - } else this.length = 0; - }), - (t.Set.complete = { - intersect: function (e) { - return e; - }, - union: function () { - return this; - }, - contains: function () { - return !0; - }, - }), - (t.Set.empty = { - intersect: function () { - return this; - }, - union: function (e) { - return e; - }, - contains: function () { - return !1; - }, - }), - (t.Set.prototype.contains = function (e) { - return !!this.elements[e]; - }), - (t.Set.prototype.intersect = function (e) { - var n, - r, - i, - s = []; - if (e === t.Set.complete) return this; - if (e === t.Set.empty) return e; - this.length < e.length - ? ((n = this), (r = e)) - : ((n = e), (r = this)), - (i = Object.keys(n.elements)); - for (var o = 0; o < i.length; o++) { - var a = i[o]; - a in r.elements && s.push(a); - } - return new t.Set(s); - }), - (t.Set.prototype.union = function (e) { - return e === t.Set.complete - ? t.Set.complete - : e === t.Set.empty - ? this - : new t.Set( - Object.keys(this.elements).concat(Object.keys(e.elements)), - ); - }), - (t.idf = function (e, n) { - var r = 0; - for (var i in e) i != "_index" && (r += Object.keys(e[i]).length); - var s = (n - r + 0.5) / (r + 0.5); - return Math.log(1 + Math.abs(s)); - }), - (t.Token = function (e, n) { - (this.str = e || ""), (this.metadata = n || {}); - }), - (t.Token.prototype.toString = function () { - return this.str; - }), - (t.Token.prototype.update = function (e) { - return (this.str = e(this.str, this.metadata)), this; - }), - (t.Token.prototype.clone = function (e) { - return ( - (e = - e || - function (n) { - return n; - }), - new t.Token(e(this.str, this.metadata), this.metadata) - ); - }); - (t.tokenizer = function (e, n) { - if (e == null || e == null) return []; - if (Array.isArray(e)) - return e.map(function (y) { - return new t.Token( - t.utils.asString(y).toLowerCase(), - t.utils.clone(n), - ); - }); - for ( - var r = e.toString().toLowerCase(), - i = r.length, - s = [], - o = 0, - a = 0; - o <= i; - o++ - ) { - var l = r.charAt(o), - u = o - a; - if (l.match(t.tokenizer.separator) || o == i) { - if (u > 0) { - var d = t.utils.clone(n) || {}; - (d.position = [a, u]), - (d.index = s.length), - s.push(new t.Token(r.slice(a, o), d)); - } - a = o + 1; - } - } - return s; - }), - (t.tokenizer.separator = /[\s\-]+/); - (t.Pipeline = function () { - this._stack = []; - }), - (t.Pipeline.registeredFunctions = Object.create(null)), - (t.Pipeline.registerFunction = function (e, n) { - n in this.registeredFunctions && - t.utils.warn("Overwriting existing registered function: " + n), - (e.label = n), - (t.Pipeline.registeredFunctions[e.label] = e); - }), - (t.Pipeline.warnIfFunctionNotRegistered = function (e) { - var n = e.label && e.label in this.registeredFunctions; - n || - t.utils.warn( - `Function is not registered with pipeline. This may cause problems when serialising the index. -`, - e, - ); - }), - (t.Pipeline.load = function (e) { - var n = new t.Pipeline(); - return ( - e.forEach(function (r) { - var i = t.Pipeline.registeredFunctions[r]; - if (i) n.add(i); - else throw new Error("Cannot load unregistered function: " + r); - }), - n - ); - }), - (t.Pipeline.prototype.add = function () { - var e = Array.prototype.slice.call(arguments); - e.forEach(function (n) { - t.Pipeline.warnIfFunctionNotRegistered(n), this._stack.push(n); - }, this); - }), - (t.Pipeline.prototype.after = function (e, n) { - t.Pipeline.warnIfFunctionNotRegistered(n); - var r = this._stack.indexOf(e); - if (r == -1) throw new Error("Cannot find existingFn"); - (r = r + 1), this._stack.splice(r, 0, n); - }), - (t.Pipeline.prototype.before = function (e, n) { - t.Pipeline.warnIfFunctionNotRegistered(n); - var r = this._stack.indexOf(e); - if (r == -1) throw new Error("Cannot find existingFn"); - this._stack.splice(r, 0, n); - }), - (t.Pipeline.prototype.remove = function (e) { - var n = this._stack.indexOf(e); - n != -1 && this._stack.splice(n, 1); - }), - (t.Pipeline.prototype.run = function (e) { - for (var n = this._stack.length, r = 0; r < n; r++) { - for (var i = this._stack[r], s = [], o = 0; o < e.length; o++) { - var a = i(e[o], o, e); - if (!(a == null || a === "")) - if (Array.isArray(a)) - for (var l = 0; l < a.length; l++) s.push(a[l]); - else s.push(a); - } - e = s; - } - return e; - }), - (t.Pipeline.prototype.runString = function (e, n) { - var r = new t.Token(e, n); - return this.run([r]).map(function (i) { - return i.toString(); - }); - }), - (t.Pipeline.prototype.reset = function () { - this._stack = []; - }), - (t.Pipeline.prototype.toJSON = function () { - return this._stack.map(function (e) { - return t.Pipeline.warnIfFunctionNotRegistered(e), e.label; - }); - }); - (t.Vector = function (e) { - (this._magnitude = 0), (this.elements = e || []); - }), - (t.Vector.prototype.positionForIndex = function (e) { - if (this.elements.length == 0) return 0; - for ( - var n = 0, - r = this.elements.length / 2, - i = r - n, - s = Math.floor(i / 2), - o = this.elements[s * 2]; - i > 1 && (o < e && (n = s), o > e && (r = s), o != e); - - ) - (i = r - n), - (s = n + Math.floor(i / 2)), - (o = this.elements[s * 2]); - if (o == e || o > e) return s * 2; - if (o < e) return (s + 1) * 2; - }), - (t.Vector.prototype.insert = function (e, n) { - this.upsert(e, n, function () { - throw "duplicate index"; - }); - }), - (t.Vector.prototype.upsert = function (e, n, r) { - this._magnitude = 0; - var i = this.positionForIndex(e); - this.elements[i] == e - ? (this.elements[i + 1] = r(this.elements[i + 1], n)) - : this.elements.splice(i, 0, e, n); - }), - (t.Vector.prototype.magnitude = function () { - if (this._magnitude) return this._magnitude; - for (var e = 0, n = this.elements.length, r = 1; r < n; r += 2) { - var i = this.elements[r]; - e += i * i; - } - return (this._magnitude = Math.sqrt(e)); - }), - (t.Vector.prototype.dot = function (e) { - for ( - var n = 0, - r = this.elements, - i = e.elements, - s = r.length, - o = i.length, - a = 0, - l = 0, - u = 0, - d = 0; - u < s && d < o; - - ) - (a = r[u]), - (l = i[d]), - a < l - ? (u += 2) - : a > l - ? (d += 2) - : a == l && ((n += r[u + 1] * i[d + 1]), (u += 2), (d += 2)); - return n; - }), - (t.Vector.prototype.similarity = function (e) { - return this.dot(e) / this.magnitude() || 0; - }), - (t.Vector.prototype.toArray = function () { - for ( - var e = new Array(this.elements.length / 2), n = 1, r = 0; - n < this.elements.length; - n += 2, r++ - ) - e[r] = this.elements[n]; - return e; - }), - (t.Vector.prototype.toJSON = function () { - return this.elements; - }); - (t.stemmer = (function () { - var e = { - ational: "ate", - tional: "tion", - enci: "ence", - anci: "ance", - izer: "ize", - bli: "ble", - alli: "al", - entli: "ent", - eli: "e", - ousli: "ous", - ization: "ize", - ation: "ate", - ator: "ate", - alism: "al", - iveness: "ive", - fulness: "ful", - ousness: "ous", - aliti: "al", - iviti: "ive", - biliti: "ble", - logi: "log", - }, - n = { - icate: "ic", - ative: "", - alize: "al", - iciti: "ic", - ical: "ic", - ful: "", - ness: "", - }, - r = "[^aeiou]", - i = "[aeiouy]", - s = r + "[^aeiouy]*", - o = i + "[aeiou]*", - a = "^(" + s + ")?" + o + s, - l = "^(" + s + ")?" + o + s + "(" + o + ")?$", - u = "^(" + s + ")?" + o + s + o + s, - d = "^(" + s + ")?" + i, - y = new RegExp(a), - p = new RegExp(u), - b = new RegExp(l), - g = new RegExp(d), - L = /^(.+?)(ss|i)es$/, - f = /^(.+?)([^s])s$/, - m = /^(.+?)eed$/, - S = /^(.+?)(ed|ing)$/, - w = /.$/, - k = /(at|bl|iz)$/, - _ = new RegExp("([^aeiouylsz])\\1$"), - B = new RegExp("^" + s + i + "[^aeiouwxy]$"), - A = /^(.+?[^aeiou])y$/, - j = - /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/, - $ = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/, - V = - /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/, - q = /^(.+?)(s|t)(ion)$/, - C = /^(.+?)e$/, - z = /ll$/, - W = new RegExp("^" + s + i + "[^aeiouwxy]$"), - N = function (c) { - var v, P, T, h, x, O, M; - if (c.length < 3) return c; - if ( - ((T = c.substr(0, 1)), - T == "y" && (c = T.toUpperCase() + c.substr(1)), - (h = L), - (x = f), - h.test(c) - ? (c = c.replace(h, "$1$2")) - : x.test(c) && (c = c.replace(x, "$1$2")), - (h = m), - (x = S), - h.test(c)) - ) { - var E = h.exec(c); - (h = y), h.test(E[1]) && ((h = w), (c = c.replace(h, ""))); - } else if (x.test(c)) { - var E = x.exec(c); - (v = E[1]), - (x = g), - x.test(v) && - ((c = v), - (x = k), - (O = _), - (M = B), - x.test(c) - ? (c = c + "e") - : O.test(c) - ? ((h = w), (c = c.replace(h, ""))) - : M.test(c) && (c = c + "e")); - } - if (((h = A), h.test(c))) { - var E = h.exec(c); - (v = E[1]), (c = v + "i"); - } - if (((h = j), h.test(c))) { - var E = h.exec(c); - (v = E[1]), (P = E[2]), (h = y), h.test(v) && (c = v + e[P]); - } - if (((h = $), h.test(c))) { - var E = h.exec(c); - (v = E[1]), (P = E[2]), (h = y), h.test(v) && (c = v + n[P]); - } - if (((h = V), (x = q), h.test(c))) { - var E = h.exec(c); - (v = E[1]), (h = p), h.test(v) && (c = v); - } else if (x.test(c)) { - var E = x.exec(c); - (v = E[1] + E[2]), (x = p), x.test(v) && (c = v); - } - if (((h = C), h.test(c))) { - var E = h.exec(c); - (v = E[1]), - (h = p), - (x = b), - (O = W), - (h.test(v) || (x.test(v) && !O.test(v))) && (c = v); - } - return ( - (h = z), - (x = p), - h.test(c) && x.test(c) && ((h = w), (c = c.replace(h, ""))), - T == "y" && (c = T.toLowerCase() + c.substr(1)), - c - ); - }; - return function (R) { - return R.update(N); - }; - })()), - t.Pipeline.registerFunction(t.stemmer, "stemmer"); - (t.generateStopWordFilter = function (e) { - var n = e.reduce(function (r, i) { - return (r[i] = i), r; - }, {}); - return function (r) { - if (r && n[r.toString()] !== r.toString()) return r; - }; - }), - (t.stopWordFilter = t.generateStopWordFilter([ - "a", - "able", - "about", - "across", - "after", - "all", - "almost", - "also", - "am", - "among", - "an", - "and", - "any", - "are", - "as", - "at", - "be", - "because", - "been", - "but", - "by", - "can", - "cannot", - "could", - "dear", - "did", - "do", - "does", - "either", - "else", - "ever", - "every", - "for", - "from", - "get", - "got", - "had", - "has", - "have", - "he", - "her", - "hers", - "him", - "his", - "how", - "however", - "i", - "if", - "in", - "into", - "is", - "it", - "its", - "just", - "least", - "let", - "like", - "likely", - "may", - "me", - "might", - "most", - "must", - "my", - "neither", - "no", - "nor", - "not", - "of", - "off", - "often", - "on", - "only", - "or", - "other", - "our", - "own", - "rather", - "said", - "say", - "says", - "she", - "should", - "since", - "so", - "some", - "than", - "that", - "the", - "their", - "them", - "then", - "there", - "these", - "they", - "this", - "tis", - "to", - "too", - "twas", - "us", - "wants", - "was", - "we", - "were", - "what", - "when", - "where", - "which", - "while", - "who", - "whom", - "why", - "will", - "with", - "would", - "yet", - "you", - "your", - ])), - t.Pipeline.registerFunction(t.stopWordFilter, "stopWordFilter"); - (t.trimmer = function (e) { - return e.update(function (n) { - return n.replace(/^\W+/, "").replace(/\W+$/, ""); - }); - }), - t.Pipeline.registerFunction(t.trimmer, "trimmer"); - (t.TokenSet = function () { - (this.final = !1), - (this.edges = {}), - (this.id = t.TokenSet._nextId), - (t.TokenSet._nextId += 1); - }), - (t.TokenSet._nextId = 1), - (t.TokenSet.fromArray = function (e) { - for ( - var n = new t.TokenSet.Builder(), r = 0, i = e.length; - r < i; - r++ - ) - n.insert(e[r]); - return n.finish(), n.root; - }), - (t.TokenSet.fromClause = function (e) { - return "editDistance" in e - ? t.TokenSet.fromFuzzyString(e.term, e.editDistance) - : t.TokenSet.fromString(e.term); - }), - (t.TokenSet.fromFuzzyString = function (e, n) { - for ( - var r = new t.TokenSet(), - i = [{ node: r, editsRemaining: n, str: e }]; - i.length; - - ) { - var s = i.pop(); - if (s.str.length > 0) { - var o = s.str.charAt(0), - a; - o in s.node.edges - ? (a = s.node.edges[o]) - : ((a = new t.TokenSet()), (s.node.edges[o] = a)), - s.str.length == 1 && (a.final = !0), - i.push({ - node: a, - editsRemaining: s.editsRemaining, - str: s.str.slice(1), - }); - } - if (s.editsRemaining != 0) { - if ("*" in s.node.edges) var l = s.node.edges["*"]; - else { - var l = new t.TokenSet(); - s.node.edges["*"] = l; - } - if ( - (s.str.length == 0 && (l.final = !0), - i.push({ - node: l, - editsRemaining: s.editsRemaining - 1, - str: s.str, - }), - s.str.length > 1 && - i.push({ - node: s.node, - editsRemaining: s.editsRemaining - 1, - str: s.str.slice(1), - }), - s.str.length == 1 && (s.node.final = !0), - s.str.length >= 1) - ) { - if ("*" in s.node.edges) var u = s.node.edges["*"]; - else { - var u = new t.TokenSet(); - s.node.edges["*"] = u; - } - s.str.length == 1 && (u.final = !0), - i.push({ - node: u, - editsRemaining: s.editsRemaining - 1, - str: s.str.slice(1), - }); - } - if (s.str.length > 1) { - var d = s.str.charAt(0), - y = s.str.charAt(1), - p; - y in s.node.edges - ? (p = s.node.edges[y]) - : ((p = new t.TokenSet()), (s.node.edges[y] = p)), - s.str.length == 1 && (p.final = !0), - i.push({ - node: p, - editsRemaining: s.editsRemaining - 1, - str: d + s.str.slice(2), - }); - } - } - } - return r; - }), - (t.TokenSet.fromString = function (e) { - for ( - var n = new t.TokenSet(), r = n, i = 0, s = e.length; - i < s; - i++ - ) { - var o = e[i], - a = i == s - 1; - if (o == "*") (n.edges[o] = n), (n.final = a); - else { - var l = new t.TokenSet(); - (l.final = a), (n.edges[o] = l), (n = l); - } - } - return r; - }), - (t.TokenSet.prototype.toArray = function () { - for (var e = [], n = [{ prefix: "", node: this }]; n.length; ) { - var r = n.pop(), - i = Object.keys(r.node.edges), - s = i.length; - r.node.final && (r.prefix.charAt(0), e.push(r.prefix)); - for (var o = 0; o < s; o++) { - var a = i[o]; - n.push({ prefix: r.prefix.concat(a), node: r.node.edges[a] }); - } - } - return e; - }), - (t.TokenSet.prototype.toString = function () { - if (this._str) return this._str; - for ( - var e = this.final ? "1" : "0", - n = Object.keys(this.edges).sort(), - r = n.length, - i = 0; - i < r; - i++ - ) { - var s = n[i], - o = this.edges[s]; - e = e + s + o.id; - } - return e; - }), - (t.TokenSet.prototype.intersect = function (e) { - for ( - var n = new t.TokenSet(), - r = void 0, - i = [{ qNode: e, output: n, node: this }]; - i.length; - - ) { - r = i.pop(); - for ( - var s = Object.keys(r.qNode.edges), - o = s.length, - a = Object.keys(r.node.edges), - l = a.length, - u = 0; - u < o; - u++ - ) - for (var d = s[u], y = 0; y < l; y++) { - var p = a[y]; - if (p == d || d == "*") { - var b = r.node.edges[p], - g = r.qNode.edges[d], - L = b.final && g.final, - f = void 0; - p in r.output.edges - ? ((f = r.output.edges[p]), (f.final = f.final || L)) - : ((f = new t.TokenSet()), - (f.final = L), - (r.output.edges[p] = f)), - i.push({ qNode: g, output: f, node: b }); - } - } - } - return n; - }), - (t.TokenSet.Builder = function () { - (this.previousWord = ""), - (this.root = new t.TokenSet()), - (this.uncheckedNodes = []), - (this.minimizedNodes = {}); - }), - (t.TokenSet.Builder.prototype.insert = function (e) { - var n, - r = 0; - if (e < this.previousWord) - throw new Error("Out of order word insertion"); - for ( - var i = 0; - i < e.length && - i < this.previousWord.length && - e[i] == this.previousWord[i]; - i++ - ) - r++; - this.minimize(r), - this.uncheckedNodes.length == 0 - ? (n = this.root) - : (n = this.uncheckedNodes[this.uncheckedNodes.length - 1].child); - for (var i = r; i < e.length; i++) { - var s = new t.TokenSet(), - o = e[i]; - (n.edges[o] = s), - this.uncheckedNodes.push({ parent: n, char: o, child: s }), - (n = s); - } - (n.final = !0), (this.previousWord = e); - }), - (t.TokenSet.Builder.prototype.finish = function () { - this.minimize(0); - }), - (t.TokenSet.Builder.prototype.minimize = function (e) { - for (var n = this.uncheckedNodes.length - 1; n >= e; n--) { - var r = this.uncheckedNodes[n], - i = r.child.toString(); - i in this.minimizedNodes - ? (r.parent.edges[r.char] = this.minimizedNodes[i]) - : ((r.child._str = i), (this.minimizedNodes[i] = r.child)), - this.uncheckedNodes.pop(); - } - }); - (t.Index = function (e) { - (this.invertedIndex = e.invertedIndex), - (this.fieldVectors = e.fieldVectors), - (this.tokenSet = e.tokenSet), - (this.fields = e.fields), - (this.pipeline = e.pipeline); - }), - (t.Index.prototype.search = function (e) { - return this.query(function (n) { - var r = new t.QueryParser(e, n); - r.parse(); - }); - }), - (t.Index.prototype.query = function (e) { - for ( - var n = new t.Query(this.fields), - r = Object.create(null), - i = Object.create(null), - s = Object.create(null), - o = Object.create(null), - a = Object.create(null), - l = 0; - l < this.fields.length; - l++ - ) - i[this.fields[l]] = new t.Vector(); - e.call(n, n); - for (var l = 0; l < n.clauses.length; l++) { - var u = n.clauses[l], - d = null, - y = t.Set.empty; - u.usePipeline - ? (d = this.pipeline.runString(u.term, { fields: u.fields })) - : (d = [u.term]); - for (var p = 0; p < d.length; p++) { - var b = d[p]; - u.term = b; - var g = t.TokenSet.fromClause(u), - L = this.tokenSet.intersect(g).toArray(); - if (L.length === 0 && u.presence === t.Query.presence.REQUIRED) { - for (var f = 0; f < u.fields.length; f++) { - var m = u.fields[f]; - o[m] = t.Set.empty; - } - break; - } - for (var S = 0; S < L.length; S++) - for ( - var w = L[S], k = this.invertedIndex[w], _ = k._index, f = 0; - f < u.fields.length; - f++ - ) { - var m = u.fields[f], - B = k[m], - A = Object.keys(B), - j = w + "/" + m, - $ = new t.Set(A); - if ( - (u.presence == t.Query.presence.REQUIRED && - ((y = y.union($)), - o[m] === void 0 && (o[m] = t.Set.complete)), - u.presence == t.Query.presence.PROHIBITED) - ) { - a[m] === void 0 && (a[m] = t.Set.empty), - (a[m] = a[m].union($)); - continue; - } - if ( - (i[m].upsert(_, u.boost, function (Qe, Ie) { - return Qe + Ie; - }), - !s[j]) - ) { - for (var V = 0; V < A.length; V++) { - var q = A[V], - C = new t.FieldRef(q, m), - z = B[q], - W; - (W = r[C]) === void 0 - ? (r[C] = new t.MatchData(w, m, z)) - : W.add(w, m, z); - } - s[j] = !0; - } - } - } - if (u.presence === t.Query.presence.REQUIRED) - for (var f = 0; f < u.fields.length; f++) { - var m = u.fields[f]; - o[m] = o[m].intersect(y); - } - } - for ( - var N = t.Set.complete, R = t.Set.empty, l = 0; - l < this.fields.length; - l++ - ) { - var m = this.fields[l]; - o[m] && (N = N.intersect(o[m])), a[m] && (R = R.union(a[m])); - } - var c = Object.keys(r), - v = [], - P = Object.create(null); - if (n.isNegated()) { - c = Object.keys(this.fieldVectors); - for (var l = 0; l < c.length; l++) { - var C = c[l], - T = t.FieldRef.fromString(C); - r[C] = new t.MatchData(); - } - } - for (var l = 0; l < c.length; l++) { - var T = t.FieldRef.fromString(c[l]), - h = T.docRef; - if (N.contains(h) && !R.contains(h)) { - var x = this.fieldVectors[T], - O = i[T.fieldName].similarity(x), - M; - if ((M = P[h]) !== void 0) - (M.score += O), M.matchData.combine(r[T]); - else { - var E = { ref: h, score: O, matchData: r[T] }; - (P[h] = E), v.push(E); - } - } - } - return v.sort(function (Te, ke) { - return ke.score - Te.score; - }); - }), - (t.Index.prototype.toJSON = function () { - var e = Object.keys(this.invertedIndex) - .sort() - .map(function (r) { - return [r, this.invertedIndex[r]]; - }, this), - n = Object.keys(this.fieldVectors).map(function (r) { - return [r, this.fieldVectors[r].toJSON()]; - }, this); - return { - version: t.version, - fields: this.fields, - fieldVectors: n, - invertedIndex: e, - pipeline: this.pipeline.toJSON(), - }; - }), - (t.Index.load = function (e) { - var n = {}, - r = {}, - i = e.fieldVectors, - s = Object.create(null), - o = e.invertedIndex, - a = new t.TokenSet.Builder(), - l = t.Pipeline.load(e.pipeline); - e.version != t.version && - t.utils.warn( - "Version mismatch when loading serialised index. Current version of lunr '" + - t.version + - "' does not match serialized index '" + - e.version + - "'", - ); - for (var u = 0; u < i.length; u++) { - var d = i[u], - y = d[0], - p = d[1]; - r[y] = new t.Vector(p); - } - for (var u = 0; u < o.length; u++) { - var d = o[u], - b = d[0], - g = d[1]; - a.insert(b), (s[b] = g); - } - return ( - a.finish(), - (n.fields = e.fields), - (n.fieldVectors = r), - (n.invertedIndex = s), - (n.tokenSet = a.root), - (n.pipeline = l), - new t.Index(n) - ); - }); - (t.Builder = function () { - (this._ref = "id"), - (this._fields = Object.create(null)), - (this._documents = Object.create(null)), - (this.invertedIndex = Object.create(null)), - (this.fieldTermFrequencies = {}), - (this.fieldLengths = {}), - (this.tokenizer = t.tokenizer), - (this.pipeline = new t.Pipeline()), - (this.searchPipeline = new t.Pipeline()), - (this.documentCount = 0), - (this._b = 0.75), - (this._k1 = 1.2), - (this.termIndex = 0), - (this.metadataWhitelist = []); - }), - (t.Builder.prototype.ref = function (e) { - this._ref = e; - }), - (t.Builder.prototype.field = function (e, n) { - if (/\//.test(e)) - throw new RangeError( - "Field '" + e + "' contains illegal character '/'", - ); - this._fields[e] = n || {}; - }), - (t.Builder.prototype.b = function (e) { - e < 0 ? (this._b = 0) : e > 1 ? (this._b = 1) : (this._b = e); - }), - (t.Builder.prototype.k1 = function (e) { - this._k1 = e; - }), - (t.Builder.prototype.add = function (e, n) { - var r = e[this._ref], - i = Object.keys(this._fields); - (this._documents[r] = n || {}), (this.documentCount += 1); - for (var s = 0; s < i.length; s++) { - var o = i[s], - a = this._fields[o].extractor, - l = a ? a(e) : e[o], - u = this.tokenizer(l, { fields: [o] }), - d = this.pipeline.run(u), - y = new t.FieldRef(r, o), - p = Object.create(null); - (this.fieldTermFrequencies[y] = p), - (this.fieldLengths[y] = 0), - (this.fieldLengths[y] += d.length); - for (var b = 0; b < d.length; b++) { - var g = d[b]; - if ( - (p[g] == null && (p[g] = 0), - (p[g] += 1), - this.invertedIndex[g] == null) - ) { - var L = Object.create(null); - (L._index = this.termIndex), (this.termIndex += 1); - for (var f = 0; f < i.length; f++) - L[i[f]] = Object.create(null); - this.invertedIndex[g] = L; - } - this.invertedIndex[g][o][r] == null && - (this.invertedIndex[g][o][r] = Object.create(null)); - for (var m = 0; m < this.metadataWhitelist.length; m++) { - var S = this.metadataWhitelist[m], - w = g.metadata[S]; - this.invertedIndex[g][o][r][S] == null && - (this.invertedIndex[g][o][r][S] = []), - this.invertedIndex[g][o][r][S].push(w); - } - } - } - }), - (t.Builder.prototype.calculateAverageFieldLengths = function () { - for ( - var e = Object.keys(this.fieldLengths), - n = e.length, - r = {}, - i = {}, - s = 0; - s < n; - s++ - ) { - var o = t.FieldRef.fromString(e[s]), - a = o.fieldName; - i[a] || (i[a] = 0), - (i[a] += 1), - r[a] || (r[a] = 0), - (r[a] += this.fieldLengths[o]); - } - for (var l = Object.keys(this._fields), s = 0; s < l.length; s++) { - var u = l[s]; - r[u] = r[u] / i[u]; - } - this.averageFieldLength = r; - }), - (t.Builder.prototype.createFieldVectors = function () { - for ( - var e = {}, - n = Object.keys(this.fieldTermFrequencies), - r = n.length, - i = Object.create(null), - s = 0; - s < r; - s++ - ) { - for ( - var o = t.FieldRef.fromString(n[s]), - a = o.fieldName, - l = this.fieldLengths[o], - u = new t.Vector(), - d = this.fieldTermFrequencies[o], - y = Object.keys(d), - p = y.length, - b = this._fields[a].boost || 1, - g = this._documents[o.docRef].boost || 1, - L = 0; - L < p; - L++ - ) { - var f = y[L], - m = d[f], - S = this.invertedIndex[f]._index, - w, - k, - _; - i[f] === void 0 - ? ((w = t.idf(this.invertedIndex[f], this.documentCount)), - (i[f] = w)) - : (w = i[f]), - (k = - (w * ((this._k1 + 1) * m)) / - (this._k1 * - (1 - this._b + this._b * (l / this.averageFieldLength[a])) + - m)), - (k *= b), - (k *= g), - (_ = Math.round(k * 1e3) / 1e3), - u.insert(S, _); - } - e[o] = u; - } - this.fieldVectors = e; - }), - (t.Builder.prototype.createTokenSet = function () { - this.tokenSet = t.TokenSet.fromArray( - Object.keys(this.invertedIndex).sort(), - ); - }), - (t.Builder.prototype.build = function () { - return ( - this.calculateAverageFieldLengths(), - this.createFieldVectors(), - this.createTokenSet(), - new t.Index({ - invertedIndex: this.invertedIndex, - fieldVectors: this.fieldVectors, - tokenSet: this.tokenSet, - fields: Object.keys(this._fields), - pipeline: this.searchPipeline, - }) - ); - }), - (t.Builder.prototype.use = function (e) { - var n = Array.prototype.slice.call(arguments, 1); - n.unshift(this), e.apply(this, n); - }), - (t.MatchData = function (e, n, r) { - for ( - var i = Object.create(null), s = Object.keys(r || {}), o = 0; - o < s.length; - o++ - ) { - var a = s[o]; - i[a] = r[a].slice(); - } - (this.metadata = Object.create(null)), - e !== void 0 && - ((this.metadata[e] = Object.create(null)), - (this.metadata[e][n] = i)); - }), - (t.MatchData.prototype.combine = function (e) { - for (var n = Object.keys(e.metadata), r = 0; r < n.length; r++) { - var i = n[r], - s = Object.keys(e.metadata[i]); - this.metadata[i] == null && - (this.metadata[i] = Object.create(null)); - for (var o = 0; o < s.length; o++) { - var a = s[o], - l = Object.keys(e.metadata[i][a]); - this.metadata[i][a] == null && - (this.metadata[i][a] = Object.create(null)); - for (var u = 0; u < l.length; u++) { - var d = l[u]; - this.metadata[i][a][d] == null - ? (this.metadata[i][a][d] = e.metadata[i][a][d]) - : (this.metadata[i][a][d] = this.metadata[i][a][d].concat( - e.metadata[i][a][d], - )); - } - } - } - }), - (t.MatchData.prototype.add = function (e, n, r) { - if (!(e in this.metadata)) { - (this.metadata[e] = Object.create(null)), (this.metadata[e][n] = r); - return; - } - if (!(n in this.metadata[e])) { - this.metadata[e][n] = r; - return; - } - for (var i = Object.keys(r), s = 0; s < i.length; s++) { - var o = i[s]; - o in this.metadata[e][n] - ? (this.metadata[e][n][o] = this.metadata[e][n][o].concat(r[o])) - : (this.metadata[e][n][o] = r[o]); - } - }), - (t.Query = function (e) { - (this.clauses = []), (this.allFields = e); - }), - (t.Query.wildcard = new String("*")), - (t.Query.wildcard.NONE = 0), - (t.Query.wildcard.LEADING = 1), - (t.Query.wildcard.TRAILING = 2), - (t.Query.presence = { OPTIONAL: 1, REQUIRED: 2, PROHIBITED: 3 }), - (t.Query.prototype.clause = function (e) { - return ( - "fields" in e || (e.fields = this.allFields), - "boost" in e || (e.boost = 1), - "usePipeline" in e || (e.usePipeline = !0), - "wildcard" in e || (e.wildcard = t.Query.wildcard.NONE), - e.wildcard & t.Query.wildcard.LEADING && - e.term.charAt(0) != t.Query.wildcard && - (e.term = "*" + e.term), - e.wildcard & t.Query.wildcard.TRAILING && - e.term.slice(-1) != t.Query.wildcard && - (e.term = "" + e.term + "*"), - "presence" in e || (e.presence = t.Query.presence.OPTIONAL), - this.clauses.push(e), - this - ); - }), - (t.Query.prototype.isNegated = function () { - for (var e = 0; e < this.clauses.length; e++) - if (this.clauses[e].presence != t.Query.presence.PROHIBITED) - return !1; - return !0; - }), - (t.Query.prototype.term = function (e, n) { - if (Array.isArray(e)) - return ( - e.forEach(function (i) { - this.term(i, t.utils.clone(n)); - }, this), - this - ); - var r = n || {}; - return (r.term = e.toString()), this.clause(r), this; - }), - (t.QueryParseError = function (e, n, r) { - (this.name = "QueryParseError"), - (this.message = e), - (this.start = n), - (this.end = r); - }), - (t.QueryParseError.prototype = new Error()), - (t.QueryLexer = function (e) { - (this.lexemes = []), - (this.str = e), - (this.length = e.length), - (this.pos = 0), - (this.start = 0), - (this.escapeCharPositions = []); - }), - (t.QueryLexer.prototype.run = function () { - for (var e = t.QueryLexer.lexText; e; ) e = e(this); - }), - (t.QueryLexer.prototype.sliceString = function () { - for ( - var e = [], n = this.start, r = this.pos, i = 0; - i < this.escapeCharPositions.length; - i++ - ) - (r = this.escapeCharPositions[i]), - e.push(this.str.slice(n, r)), - (n = r + 1); - return ( - e.push(this.str.slice(n, this.pos)), - (this.escapeCharPositions.length = 0), - e.join("") - ); - }), - (t.QueryLexer.prototype.emit = function (e) { - this.lexemes.push({ - type: e, - str: this.sliceString(), - start: this.start, - end: this.pos, - }), - (this.start = this.pos); - }), - (t.QueryLexer.prototype.escapeCharacter = function () { - this.escapeCharPositions.push(this.pos - 1), (this.pos += 1); - }), - (t.QueryLexer.prototype.next = function () { - if (this.pos >= this.length) return t.QueryLexer.EOS; - var e = this.str.charAt(this.pos); - return (this.pos += 1), e; - }), - (t.QueryLexer.prototype.width = function () { - return this.pos - this.start; - }), - (t.QueryLexer.prototype.ignore = function () { - this.start == this.pos && (this.pos += 1), (this.start = this.pos); - }), - (t.QueryLexer.prototype.backup = function () { - this.pos -= 1; - }), - (t.QueryLexer.prototype.acceptDigitRun = function () { - var e, n; - do (e = this.next()), (n = e.charCodeAt(0)); - while (n > 47 && n < 58); - e != t.QueryLexer.EOS && this.backup(); - }), - (t.QueryLexer.prototype.more = function () { - return this.pos < this.length; - }), - (t.QueryLexer.EOS = "EOS"), - (t.QueryLexer.FIELD = "FIELD"), - (t.QueryLexer.TERM = "TERM"), - (t.QueryLexer.EDIT_DISTANCE = "EDIT_DISTANCE"), - (t.QueryLexer.BOOST = "BOOST"), - (t.QueryLexer.PRESENCE = "PRESENCE"), - (t.QueryLexer.lexField = function (e) { - return ( - e.backup(), - e.emit(t.QueryLexer.FIELD), - e.ignore(), - t.QueryLexer.lexText - ); - }), - (t.QueryLexer.lexTerm = function (e) { - if ( - (e.width() > 1 && (e.backup(), e.emit(t.QueryLexer.TERM)), - e.ignore(), - e.more()) - ) - return t.QueryLexer.lexText; - }), - (t.QueryLexer.lexEditDistance = function (e) { - return ( - e.ignore(), - e.acceptDigitRun(), - e.emit(t.QueryLexer.EDIT_DISTANCE), - t.QueryLexer.lexText - ); - }), - (t.QueryLexer.lexBoost = function (e) { - return ( - e.ignore(), - e.acceptDigitRun(), - e.emit(t.QueryLexer.BOOST), - t.QueryLexer.lexText - ); - }), - (t.QueryLexer.lexEOS = function (e) { - e.width() > 0 && e.emit(t.QueryLexer.TERM); - }), - (t.QueryLexer.termSeparator = t.tokenizer.separator), - (t.QueryLexer.lexText = function (e) { - for (;;) { - var n = e.next(); - if (n == t.QueryLexer.EOS) return t.QueryLexer.lexEOS; - if (n.charCodeAt(0) == 92) { - e.escapeCharacter(); - continue; - } - if (n == ":") return t.QueryLexer.lexField; - if (n == "~") - return ( - e.backup(), - e.width() > 0 && e.emit(t.QueryLexer.TERM), - t.QueryLexer.lexEditDistance - ); - if (n == "^") - return ( - e.backup(), - e.width() > 0 && e.emit(t.QueryLexer.TERM), - t.QueryLexer.lexBoost - ); - if ((n == "+" && e.width() === 1) || (n == "-" && e.width() === 1)) - return e.emit(t.QueryLexer.PRESENCE), t.QueryLexer.lexText; - if (n.match(t.QueryLexer.termSeparator)) - return t.QueryLexer.lexTerm; - } - }), - (t.QueryParser = function (e, n) { - (this.lexer = new t.QueryLexer(e)), - (this.query = n), - (this.currentClause = {}), - (this.lexemeIdx = 0); - }), - (t.QueryParser.prototype.parse = function () { - this.lexer.run(), (this.lexemes = this.lexer.lexemes); - for (var e = t.QueryParser.parseClause; e; ) e = e(this); - return this.query; - }), - (t.QueryParser.prototype.peekLexeme = function () { - return this.lexemes[this.lexemeIdx]; - }), - (t.QueryParser.prototype.consumeLexeme = function () { - var e = this.peekLexeme(); - return (this.lexemeIdx += 1), e; - }), - (t.QueryParser.prototype.nextClause = function () { - var e = this.currentClause; - this.query.clause(e), (this.currentClause = {}); - }), - (t.QueryParser.parseClause = function (e) { - var n = e.peekLexeme(); - if (n != null) - switch (n.type) { - case t.QueryLexer.PRESENCE: - return t.QueryParser.parsePresence; - case t.QueryLexer.FIELD: - return t.QueryParser.parseField; - case t.QueryLexer.TERM: - return t.QueryParser.parseTerm; - default: - var r = "expected either a field or a term, found " + n.type; - throw ( - (n.str.length >= 1 && (r += " with value '" + n.str + "'"), - new t.QueryParseError(r, n.start, n.end)) - ); - } - }), - (t.QueryParser.parsePresence = function (e) { - var n = e.consumeLexeme(); - if (n != null) { - switch (n.str) { - case "-": - e.currentClause.presence = t.Query.presence.PROHIBITED; - break; - case "+": - e.currentClause.presence = t.Query.presence.REQUIRED; - break; - default: - var r = "unrecognised presence operator'" + n.str + "'"; - throw new t.QueryParseError(r, n.start, n.end); - } - var i = e.peekLexeme(); - if (i == null) { - var r = "expecting term or field, found nothing"; - throw new t.QueryParseError(r, n.start, n.end); - } - switch (i.type) { - case t.QueryLexer.FIELD: - return t.QueryParser.parseField; - case t.QueryLexer.TERM: - return t.QueryParser.parseTerm; - default: - var r = "expecting term or field, found '" + i.type + "'"; - throw new t.QueryParseError(r, i.start, i.end); - } - } - }), - (t.QueryParser.parseField = function (e) { - var n = e.consumeLexeme(); - if (n != null) { - if (e.query.allFields.indexOf(n.str) == -1) { - var r = e.query.allFields - .map(function (o) { - return "'" + o + "'"; - }) - .join(", "), - i = "unrecognised field '" + n.str + "', possible fields: " + r; - throw new t.QueryParseError(i, n.start, n.end); - } - e.currentClause.fields = [n.str]; - var s = e.peekLexeme(); - if (s == null) { - var i = "expecting term, found nothing"; - throw new t.QueryParseError(i, n.start, n.end); - } - switch (s.type) { - case t.QueryLexer.TERM: - return t.QueryParser.parseTerm; - default: - var i = "expecting term, found '" + s.type + "'"; - throw new t.QueryParseError(i, s.start, s.end); - } - } - }), - (t.QueryParser.parseTerm = function (e) { - var n = e.consumeLexeme(); - if (n != null) { - (e.currentClause.term = n.str.toLowerCase()), - n.str.indexOf("*") != -1 && (e.currentClause.usePipeline = !1); - var r = e.peekLexeme(); - if (r == null) { - e.nextClause(); - return; - } - switch (r.type) { - case t.QueryLexer.TERM: - return e.nextClause(), t.QueryParser.parseTerm; - case t.QueryLexer.FIELD: - return e.nextClause(), t.QueryParser.parseField; - case t.QueryLexer.EDIT_DISTANCE: - return t.QueryParser.parseEditDistance; - case t.QueryLexer.BOOST: - return t.QueryParser.parseBoost; - case t.QueryLexer.PRESENCE: - return e.nextClause(), t.QueryParser.parsePresence; - default: - var i = "Unexpected lexeme type '" + r.type + "'"; - throw new t.QueryParseError(i, r.start, r.end); - } - } - }), - (t.QueryParser.parseEditDistance = function (e) { - var n = e.consumeLexeme(); - if (n != null) { - var r = parseInt(n.str, 10); - if (isNaN(r)) { - var i = "edit distance must be numeric"; - throw new t.QueryParseError(i, n.start, n.end); - } - e.currentClause.editDistance = r; - var s = e.peekLexeme(); - if (s == null) { - e.nextClause(); - return; - } - switch (s.type) { - case t.QueryLexer.TERM: - return e.nextClause(), t.QueryParser.parseTerm; - case t.QueryLexer.FIELD: - return e.nextClause(), t.QueryParser.parseField; - case t.QueryLexer.EDIT_DISTANCE: - return t.QueryParser.parseEditDistance; - case t.QueryLexer.BOOST: - return t.QueryParser.parseBoost; - case t.QueryLexer.PRESENCE: - return e.nextClause(), t.QueryParser.parsePresence; - default: - var i = "Unexpected lexeme type '" + s.type + "'"; - throw new t.QueryParseError(i, s.start, s.end); - } - } - }), - (t.QueryParser.parseBoost = function (e) { - var n = e.consumeLexeme(); - if (n != null) { - var r = parseInt(n.str, 10); - if (isNaN(r)) { - var i = "boost must be numeric"; - throw new t.QueryParseError(i, n.start, n.end); - } - e.currentClause.boost = r; - var s = e.peekLexeme(); - if (s == null) { - e.nextClause(); - return; - } - switch (s.type) { - case t.QueryLexer.TERM: - return e.nextClause(), t.QueryParser.parseTerm; - case t.QueryLexer.FIELD: - return e.nextClause(), t.QueryParser.parseField; - case t.QueryLexer.EDIT_DISTANCE: - return t.QueryParser.parseEditDistance; - case t.QueryLexer.BOOST: - return t.QueryParser.parseBoost; - case t.QueryLexer.PRESENCE: - return e.nextClause(), t.QueryParser.parsePresence; - default: - var i = "Unexpected lexeme type '" + s.type + "'"; - throw new t.QueryParseError(i, s.start, s.end); - } - } - }), - (function (e, n) { - typeof define == "function" && define.amd - ? define(n) - : typeof se == "object" - ? (oe.exports = n()) - : (e.lunr = n()); - })(this, function () { - return t; - }); - })(); - }); - var re = []; - function G(t, e) { - re.push({ selector: e, constructor: t }); - } - var U = class { - constructor() { - this.alwaysVisibleMember = null; - this.createComponents(document.body), - this.ensureFocusedElementVisible(), - this.listenForCodeCopies(), - window.addEventListener("hashchange", () => - this.ensureFocusedElementVisible(), - ), - document.body.style.display || - (this.ensureFocusedElementVisible(), - this.updateIndexVisibility(), - this.scrollToHash()); - } - createComponents(e) { - re.forEach((n) => { - e.querySelectorAll(n.selector).forEach((r) => { - r.dataset.hasInstance || - (new n.constructor({ el: r, app: this }), - (r.dataset.hasInstance = String(!0))); - }); - }); - } - filterChanged() { - this.ensureFocusedElementVisible(); - } - showPage() { - document.body.style.display && - (console.log("Show page"), - document.body.style.removeProperty("display"), - this.ensureFocusedElementVisible(), - this.updateIndexVisibility(), - this.scrollToHash()); - } - scrollToHash() { - if (location.hash) { - console.log("Scorlling"); - let e = document.getElementById(location.hash.substring(1)); - if (!e) return; - e.scrollIntoView({ behavior: "instant", block: "start" }); - } - } - ensureActivePageVisible() { - let e = document.querySelector(".tsd-navigation .current"), - n = e?.parentElement; - for (; n && !n.classList.contains(".tsd-navigation"); ) - n instanceof HTMLDetailsElement && (n.open = !0), (n = n.parentElement); - if (e && !e.checkVisibility()) { - let r = - e.getBoundingClientRect().top - - document.documentElement.clientHeight / 4; - document.querySelector(".site-menu").scrollTop = r; - } - } - updateIndexVisibility() { - let e = document.querySelector(".tsd-index-content"), - n = e?.open; - e && (e.open = !0), - document.querySelectorAll(".tsd-index-section").forEach((r) => { - r.style.display = "block"; - let i = Array.from(r.querySelectorAll(".tsd-index-link")).every( - (s) => s.offsetParent == null, - ); - r.style.display = i ? "none" : "block"; - }), - e && (e.open = n); - } - ensureFocusedElementVisible() { - if ( - (this.alwaysVisibleMember && - (this.alwaysVisibleMember.classList.remove("always-visible"), - this.alwaysVisibleMember.firstElementChild.remove(), - (this.alwaysVisibleMember = null)), - !location.hash) - ) - return; - let e = document.getElementById(location.hash.substring(1)); - if (!e) return; - let n = e.parentElement; - for (; n && n.tagName !== "SECTION"; ) n = n.parentElement; - if (n && n.offsetParent == null) { - (this.alwaysVisibleMember = n), n.classList.add("always-visible"); - let r = document.createElement("p"); - r.classList.add("warning"), - (r.textContent = - "This member is normally hidden due to your filter settings."), - n.prepend(r); - } - } - listenForCodeCopies() { - document.querySelectorAll("pre > button").forEach((e) => { - let n; - e.addEventListener("click", () => { - e.previousElementSibling instanceof HTMLElement && - navigator.clipboard.writeText( - e.previousElementSibling.innerText.trim(), - ), - (e.textContent = "Copied!"), - e.classList.add("visible"), - clearTimeout(n), - (n = setTimeout(() => { - e.classList.remove("visible"), - (n = setTimeout(() => { - e.textContent = "Copy"; - }, 100)); - }, 1e3)); - }); - }); - } - }; - var ie = (t, e = 100) => { - let n; - return () => { - clearTimeout(n), (n = setTimeout(() => t(), e)); - }; - }; - var de = De(ae()); - async function le(t, e) { - if (!window.searchData) return; - let n = await fetch(window.searchData), - r = new Blob([await n.arrayBuffer()]) - .stream() - .pipeThrough(new DecompressionStream("gzip")), - i = await new Response(r).json(); - (t.data = i), - (t.index = de.Index.load(i.index)), - e.classList.remove("loading"), - e.classList.add("ready"); - } - function he() { - let t = document.getElementById("tsd-search"); - if (!t) return; - let e = { base: t.dataset.base + "/" }, - n = document.getElementById("tsd-search-script"); - t.classList.add("loading"), - n && - (n.addEventListener("error", () => { - t.classList.remove("loading"), t.classList.add("failure"); - }), - n.addEventListener("load", () => { - le(e, t); - }), - le(e, t)); - let r = document.querySelector("#tsd-search input"), - i = document.querySelector("#tsd-search .results"); - if (!r || !i) - throw new Error( - "The input field or the result list wrapper was not found", - ); - let s = !1; - i.addEventListener("mousedown", () => (s = !0)), - i.addEventListener("mouseup", () => { - (s = !1), t.classList.remove("has-focus"); - }), - r.addEventListener("focus", () => t.classList.add("has-focus")), - r.addEventListener("blur", () => { - s || ((s = !1), t.classList.remove("has-focus")); - }), - Ae(t, i, r, e); - } - function Ae(t, e, n, r) { - n.addEventListener( - "input", - ie(() => { - Ve(t, e, n, r); - }, 200), - ); - let i = !1; - n.addEventListener("keydown", (s) => { - (i = !0), - s.key == "Enter" - ? Ne(e, n) - : s.key == "Escape" - ? n.blur() - : s.key == "ArrowUp" - ? ue(e, -1) - : s.key === "ArrowDown" - ? ue(e, 1) - : (i = !1); - }), - n.addEventListener("keypress", (s) => { - i && s.preventDefault(); - }), - document.body.addEventListener("keydown", (s) => { - s.altKey || - s.ctrlKey || - s.metaKey || - (!n.matches(":focus") && - s.key === "/" && - (n.focus(), s.preventDefault())); - }); - } - function Ve(t, e, n, r) { - if (!r.index || !r.data) return; - e.textContent = ""; - let i = n.value.trim(), - s; - if (i) { - let o = i - .split(" ") - .map((a) => (a.length ? `*${a}*` : "")) - .join(" "); - s = r.index.search(o); - } else s = []; - for (let o = 0; o < s.length; o++) { - let a = s[o], - l = r.data.rows[Number(a.ref)], - u = 1; - l.name.toLowerCase().startsWith(i.toLowerCase()) && - (u *= 1 + 1 / (1 + Math.abs(l.name.length - i.length))), - (a.score *= u); - } - if (s.length === 0) { - let o = document.createElement("li"); - o.classList.add("no-results"); - let a = document.createElement("span"); - (a.textContent = "No results found"), o.appendChild(a), e.appendChild(o); - } - s.sort((o, a) => a.score - o.score); - for (let o = 0, a = Math.min(10, s.length); o < a; o++) { - let l = r.data.rows[Number(s[o].ref)], - u = ``, - d = ce(l.name, i); - globalThis.DEBUG_SEARCH_WEIGHTS && - (d += ` (score: ${s[o].score.toFixed(2)})`), - l.parent && - (d = ` - ${ce(l.parent, i)}.${d}`); - let y = document.createElement("li"); - y.classList.value = l.classes ?? ""; - let p = document.createElement("a"); - (p.href = r.base + l.url), - (p.innerHTML = u + d), - y.append(p), - e.appendChild(y); - } - } - function ue(t, e) { - let n = t.querySelector(".current"); - if (!n) - (n = t.querySelector(e == 1 ? "li:first-child" : "li:last-child")), - n && n.classList.add("current"); - else { - let r = n; - if (e === 1) - do r = r.nextElementSibling ?? void 0; - while (r instanceof HTMLElement && r.offsetParent == null); - else - do r = r.previousElementSibling ?? void 0; - while (r instanceof HTMLElement && r.offsetParent == null); - r && (n.classList.remove("current"), r.classList.add("current")); - } - } - function Ne(t, e) { - let n = t.querySelector(".current"); - if ((n || (n = t.querySelector("li:first-child")), n)) { - let r = n.querySelector("a"); - r && (window.location.href = r.href), e.blur(); - } - } - function ce(t, e) { - if (e === "") return t; - let n = t.toLocaleLowerCase(), - r = e.toLocaleLowerCase(), - i = [], - s = 0, - o = n.indexOf(r); - for (; o != -1; ) - i.push(K(t.substring(s, o)), `${K(t.substring(o, o + r.length))}`), - (s = o + r.length), - (o = n.indexOf(r, s)); - return i.push(K(t.substring(s))), i.join(""); - } - var He = { - "&": "&", - "<": "<", - ">": ">", - "'": "'", - '"': """, - }; - function K(t) { - return t.replace(/[&<>"'"]/g, (e) => He[e]); - } - var I = class { - constructor(e) { - (this.el = e.el), (this.app = e.app); - } - }; - var F = "mousedown", - fe = "mousemove", - H = "mouseup", - J = { x: 0, y: 0 }, - pe = !1, - ee = !1, - Be = !1, - D = !1, - me = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( - navigator.userAgent, - ); - document.documentElement.classList.add(me ? "is-mobile" : "not-mobile"); - me && - "ontouchstart" in document.documentElement && - ((Be = !0), (F = "touchstart"), (fe = "touchmove"), (H = "touchend")); - document.addEventListener(F, (t) => { - (ee = !0), (D = !1); - let e = F == "touchstart" ? t.targetTouches[0] : t; - (J.y = e.pageY || 0), (J.x = e.pageX || 0); - }); - document.addEventListener(fe, (t) => { - if (ee && !D) { - let e = F == "touchstart" ? t.targetTouches[0] : t, - n = J.x - (e.pageX || 0), - r = J.y - (e.pageY || 0); - D = Math.sqrt(n * n + r * r) > 10; - } - }); - document.addEventListener(H, () => { - ee = !1; - }); - document.addEventListener("click", (t) => { - pe && (t.preventDefault(), t.stopImmediatePropagation(), (pe = !1)); - }); - var X = class extends I { - constructor(e) { - super(e), - (this.className = this.el.dataset.toggle || ""), - this.el.addEventListener(H, (n) => this.onPointerUp(n)), - this.el.addEventListener("click", (n) => n.preventDefault()), - document.addEventListener(F, (n) => this.onDocumentPointerDown(n)), - document.addEventListener(H, (n) => this.onDocumentPointerUp(n)); - } - setActive(e) { - if (this.active == e) return; - (this.active = e), - document.documentElement.classList.toggle("has-" + this.className, e), - this.el.classList.toggle("active", e); - let n = (this.active ? "to-has-" : "from-has-") + this.className; - document.documentElement.classList.add(n), - setTimeout(() => document.documentElement.classList.remove(n), 500); - } - onPointerUp(e) { - D || (this.setActive(!0), e.preventDefault()); - } - onDocumentPointerDown(e) { - if (this.active) { - if (e.target.closest(".col-sidebar, .tsd-filter-group")) return; - this.setActive(!1); - } - } - onDocumentPointerUp(e) { - if (!D && this.active && e.target.closest(".col-sidebar")) { - let n = e.target.closest("a"); - if (n) { - let r = window.location.href; - r.indexOf("#") != -1 && (r = r.substring(0, r.indexOf("#"))), - n.href.substring(0, r.length) == r && - setTimeout(() => this.setActive(!1), 250); - } - } - } - }; - var te; - try { - te = localStorage; - } catch { - te = { - getItem() { - return null; - }, - setItem() {}, - }; - } - var Q = te; - var ye = document.head.appendChild(document.createElement("style")); - ye.dataset.for = "filters"; - var Y = class extends I { - constructor(e) { - super(e), - (this.key = `filter-${this.el.name}`), - (this.value = this.el.checked), - this.el.addEventListener("change", () => { - this.setLocalStorage(this.el.checked); - }), - this.setLocalStorage(this.fromLocalStorage()), - (ye.innerHTML += `html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } -`), - this.app.updateIndexVisibility(); - } - fromLocalStorage() { - let e = Q.getItem(this.key); - return e ? e === "true" : this.el.checked; - } - setLocalStorage(e) { - Q.setItem(this.key, e.toString()), - (this.value = e), - this.handleValueChange(); - } - handleValueChange() { - (this.el.checked = this.value), - document.documentElement.classList.toggle(this.key, this.value), - this.app.filterChanged(), - this.app.updateIndexVisibility(); - } - }; - var Z = class extends I { - constructor(e) { - super(e), - (this.summary = this.el.querySelector(".tsd-accordion-summary")), - (this.icon = this.summary.querySelector("svg")), - (this.key = `tsd-accordion-${this.summary.dataset.key ?? this.summary.textContent.trim().replace(/\s+/g, "-").toLowerCase()}`); - let n = Q.getItem(this.key); - (this.el.open = n ? n === "true" : this.el.open), - this.el.addEventListener("toggle", () => this.update()); - let r = this.summary.querySelector("a"); - r && - r.addEventListener("click", () => { - location.assign(r.href); - }), - this.update(); - } - update() { - (this.icon.style.transform = `rotate(${this.el.open ? 0 : -90}deg)`), - Q.setItem(this.key, this.el.open.toString()); - } - }; - function ge(t) { - let e = Q.getItem("tsd-theme") || "os"; - (t.value = e), - ve(e), - t.addEventListener("change", () => { - Q.setItem("tsd-theme", t.value), ve(t.value); - }); - } - function ve(t) { - document.documentElement.dataset.theme = t; - } - var Le; - function be() { - let t = document.getElementById("tsd-nav-script"); - t && (t.addEventListener("load", xe), xe()); - } - async function xe() { - let t = document.getElementById("tsd-nav-container"); - if (!t || !window.navigationData) return; - let n = await (await fetch(window.navigationData)).arrayBuffer(), - r = new Blob([n]).stream().pipeThrough(new DecompressionStream("gzip")), - i = await new Response(r).json(); - (Le = t.dataset.base + "/"), (t.innerHTML = ""); - for (let s of i) we(s, t, []); - window.app.createComponents(t), - window.app.showPage(), - window.app.ensureActivePageVisible(); - } - function we(t, e, n) { - let r = e.appendChild(document.createElement("li")); - if (t.children) { - let i = [...n, t.text], - s = r.appendChild(document.createElement("details")); - (s.className = t.class - ? `${t.class} tsd-index-accordion` - : "tsd-index-accordion"), - (s.dataset.key = i.join("$")); - let o = s.appendChild(document.createElement("summary")); - (o.className = "tsd-accordion-summary"), - (o.innerHTML = - ''), - Ee(t, o); - let a = s.appendChild(document.createElement("div")); - a.className = "tsd-accordion-details"; - let l = a.appendChild(document.createElement("ul")); - l.className = "tsd-nested-navigation"; - for (let u of t.children) we(u, l, i); - } else Ee(t, r, t.class); - } - function Ee(t, e, n) { - if (t.path) { - let r = e.appendChild(document.createElement("a")); - (r.href = Le + t.path), - n && (r.className = n), - location.pathname === r.pathname && r.classList.add("current"), - t.kind && - (r.innerHTML = ``), - (r.appendChild(document.createElement("span")).textContent = t.text); - } else e.appendChild(document.createElement("span")).textContent = t.text; - } - G(X, "a[data-toggle]"); - G(Z, ".tsd-index-accordion"); - G(Y, ".tsd-filter-item input[type=checkbox]"); - var Se = document.getElementById("tsd-theme"); - Se && ge(Se); - var je = new U(); - Object.defineProperty(window, "app", { value: je }); - he(); - be(); -})(); +window.translations={"copy":"Copy","copied":"Copied!","normally_hidden":"This member is normally hidden due to your filter settings."}; +"use strict";(()=>{var Pe=Object.create;var ie=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var _e=Object.getOwnPropertyNames;var Re=Object.getPrototypeOf,Me=Object.prototype.hasOwnProperty;var Fe=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var De=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of _e(e))!Me.call(t,i)&&i!==n&&ie(t,i,{get:()=>e[i],enumerable:!(r=Oe(e,i))||r.enumerable});return t};var Ae=(t,e,n)=>(n=t!=null?Pe(Re(t)):{},De(e||!t||!t.__esModule?ie(n,"default",{value:t,enumerable:!0}):n,t));var ue=Fe((ae,le)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var d=t.utils.clone(n)||{};d.position=[a,u],d.index=s.length,s.push(new t.Token(r.slice(a,o),d))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ol?d+=2:a==l&&(n+=r[u+1]*i[d+1],u+=2,d+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}if(s.str.length==0&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}s.str.length==1&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var d=s.str.charAt(0),m=s.str.charAt(1),p;m in s.node.edges?p=s.node.edges[m]:(p=new t.TokenSet,s.node.edges[m]=p),s.str.length==1&&(p.final=!0),i.push({node:p,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),l=0;l1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof ae=="object"?le.exports=n():e.lunr=n()}(this,function(){return t})})()});var se=[];function G(t,e){se.push({selector:e,constructor:t})}var U=class{constructor(){this.alwaysVisibleMember=null;this.createComponents(document.body),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible()),document.body.style.display||(this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}createComponents(e){se.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}showPage(){document.body.style.display&&(document.body.style.removeProperty("display"),this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}scrollToHash(){if(location.hash){let e=document.getElementById(location.hash.substring(1));if(!e)return;e.scrollIntoView({behavior:"instant",block:"start"})}}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),n=e?.parentElement;for(;n&&!n.classList.contains(".tsd-navigation");)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(e&&!Ve(e)){let r=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=r,document.querySelector(".col-sidebar").scrollTop=r}}updateIndexVisibility(){let e=document.querySelector(".tsd-index-content"),n=e?.open;e&&(e.open=!0),document.querySelectorAll(".tsd-index-section").forEach(r=>{r.style.display="block";let i=Array.from(r.querySelectorAll(".tsd-index-link")).every(s=>s.offsetParent==null);r.style.display=i?"none":"block"}),e&&(e.open=n)}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(!n)return;let r=n.offsetParent==null,i=n;for(;i!==document.body;)i instanceof HTMLDetailsElement&&(i.open=!0),i=i.parentElement;if(n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let s=document.createElement("p");s.classList.add("warning"),s.textContent=window.translations.normally_hidden,n.prepend(s)}r&&e.scrollIntoView()}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach(e=>{let n;e.addEventListener("click",()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent=window.translations.copied,e.classList.add("visible"),clearTimeout(n),n=setTimeout(()=>{e.classList.remove("visible"),n=setTimeout(()=>{e.textContent=window.translations.copy},100)},1e3)})})}};function Ve(t){let e=t.getBoundingClientRect(),n=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(e.bottom<0||e.top-n>=0)}var oe=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var pe=Ae(ue());async function ce(t,e){if(!window.searchData)return;let n=await fetch(window.searchData),r=new Blob([await n.arrayBuffer()]).stream().pipeThrough(new DecompressionStream("gzip")),i=await new Response(r).json();t.data=i,t.index=pe.Index.load(i.index),e.classList.remove("loading"),e.classList.add("ready")}function fe(){let t=document.getElementById("tsd-search");if(!t)return;let e={base:t.dataset.base+"/"},n=document.getElementById("tsd-search-script");t.classList.add("loading"),n&&(n.addEventListener("error",()=>{t.classList.remove("loading"),t.classList.add("failure")}),n.addEventListener("load",()=>{ce(e,t)}),ce(e,t));let r=document.querySelector("#tsd-search input"),i=document.querySelector("#tsd-search .results");if(!r||!i)throw new Error("The input field or the result list wrapper was not found");i.addEventListener("mouseup",()=>{te(t)}),r.addEventListener("focus",()=>t.classList.add("has-focus")),He(t,i,r,e)}function He(t,e,n,r){n.addEventListener("input",oe(()=>{Ne(t,e,n,r)},200)),n.addEventListener("keydown",i=>{i.key=="Enter"?Be(e,t):i.key=="ArrowUp"?(de(e,n,-1),i.preventDefault()):i.key==="ArrowDown"&&(de(e,n,1),i.preventDefault())}),document.body.addEventListener("keypress",i=>{i.altKey||i.ctrlKey||i.metaKey||!n.matches(":focus")&&i.key==="/"&&(i.preventDefault(),n.focus())}),document.body.addEventListener("keyup",i=>{t.classList.contains("has-focus")&&(i.key==="Escape"||!e.matches(":focus-within")&&!n.matches(":focus"))&&(n.blur(),te(t))})}function te(t){t.classList.remove("has-focus")}function Ne(t,e,n,r){if(!r.index||!r.data)return;e.textContent="";let i=n.value.trim(),s;if(i){let o=i.split(" ").map(a=>a.length?`*${a}*`:"").join(" ");s=r.index.search(o)}else s=[];for(let o=0;oa.score-o.score);for(let o=0,a=Math.min(10,s.length);o`,d=he(l.name,i);globalThis.DEBUG_SEARCH_WEIGHTS&&(d+=` (score: ${s[o].score.toFixed(2)})`),l.parent&&(d=` + ${he(l.parent,i)}.${d}`);let m=document.createElement("li");m.classList.value=l.classes??"";let p=document.createElement("a");p.href=r.base+l.url,p.innerHTML=u+d,m.append(p),p.addEventListener("focus",()=>{e.querySelector(".current")?.classList.remove("current"),m.classList.add("current")}),e.appendChild(m)}}function de(t,e,n){let r=t.querySelector(".current");if(!r)r=t.querySelector(n==1?"li:first-child":"li:last-child"),r&&r.classList.add("current");else{let i=r;if(n===1)do i=i.nextElementSibling??void 0;while(i instanceof HTMLElement&&i.offsetParent==null);else do i=i.previousElementSibling??void 0;while(i instanceof HTMLElement&&i.offsetParent==null);i?(r.classList.remove("current"),i.classList.add("current")):n===-1&&(r.classList.remove("current"),e.focus())}}function Be(t,e){let n=t.querySelector(".current");if(n||(n=t.querySelector("li:first-child")),n){let r=n.querySelector("a");r&&(window.location.href=r.href),te(e)}}function he(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(ee(t.substring(s,o)),`${ee(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(ee(t.substring(s))),i.join("")}var je={"&":"&","<":"<",">":">","'":"'",'"':"""};function ee(t){return t.replace(/[&<>"'"]/g,e=>je[e])}var I=class{constructor(e){this.el=e.el,this.app=e.app}};var F="mousedown",ye="mousemove",N="mouseup",J={x:0,y:0},me=!1,ne=!1,qe=!1,D=!1,ve=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(ve?"is-mobile":"not-mobile");ve&&"ontouchstart"in document.documentElement&&(qe=!0,F="touchstart",ye="touchmove",N="touchend");document.addEventListener(F,t=>{ne=!0,D=!1;let e=F=="touchstart"?t.targetTouches[0]:t;J.y=e.pageY||0,J.x=e.pageX||0});document.addEventListener(ye,t=>{if(ne&&!D){let e=F=="touchstart"?t.targetTouches[0]:t,n=J.x-(e.pageX||0),r=J.y-(e.pageY||0);D=Math.sqrt(n*n+r*r)>10}});document.addEventListener(N,()=>{ne=!1});document.addEventListener("click",t=>{me&&(t.preventDefault(),t.stopImmediatePropagation(),me=!1)});var X=class extends I{constructor(e){super(e),this.className=this.el.dataset.toggle||"",this.el.addEventListener(N,n=>this.onPointerUp(n)),this.el.addEventListener("click",n=>n.preventDefault()),document.addEventListener(F,n=>this.onDocumentPointerDown(n)),document.addEventListener(N,n=>this.onDocumentPointerUp(n))}setActive(e){if(this.active==e)return;this.active=e,document.documentElement.classList.toggle("has-"+this.className,e),this.el.classList.toggle("active",e);let n=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(n),setTimeout(()=>document.documentElement.classList.remove(n),500)}onPointerUp(e){D||(this.setActive(!0),e.preventDefault())}onDocumentPointerDown(e){if(this.active){if(e.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(e){if(!D&&this.active&&e.target.closest(".col-sidebar")){let n=e.target.closest("a");if(n){let r=window.location.href;r.indexOf("#")!=-1&&(r=r.substring(0,r.indexOf("#"))),n.href.substring(0,r.length)==r&&setTimeout(()=>this.setActive(!1),250)}}}};var re;try{re=localStorage}catch{re={getItem(){return null},setItem(){}}}var Q=re;var ge=document.head.appendChild(document.createElement("style"));ge.dataset.for="filters";var Y=class extends I{constructor(e){super(e),this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),ge.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } +`,this.app.updateIndexVisibility()}fromLocalStorage(){let e=Q.getItem(this.key);return e?e==="true":this.el.checked}setLocalStorage(e){Q.setItem(this.key,e.toString()),this.value=e,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),this.app.filterChanged(),this.app.updateIndexVisibility()}};var Z=class extends I{constructor(e){super(e),this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.dataset.key??this.summary.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`;let n=Q.getItem(this.key);this.el.open=n?n==="true":this.el.open,this.el.addEventListener("toggle",()=>this.update());let r=this.summary.querySelector("a");r&&r.addEventListener("click",()=>{location.assign(r.href)}),this.update()}update(){this.icon.style.transform=`rotate(${this.el.open?0:-90}deg)`,Q.setItem(this.key,this.el.open.toString())}};function Ee(t){let e=Q.getItem("tsd-theme")||"os";t.value=e,xe(e),t.addEventListener("change",()=>{Q.setItem("tsd-theme",t.value),xe(t.value)})}function xe(t){document.documentElement.dataset.theme=t}var K;function we(){let t=document.getElementById("tsd-nav-script");t&&(t.addEventListener("load",Le),Le())}async function Le(){let t=document.getElementById("tsd-nav-container");if(!t||!window.navigationData)return;let n=await(await fetch(window.navigationData)).arrayBuffer(),r=new Blob([n]).stream().pipeThrough(new DecompressionStream("gzip")),i=await new Response(r).json();K=t.dataset.base,K.endsWith("/")||(K+="/"),t.innerHTML="";for(let s of i)Se(s,t,[]);window.app.createComponents(t),window.app.showPage(),window.app.ensureActivePageVisible()}function Se(t,e,n){let r=e.appendChild(document.createElement("li"));if(t.children){let i=[...n,t.text],s=r.appendChild(document.createElement("details"));s.className=t.class?`${t.class} tsd-accordion`:"tsd-accordion";let o=s.appendChild(document.createElement("summary"));o.className="tsd-accordion-summary",o.dataset.key=i.join("$"),o.innerHTML='',be(t,o);let a=s.appendChild(document.createElement("div"));a.className="tsd-accordion-details";let l=a.appendChild(document.createElement("ul"));l.className="tsd-nested-navigation";for(let u of t.children)Se(u,l,i)}else be(t,r,t.class)}function be(t,e,n){if(t.path){let r=e.appendChild(document.createElement("a"));r.href=K+t.path,n&&(r.className=n),location.pathname===r.pathname&&r.classList.add("current"),t.kind&&(r.innerHTML=``),r.appendChild(document.createElement("span")).textContent=t.text}else e.appendChild(document.createElement("span")).textContent=t.text}G(X,"a[data-toggle]");G(Z,".tsd-accordion");G(Y,".tsd-filter-item input[type=checkbox]");var Te=document.getElementById("tsd-theme");Te&&Ee(Te);var $e=new U;Object.defineProperty(window,"app",{value:$e});fe();we();})(); /*! Bundled license information: lunr/lunr.js: diff --git a/docs/assets/navigation.js b/docs/assets/navigation.js index 9c3d6e8f..5f20d31e 100644 --- a/docs/assets/navigation.js +++ b/docs/assets/navigation.js @@ -1,2 +1 @@ -window.navigationData = - "data:application/octet-stream;base64,H4sIAAAAAAAACp2XX2/aMBTFv0ue6bpma7fxlkBLkbq1olFfpj2Y5BYsgh3ZDgNN++5T/kBi5+aG8epzzs+OHdvXP/94BvbGG3uhTA4zJfPMG3kZM2tv7IHIt/r6JHxYm23qjbwNF4k3/vp3ZGWjQwZYtGinkvsmFKdMayhieztx47czE67iFLqxqp1K3qcpzzQSrQUq+8QFEixaqdSL5MJ0Y2UznUsPKymwZClQ2UWY63U3WTZ3cqNK98ae0ckV11ewN6AES702EXQmBTZxR+Uy7msQ9S3mSbqY3DuFjXYx+w1iIxWKrqQLyQdtYItgy3ZqzUNrI3FhQL2zuNhLnc3k396dNZhi8z5nhkuhcXKjdzpwMC9KZv2QUqUQkzVPEwViygxDKW0DBeoFDAVnYIIgDAPdN81tAwV6kQaE4Sx1/6AWy/FQuAU7xEybR25QUiNTEGIowyMoFrCJmkNWL6qT+fjty82t315TmaZccykmLE2XLN64kI5hiDiFWG4z58CtWC0JpZy1H44Q51Sxe0COlf/pYy4i0J3hV61D3/8E7N1NFm1Dudcgwjqtm4fSkWI7UBoechEXZ4GLcfXBVbyf+Ytg2mB2THG2TIs5riSb8KkdXgRTf3o/w8K1RISXXPgJxE34vR6yvq4lO3z3uR2WyeG73EGCxo8iAYiZmBf7jsUGQ7RkCrKGeBPMRYgijiIFKK/cuXBv5RbFcpyB6myYLgvdNgjsOTeaJzBItH0UNpXx5jfX+JceRRogoDxXdKAUO/RwLM8QrltsOSy85rJBCpgB67JqQY7iIKBTL7sQtG62QAnT66JIjiRGaVQKAStfMXRn1dLVDRXn2jARo19x1Ki4Yr/Dt0c0XUkDYeJ3bckEBITOFUyk2AG6nm19EPMj3y5B9WMqfRBTj7r6rftplm0QWlUbzg3uIlsmCrg3IBK7OGmRTiqBWIEJZS5imHIFzt3WoLouGuk8sS0Q8sp2453L2gKgd7aNKLoIOb5mJ5EAlMWhhrgsdzGIZTgHVOz//vsGsZ0LtV/sPcjuA54GPjB89lHjuWDiiMB8FFa/8m3WM5W15sbPqky3LCtvr0i6z4WmA9dDjHPLssoTyd6L0/UQOCHNfOjHdD0ELitOF7J0sR1DqGeioLIMJKjsiqrNHMs5MPITbQ+BUyzxE1hhlFoib2gFJlciUjn6VY3aQfz6B3CVlia/FAAA"; +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA52XS3PaMBSF/4vXpGlok7bsbEgIM2mTSTzZdLoQ9g1oMJJHkilMp/+94wfYkq+vaLY653x6WdL1zz+Bgb0JJkEk08NcySIPRkHOzDqYBCCKrb48CR/WZpsFo2DDRRpMvv4dWdn4kAMWLdup5L4NJRnTGsrY3k5cjbuZKVdJBv1Y3U4lb7OM5xqJNgKVfeACCZatVOpJcmH6saqZzmWHlRRYshKo7HNU6HU/WTWTOdC5FNjyHJVeelRbgklgdHrB9QXsDSjBsqDDfQnjoS07Se8mDy5Uq72b/QqJkQpF19I7yQdtYItgq3ZqhyLruHBhQL2xpDwxvSMzvr5xDuhjbrgUGs+3ug/zpGQ+DKlUCjFd8yxVIGbMMJTSNVCgQYAvOAcThlEU6qHF7Boo0JM0IAxnmfuddFiOh8I9s0PCtLnnBiW1MgUhhuIfQbmBbdQc8mZTnczHb1+ursfdPZVZxjWXYsqybMmSjQvpGXzEGSRymzuXZ83qSCjlrCN4hDh3h90Dcnn8Tx8LEYPuDb9u9c3/AdibmyzbfLmXMMY6bZp96VixHSgNd4VIyrvAxbi6dxdv5+PncNZidkxxtszKNa4lm/CpG34OZ+PZ7RwLNxIRXnIxTiFpw2/NkPVlI9nhm8/dsEwP3+UOUjR+FAlAwsSiPHcsMRiiI1OQNSSbcCEiFHEUKUD1sC6E+/Z2KJbjDFTvwPRZ6LFBYI+F0TwFL9H2UdhMJpvfXOMzPYo0QEB1r+hQKXYY4FgeH65fUjksvLKyQQqYAeux6kCOohfQq31dCFoDW6CU6XVZ8MYSo7QqhYDVWDH0ZDXSxRUV59owkaCzOGpUXLHf0es9mq4lT5j4XDsyAQGhCwVTKXaA7mdX92J+FNslqGFMrXsxzajrz3qYZtm80LracF5wF9kxUcC9AZHaxUmHdFIJxApMJAuRwIwrcN62FtV30Ujnd9kCIX/Mbrz3WFsA9M22EWUXEcf37CQSgKo41JBU5S4GsQzngMrzP/zeILZzofbf9wCy/zNOA+8Yvvqo8VwwcUVgPgqrX/g2H1jKRnPjZ1WmW5ZXr1cs3d+FtgPXQ4xzy/LaE8vBh9P1UDi5Q6dcthMxIc3C9z27HgKXl5cSWfHYDh/qkajDLAMJqrqiSjrHcg6MnKLtIXCKpeMUVhilkciHXYEplIhVgc6qVXuIX/8AfjD0VsIUAAA=" \ No newline at end of file diff --git a/docs/assets/search.js b/docs/assets/search.js index bacbcbc1..bfa0d3dd 100644 --- a/docs/assets/search.js +++ b/docs/assets/search.js @@ -1,2 +1 @@ -window.searchData = - "data:application/octet-stream;base64,H4sIAAAAAAAACr2dUZPbNpLHv8qV/DrrCGiSIv1mJ3vZVO1dthLf3m65Ui5aoseqzEhTksaON5XvfkWAIBvN7gZJae9hK94R2H8QDXQ3foSo31en45fz6tW731e/7g+71Su7rjYmt3erQ/3YrF6tvj0+POzP++Ph2/rh4UO9/XV1t3o+PaxerS5fn5rzN6PPX366PD6s7lbbh/p8bs6rV6vVH3fBepHnUPS2379vbUwy+KJvi+zerZ7qU3O4sN0cRMte8M1x9/UtlmwOz4/nb8Kf1a6bod9/fnjYP51VKy+GNnyH+66wCt/uT9sHXaBvssT+344PX++PB1VgaLNE4c3xN9W6/3yJ5b/uD/rIdA2Wjcv+cEmMim8x2Xo8+74/HZ+fGAH39+vn32Bm0gT0vZk3A5HEhCmoKMhzEElMmYSKBj8Lkf3UNFRsC/MQGU9ORHV0+JkYjU1qKlL7NLj/tak/kvDb/kmdhzZHk+TT/mF3ag7f1Ze6t7M/XJrTx3rbxnL0uT651zbrrW67qyZZfIFaC6kBd5K/D6n/8/q9S1l50bXg+6n0r/Xlj0+X/fFw5gTQx9N7uz//fKkv++0Ugy9QY3m2hR6Kgm9P+/v75jRRcWh9heS3TavR7CZqouaLRevDPQqcml5ouVjqqd7t9of7SWJD28Vy91Hy0sRCyzlSeML/VH/d1ufLX/YXTm74dPp0f4riqWzsxZMaVVHHBKEPx93XKTpduxkyeID+drw0h8u+fvh7s70c2SVFmkwfqt+mWnsh507aP0GKHSlWSh4rWQoPmDxONxmeaaOyYDCmjYF66983l9ev37x5fcbVEJLAn+upf50N1ez9XKsvyBX8nUSdnbhxnKz6Ev+fP5mXiU3l99Kl0f+RIw6brJf08KW3dU0vw70Knf1ys65++fd29NPNOvrp5h2l5fUbnAp8ed3+aXJ53Tb+2+n4JBZ97sPpkUtaNLGpF+qaGPqkiHyvFQpE6ftkqaDK7c/fHg+fGzYEETXUdKHYhw98rCNCXbOFIsePH88NW6oQmb7hQqHz1/OleZwg1DdcKLTbny5sciM6od10GVtYk6E72tYPzT+m3FFoeJ3UP6dK/XOeFM6z5+byt+N531bLU9Si1sslf257PU0vNF0u9lrbMcVir5NbppTYj1OXF267UG53qr+8+ftfpkz9vuUVUhN1losM6U8o+ogabb84xuuoIorxDKi4nHd/2p//tD98ak77i9vdzxFPYItInYMWV8qnEEac4TiAcVUHVJyBtMcw4yrZBNpAwhzYuEpaxRx4do8ql7mytGD8+fXbt835QmrG7q/XPljDZlKP00JH5K7+cGB66v94bUeRlVQ/u17I3Xx7qj83p3Pzn8+HbZRCvRT9+Nqus/ZSNzHqI5qXdgi+5IlMZ+sb/2e147kZBmR7PJwvp+cIhjCmXsTtBLLueyQso8f94R+qRNdgke36t4Rt32Bhv/+Z6rdczyX7nbDtGyyxHW1OONvqtkS3TfYknPXEbmSK/W+PT18naHTNlujQrMKJpEC5rhCnS86+Tv1166NKiBNIPqxJadCChxdJPZ/RVcjmk5NIbDt1+/GekzOv7zZTY0SoAz9ECd6ga0TphbOvH4hJ2o4hjSSg45nkKNHaVRin1GM3Xef9ffJW3ovF2tPpeGm2pFjT9Z4PblO/+6ne7Z/Pqu6o6UJ9Qh/0iTdjxhG7+oqZsVo4WqIvdpUiTLKvVwQJ5DNJQc/dCdKTUkhPYv2p6th+CiOxNzEBICWVfk67O8WNkhqvk4k2iYuSGj+my540JdJVeKTCen8STNHVIkrEJkWND6VtY9glmdcwl67w/LSrL030VIWNubjZEp3H+vTr6/N3yQoibrc0spPZ4GfT/+4vn9IznG2+NMOhrSY9YBi0u7/fZLOJbU3abYZOzSmXIhG1XppgnS+YRhJ6xZTQEQvLSCZZWSZU3p9cOTJOmJEKajVtTk1THSdRTvWfN1M9X5qE10KTpXokkStlL/Viqu5NaqVvbnRvs+xPmijcPFmgkpgY3LxIqODQunVjnQhDoc0iBZ93fpi0gkdtbzLXWeQW6Y6Ym4asU2ochIvVKIW7Ro3DcvTe2Kix8N5SapTUXaHGortIbcTurlDbujnXnawfb19pYo7b3qQHEoaLpOc+10lmVgGdkZg88/lhUlWCaUR27oPDhK6A1+LMMOZrVyjywC0SHBO3a+ZQe073/Kbe/poqykhLOdL+xzWLalLK3yqPZ2/SDQGFxeVOmoVd0wWHQchxW37+RQ1v1pkkKos6cU1UTcKzSOmamT8Nd41H95rsOw2AjTWvyYqTsOFY8naKE5bPvMf+iZpRw3LxfQpc7jptHtRR4TGpu06VBxtUVeQZC1UFmEdlGZp3ha6O9+J5JfK9K/RZ4BcnZUr8rlTjEOBIkDLA60a43UafjvtdS8GOz5efjm0Jl1pQ6nW3W9tt6TFhZXfNbqJ7OdWH80N9SeEw1Owmuqd2/BKifZubKO7PP+8fn1KxBLW6iaqCoZk9/ohDXzPCzUTfxg1vV1pNpeRkpzwNk1/TGT/W3+LdakiXieWXuPLf0902+EygRLjZ/9u4zR+vm44Tfg5BXxEQOtT9/SbPIbCtSc8hQqfmMLhIRD33lrLOMbfYunbyLd33cYVP+y4T2HTfU9a1028J6yxDi6yr598S1sXnMpFC8rlMQiVB5uhUlVbgDEWJxEVSqRNxybETyBsZu8SptaSKRNqITOrcWkJHIGuRSOLkWkKBJ2mRgH52LWGffVIamVeflE6wzj8pHUnoT0pTM1fjf/H0ncr/5qxUCffFa3QK7puhKtC9SHPmSbfUbFdgXjzlJ8I8XXv6k1Qad1NPUpNaidA+J6YnuWBkec46nsYBx46ZUxFM435jjTmZexLnG0ssV5iwcPTTdYzCVI4X38eE83VpLZ7bUSH9hF1ahed0VEU/Y5dWEbgclUmcskvo6BwungeTztkl9FjuFqdw7aTdBOscZxsJaGft0iM2lavR4ZvC1eauLZajjVfWiKPN0JHZSly5sGRlho7AySIRhpPNUBC5GK24x1xshorCwSKdCecxUyOmcK942CZyrxnaGuYim9f5p0EnjfBEqsWM+QKqNTNCTNgUT4NY143K/NG42SgkTn0x/Zh96oup0REk4xJa6k1OU+FY/z6dKWBMeRcSu+XsjSdeOKNa5beakenUG2ZE+yL06c1PeKWMaP39l/3u8km23X8+bZJoSp+a/f2ncYk1SPUNlmiRUjtxW+O7mmw5dRvMXSi28SKuP16a0/+41fnz/l/KVB03XDRiMwJIL70weCjzgkXVvd6so6KaCoesB5U5R0T1exlvUvG9TD+Wot+LpjLnSKiiwqLsXmXWUVBFJQGbcehfcgRUezOeAJ17yfmv9FBiuACfUQyf/coYRU2C0Ehu/jtiRD0BRvdiM494Kko8lO6F5h3tVN+aqGDdYYLc5Eintjgk7jgsi6uPcmoZm+dVQ8K+8ginNqUU4jvMq1sc3VRzvYJ+cfU1/3VHiqYSdJdG3CQK7hWWrp5pSDj23NKMOw0Nx1pLM+IkRBxL3UYpsfTmvvVJrPs0ZDzc14Jjn7omj46x4Lzjnroaj5Cx2rxjnrqagJKx3MzjnYqejpSZN9HOOdap6LJoeUjEc45zJlQ4xBwJzTnGqY/kVNSMh/Xa45uptcki53hlzjq2qejJeHMgGbOPayp6AoLuxWYe01SURBSN6+95xzOTe2kWSZN99KxjmdpIKmh6GM5bHMdUOqExarQ7vcExzOTYT4TVxBu3Pn6ZCDYJ0nKDY5fzxmne+NxsXOKjlvj3MQZ6vT/o73OcfswyWJp4yLLtzrwDTL1A4vhSwrJ0eCkynzq6pGgoRwl7CZYra45VFQXSjPQmsGZ1XunyArfF+hMA9KwOTGLSqAPi/S9RS9+vfLvT9OawayQ7h17PG+5ZT8T6/sxA2sunn3Agu+/ELM6tK/GHswelOaw7dU/ckSx8T9P33al70pXmMG9VSTjA3SvN4t6qUvKYNU5VS9i3qi4fue5l5/LvRL4Rj1+jfDOTgScU5aPYSHIuB1c1xWPZveBMFq6qSUe0e7F5PFyfL/pB52HS3ISJ6wtHPo07LJmrubheTEgnOYda4ko2rk8z9Tz0MNduwccTVYZ6OBpXknMZeUJXDdLLI/SEQ9O9yvKVNfUAdezJ5Vl76mHqWG95Rp14sDqWu5VacmnOY+dqkakfuB7ubwE/T+lKh6+x6DyGnlKUDmJjxXkcPaUoHsrGkjNZuqqZOqA9zKFFPF3VFg5rD8l8DlNPKvEHtyOxOVw9NarTD3HjIb6WrafXrnCgO165s/i6qqkdIB7IzmzGrmqKB717wZmcXVVTDn3jOn8ea5+w0RcOgJNN/izero+qehh8GNpbMHe1I/rJcLRDvgF3n+CHycfEiWduzd6TASmJhW7A3+eO19xxuuH4YAr/1/1hPKnbP96EwfeGJiF415c5BH4wrwL4lF2ev8fGdfyuKYj0fRBIHuom9kev5K1P48ppMB8+X2K7OYw3e4Nl/+k0u0KVoFiPW81XSWDhQWjhQWfN6ywDHhRnIWBVhyPASGcOAE7cz3gXGd3P9C1k4n5UnTnwV9Nh2e+gMwv9ajoJ8hsFyCXgV9OWuO8gOhf76nFOoL44zs2EvrqexHyx4FzkqykKxBcF2nnAV9Piee8gNQ/3qrNEo71oqtwE9qpLRYKLaJFcjXq1Dgikd5C/FvSqk0vhvGiG3QLz6hlfobxRxTIX8uqqWjBeHImThHfQWLyWpvFd4sHFOXka3SVqizPmJLZLxG6klVqK88CuViVqXBfd2wKsm1DlqW4kOQ/qJvR4phvpzUO6CT2B6EaCM4FuYk+h8NxoV7EA52rKLM1FqXoOzE3pcCw3lpqDcifu0VIkl92yLQW5ybXKclyyUmdhXE1RJn+ID8yGuJqiwHAHuZkIV9MSCW5Us88DuOkdOctv6W58Fr5Vx1Oht2hQbwFvtW5o7Bbvb2+AbtMemEhuqU9uDW5T4SfFbW6AbWeO1cwxut3YYGb7M78P9X9WuW204zg156fjgfnRPWToBWrEA7iuM5JGPZ7tkfl6+qtrRkpxKDucG4aCYrG+ycQ7IannqT5xMQQroEbXaLABktNRX3Gka20/Ndtff2TgP9ZBjRZrvD41dVqka7Vc5eFhgsjDwzUa3x4fHvZnrgAaKeGmS/RO9ddtfdan89Bmycrc1RfdLV2DaQk4MXqnpr40/Bc+oqGL2t1OmX3INRbumt1Ot/vJ07Ry3/B22twmaCw8Zws0RVX6Hdex8tDyljOMf3s7N8dCy1uoK2Utll5Q2E7RnaB5Iz12oxvFjDlb3bQWt9mlcnO2u4mY2zweP6eqoa7JLfTu243qpTlc9vXDuK7EsrTlLdQvp/pzc0osVdRooWaBMk5zb0/1QJU/Ph+2bgPxTffJn4xavBa4rNzZXXPPmOo+mW6Kj1uDwejzeUZxCKYGU+/LK/Aj+PPzqYP+cQ4djI7azDPeb+kitkLNR62mCuz250t92HJDGz6aPKoPx+2vX/a8m8Jnk2/8t0tz2EUxG91v/+FUcx+Ou6//dfzccNO7/2yqscPx8kP7dOXcbB2rZGzSJlNN7xN290uMbuuD60y95eYm+nSyQVet/3Dgeth/NmPaHHxReX59whvSaPZETaaafqyf/Jp7e5RM0yYzTLv2b4/koWBkOmoy1fR9c3lzfD5sm+/2p2YbEd3B+LjRDPM/v377tjlzk2H4cHIAqc+f2sr87ZELIf2Hk82d6i+0TkT2hk/nGMSFSmzszd//Mmue/kShDJmk4fPJmbK5PJ8Ob0/PnMXhwxm+jU/LRZ51H02OmPuD3TVbLl76T+alsP9+fvzQcKsEfzz5NtsbebNnc2H/mWoMhgOS3/35e/vT6+96U5/r077+8NCcv+k+mWrop9ff2e/+/D1jqPtk3ogRvEpHzH881eSTXzQ/HMied7BKWkw3vD9cfjjISzZuMLu/muG4yawe/6gNBPp8cnBwrZXhjRvMNSuPAmkxz/CPz5fzfjfal1PrcbPZpUybAMRxYVotEmj/9581m9PYdotFpggsMi57gWvGSfxyt9ofds1vq1e/r9p9YVs5vFrZl/CyWt2tPu6bh9159eqdV79bbY+Pj+228JfuM1+ltC18k2/Wq7t367u8eJnD5pdf7t6FK9wH7g+umVndvTN3GbzMsyxqZqJmdnX3znLWbNQMVnfv4C4rX66L2BpEzbLV3buMa5ZFzfLV3buca5ZHzYrV3buCa1ZEzTaru3cbrtkmalau7t6Vd1n+Ms+jVmXUqlrdvau48aji0V1LA2KIG4w0JCZ2hLHSoJjYFQakYTGxM0wmDYyJ3WFyYWhM7A/Tjrth556JXWLaoTeGbRl7xbTDb9gZaGLPmNYDhh/z2Dl2Lba0sXesWyUZO//JOmmdYPI7qF6aysQtY//Y1gumYFvGDrKtG8yGbRl7yLaOMCV7R7GPrPNRxdqMfWRbR9g12zL2kW0dYVlv2thHthJmko09BK0brL3LzcvMlnFAiT0ErRsscNoQewhcKMu4+wESzFo3WNaXEHsIWjfYglWPPQS5rB57CApZPfYQOA9t2FGKPQSl3DL2EFRSXoDYRZlzUcndeha7KHMuYoNmFrsoa/0AbADJYhdlIE6QjKSc1g/ATs4sdlHW+gHsXbZ+mWU2bhm7KGv9AMC2jF2UtX6AjG0Zuyhr/QA52zJ2UdY6Agr23mMf5S4LsQEkj32Ut46AklPPYx/lzkcV2zL2Ud46IluzLWMf5a4uMGxLUhm0jshYH+Wxj/LWERnrozz2Ud46ImN9lMc+yltHZPkdlC/Xm3jk89hHeeuIjA3yeeyjonVEtuHUi9hHhRFTTBH7qLBiiiliHxUgppgi9lGRiSmmiH1U5GKKKUgBV4gppoh9VDgfsdGmiH1UlFIAK2IXFc5FbFgqYhdt1pLJTeyhTeuGnI1fm9hDGyuajB20Aak+3MT+2bROyM1dZl6WG4hbxv7ZuPLasi1j/2xaJ+TAtiQ1duuEPGNbxv7ZtF7Ic7Zl7KBNJUbETeygci1GxDL2UOk8xCbsMvZQacVZXMYuKkFcGWXsozITV3AZ+6jMxRVcxj4qCzHGl7GPyo0Y40uyFSrFrFXGPiorMWeWsY+qtZgzq9hHlRFjUhX7qHJ7og03l6rYR1XriJyNH1XsoyoTC7Uq9lGVi4VaFfuocuuoYvsZ+6jaiNm1in1UlWJ2rciWtRKjbEV3rWsxEfvPcFsjpmL/GW5rxWTsP8NtQUzH/jPcNhOTp/8Mt83FlOw/w20LMdH7z3Db1i8F6wj/GW7beqZgg7T/DLdtfVPwO9818ZuCG0a8wYh5wlDk4MgCv7oNpQ4OLvDr21Dw4PgCH18MZQ+OMRTsBs9Q/uAoQ8Fu1w0lEI4zFDnflrjNQwg2IhlKIRxrKNgMYwiHMI42FBu2LSERxvGGgo1gxlJU1PqmYEsbQ2iEccxhs2ZJIOERxlEHvnIwhEgYxx342sEQJmEceeCrB0OohHHsga8fDOESxsp7KkPIhHEEYsMTUUInjGMQfG1gCJ8wIFfthhAKA3LdboBSPhDzviGUwjgWwWd+QziFcTRiY9lxIKTCOB6xAb4t8ZsjEnyuNoRWGMckNhlvl/jNYQk+XxuCLIxnFrwvCLQwDk3wmdgQbGEcnOBzsSHgwjg8wdcCJqOANhMztyHwwjhEIaRugi+MgxRC6iYAwzhMIaRugjCMAxVC6iYQwzhUIaRugjGMgxVC6iYgwzhcIaRugjKMAxabnJ1nBGYYhyw2Bd+W+M1Bi82Gb0vZultvJd+W+M2Bi03FtyV+y5WyhGAN4+BFyecAAjaMwxdCCUPQhnEAo+RjKoEbxiGMko87BG8YBzFKPu4QwGEcxuCfmxDCYQp5C20I4zCFvIk2BX0sIm+jDeEcppA30oaQDlPIW2lDYIcp5M20IbjDOKohlGeEeBjHNYS0SZiH2chbakOwh3F0Q0ibhHwYxzeEtEnYh3GEQ0ibhH4YxziEtLmhD7Q2cqlMCIhxnEMolQkDMY50COmYUBDjWIeQjgkHMR6E8OmYkBDjeIeQjgkLMaUMFA2hIaaUt9qG8BBTypttQ4iI8UiET92EiRhHPoTUTaiIcexDSN2Ei5hS3nQbQkZMpey6CRsxlbLrJnTEVMqum/ARUym7bkJITKXsugkjMZWy6yaUxFTKrptwEuNoiJC6CSkxjocIqZuwEuOIiJC6CS2xjojwqdsSWmIdEeFTtyW0xDoiwqduS2iJdUSET92W0BLriAifui2hJdYRET51W0JLrCMifOq2hJZYR0T41G0JLbGOiPBbU0toifW0hH+kT9zmiAif5i2hJdYRET6sW0JLrKcl7HKzhJZYT0vY5WYJLbGOiJQZR7ctoSXWH9XI+bbEbY6IlCw1t4SWWEdESvYBsiW0xDoiUpZ8W+I2R0QEF9NTG46I8CWXpec2HBHhSy47OrlhxZLL0rMbjojwJZelpzccEeFLLkvPbzgiwpdRlp7g0I5w0DMcjohIx1KI3xwREQ6m0HMcjojwZZQltMQ6IsKXUZbQEuuICF/uWEJLrCMifLljCS2xjojw5Y4ltMQ6IsKXO5bQEuuIiHBEh9AS6w92sOWOJbTE+qMdvN8ILbGOiPDljiW0xDoiwpc7ltAS64gIX+5YQkusP+PBHxYitMR6WsKWO5bQEuuICF/uWEJLrCMifLljCS2xnpbw8ZfQEutpCVvuWEJLrKcl/BoitMRm8mkCS2iJdUSEL3csoSXWERG+3LGEllhHRPhyxxJaYj0t4csdQkuspyV8uUNoiXVERCh3CC2xjogI5Q6hJdYREaHcIbTEOiIilDuEllhPS/gYRWiJdUREKHcILbGelnCH4wgrsYX8DMcSVmIL+RmOJazEFvIzHEtgiS3kZziWwBLrgIhQwRBYYh0QESoYAkusAyJCBUNgiXVARKhgCCyxDogIFQyBJdYBEaGCIbDE+vMhfAVDYIl1QESoYAgssQ6ICBUMgSXWnxPhKxgCS6yHJXwFQ2CJdUBEqGAILLEOiAgVDIEl1gERoYIhsMQ6ICJUMASW2FI+G2cJLLGlfDrOElhiPSzhowOBJdYBEaGCIbDEOiAiVDAEllgHRIQKhsAS64CIUMEQWGIdEBEqGAJLrAMiQgVDYIn1p0j4CobAEuthCZ8tCCyxDogIFQyBJdYBEaGCIbDEeljCVzAEllgPS/j4S2CJ9bCEj78EllgPS/j4S2CJdUBEqGAILLH+XAm/hggssQ6ICBUMgSXgYQlbwQCBJeBhCVvBAIEl4IAIX8EAgSXggAhfwQCBJeCACF/BAIEl4IAIX8EAgSXgYQmbL4DAEvBHS9g8DwSWgAMifAUDBJaAIyJ8BQOEloAjInwFA4SWgCMi7DdKgMAS8F9n4W+NwBLwsIRdQkBgCfijJewSAgJLwAERvoQBAkvAwxL2SAUQWAIOiFTsMVAgsAQcEKnY4+lAYAkosAQILAEFlgCBJaDAEiCwBBRYAgSWgAJLgMASUGAJEFgCCiwBAktAgSVAYAkosAQILAEFlgCBJaDAEqBffFFgCdCvviiwBOiXXxRYAqOvv8iwBOgXYBRYAvQrMAosAfolGAWWAP0ajAJLgH4RRoElQL8Ko8ASILAEFFgCBJaAAkuAwBJQYAkQWAIKLAECS0CBJUBgCSiwBAgsAQWWAIEloMASILAEFFgCBJaAAkuAwBJQYAkQWAIKLAECS0CBJUBgCSiwBAgsAQWWAIEloMASILAEFFgCBJaAAkuAwBJQYAkQWAIKLAECS6CQt29AcAk4JFKxJ2mB4BJwSKTiv09IcAk4JFKxx02B4BJwSKRij5sCwSXgkEjFf6uQ4BJwSKRij5ACwSXgkEjFHiEFgkvAIZGKr3cILgGHRMyaL3gILwH/ZZo1X/EQYAIOivDf1AUCTMCfLlnzbibEBPzxkjXvZ4JMwJ8vWfOOJswEHBcxaxZgAYEmsPHfmGYJFhBqAp6arHlfE2wCDo0IcYJgE/DYZM1PDMJNoJTP4gHhJlDKZ/GAcBPw37dZ8zOOgBPwp0z4r5oDISfgv3XDf9scCDoB/8Ubw3/1mLAT8OzEAN+YuK/cKL4m9AQcIZFmEcEn4BCJ4b+mDoSfgGMkxvCRiAAU8F/FMXwoIgQFHCUxhp+fBKFA5T3IzznCUKDyHuTnBoEo4ECJsfzcIBQFHCkx/HfXgWAUcKjEWD7CEI4ClX9xAR9hCEgBB0uM5T1ISErmaImxrAczglIyh0sM/xX1jLCUzPESY1kPZgSmZA6YGOkb4ORL2I6YGOFL4ASnZA6ZGOF74ISnZMpXdTLCUzLHTIzwZXACVDIHTQyw3s4IUcnW/uUTrLczglQy498/wXo7I0wlMz4F8t4mVCVz5MQA722CVTIDcqjLCFfJTCaHuoyAlcx4B/LziJCVzL81BPh5RNBK5l8cAsLLBIgH/dd2Mn4eEbiS+deHZPzcIHQl828Qyfi5QfBK1r1EhJ8bhK9k/j0iGT83CGDJ/KtEMn5uEMKS+beJZPzcIIgl8y8UyXgPEsaSecbCfzs76yCLe8vR5+Z0aXY/+LcdvXu3ev/e/8Ts76v33SuQTHjL0u8rs3r1+x93K6j8f4vS/3ez7v5r2//+MbwQqf1/rXL4PbnBaL4ZrFbWX95+58T/o+yE2nMg/h9l1kn7v3Aan5r9/acLFinzQaQ9auVNFYVk4VTv9s/n37CJAtDdexPylV+jKzN8pah5vjTRwBQ5vmwjXfZlv7t8iu41w/eahXuVelx/vDQn/87s8/5fkb/LElsqg6VKsuR/SgvNF3x9N+hF16FS8p7/HdLBCKBhyMI066Zd+z0x/4+i+0t7dsv/Y9MJgv8LpxRex4h6DGjw2mgvXOneoTtcZu1wFXRLIBNv8Lj7OloFFVoEynWP/n27qMMGXdlWW/K1x6fut2vQ1dFUUa59Oh2foisBxYJMU6UxBI2UFCPIBCiGK4oQHjofr6Wx2taHff96XnS/kaMqaU3539yM+oBGuf2SpnZd7KANDhsQbqBch7BmQ1iDENZE6+1bgOv94UN8R4DvqFSvbX8LBE05PHMK/Ur3UyXo0hJfKg5je+l2+FkQ1Ov1GhsQvdgaOB6i+VNt8JVSMN1+2j/sTk0sinxv5Nv1F/qfAsHrDF0s3nD3RsbhMhxNOtd3CW0jhQdvZH8YG2tLmsGclYJTMPAUXn6ILQC2IK14b+HoX1HJmsH3JS+H4eXleCCxAyvl2kPjf4C39q+Zxo7MsAlx9rQmhh9zwkEeB6+16M0wc7f1w8OHevsrtoHmr+iH4+F8OT37N1mjegeJb/pJYUIeC+nLhAhRhFLLiGPlXlv71P/+Fgo+eNbakDQ3oaYKObk9AtTlSqlK8K/wJ5G5RSCDI/qEW4qLyxlhJvYaO3QjpRN/eRN+twBfX+Drw82UomedoYf9gVjBoVRen+7iJ/+rBPhqnFrE+jdcPV5Ta7wuNlLX27d/tx2/HOMVUeEZLQ3gKKjh3BQKqG7ewUaKDv2PWuBFjW++7CZCZqQx7H7KG5UTKKHk3fQswx4AwioJnrWhxrJhewAgrcJd/2MMuLt4vlTijbqfdkHBHF2Vh8W07m62/aqz/0cVVlXW3YCtuioVwl+gFLt7qr98+BzV8xlaZHmod9ehkgij1X4Hq5MNhXpVBdmgH4YrW0uJs9XnZies8QSTogSzNvGaCn0PQU8ahOYQza4KFwti8vWv8N52b/jGXUcLKxM3bv7yQ/dKdXw53n8Yaa74y7uRe+p+VATPOBwpK/nGWyuf3UuDxxEGV+stORZsuB/yoDsUg/diLcLlL75vLnX94UN9pruwDA1iERy4DgszC6uhCukrC7OxClM+k6bcoBlL2igghhksG/ngfrthN/zAA46PeA6speB831y23U/5RvPP4Pmn9CBc/MX/DvCp/x1glJHxpj4PuCMMkg0D2R6664ZN8nOrN5rsJa5xQ+VgQ7CwIXzAOujkyu2MNqktQkXDqPTs6H7kuh2HERQocBc1G0/o95/wRMbRQKQI983lXF8u7hc58Dwo8Q2IF9Mbt0jTdr4qukENUdZkYTWUIZVmwQGBa0EmxQ8n+WFPogYUOPZI0zbKFlGgFq8YAzK0QKwJ01HcFYbfFUWLBAenQhrZ/rXr7YqPPYMXWSXFiv76tgbidkg4WNtkL1orozIQh7pMLIhHNj7WZK7hciETIVRkh91r4SlrtYGJ9TNUEoo77P2ZYxZ4ixZ4WtFl7yrUG4EHmkAu2q/UdVVZqMBBHL3zOHZF6K2bgWUQMX0NGEq/HgKFLROIuX1/Pnc/6I0CMSY6eQiQ67Bi84BjQo6DXJxN53Mb52OOiHlzt/hDOA4Au33BVHdP4VZCbGm/O9FtyKRyZ3++nPb396RYQVPOdkaLTj5U5SYgJxN2nzZQVBu4Klhp4T809cd424ITjnQRWWJoeoUav/ehFCAf6ycHAi7Hzw3dUrdPUFFYV0z4ay9HhingyLGWCrT2x8rr82j7UuB99jrM2bzfUoWBDvMM1qGeyaUxe6x/i1ZHjlJv2AeZsIE3IRlZGybwJqQckfI81r9FN5GjEQjzz4QZacITHhvmlQ3TB8Q4+7g/xPeAUn+gBSYEGFOE8BG2oDaAChBZ1+P+EN8DiiGb0HUbhqsIyyssSRtWHogQ63C8KEkL1yKVFH58MRSFOjxfu1kibgn95dvjU3ynyEQpufip3u32h/uozyjuhYEJI1/2j99ChR9mkQ1NbRhVEFPRaOOCEli/NEJhFGK4dPPOGM8yATMPcVvoDBxZmoopoJEypN/LtfgvLgk3uIwNmc+EAGpDbLdhTAFEJ43vDe/4wyQOc1habJ0ZFhxjvJKJYbq3wJYhuK4UN0FPx6iAjctt8Zquzh8H9ujhhjR+/S+j4k0CvjCUI5mRijDucS9KUkaMP9zT3hJfKHc6uqjC/S2kWNT//DnOv7hu3sj9dFd+2kcX45pbzPjhB4CxJn5yVIq9ZdB7hTlhIQ5OcznVh/OD+xlnFEdwrRG2snYd8lEe+HPY7kIuRWT/K4AX9xOBeJng5ytrcUDabX1cz2CXh27YsIW3YZsPoauQS2PG7Flx/S8+ajtv63jJ5/iBcsh/WSBwoay2WehjKOtBXKZOYrxEN/hwA/R7gpA3Aru1ofwEkBahE4h3BOgmwiBWfcUYqueyp8LhrsIGHERc5LSiFYjjWyj+A7c1WYi+gUnbcPDFVgHUgJRBzs1TfSIzpsI4sBBHpLuSwrwK42vxYMe5uYzgC37+F4pRsw53F3ZdJvAKG5iGDVAbxIf950B9Ij00O/JgPSwDE7i0qcIazvrCIKzhTLm9MWfdFHglBp3gRxsYPYR9HuTidG/Nn/eU3+GiIQ+Va1jpJnTfhFlhw8yx4RZBhDLn5jJaxviJbwgsJnTeBMhqwuq1YYXbAGJBPIZyvtQxwSlxVBeLhNEpJTziYhV19j+Sjtc2yq/BLWElm3DYy2z6PUFYb+HkBIS/gFg7sklkg/N678EA8Wx4nAJhUUAuZanhl+Jx4YHTcSmtlXBp+D3CKHKjQCQ+g6OnaqLMFar5ACb72jHU7jY8brYBDoD4qK5VGvHQiAMHDto/1umdF5Zd6IANEAnESuz54NbAzhdW0bigPCg+v/Dn2OJiBT/42EgT1F9IA22BK46wZzchkNkwR2yYRxCeBkL/l42Ugrxi9Ow+BJzovkvMFsKjFxuEbOgMBOwAuVQkMIqxEn4cHGaGDbdtA86A8AAPcn00Oci3wSPao4R1P1PCOgyYD8SQwuwWcFqUJlj0RDd6bC6ttfEBS0zZTKg+xNosfqiFMXkfYroV1IPBsHIDKrTh4JgNBQiAFKDjg4m4zgiLLyzYkE9CEWhCjWbD4zYbCkUA9u5+uVs97Z88Qn/17pc//vg/YkIRpusoAQA="; +window.searchData = "data:application/octet-stream;base64,H4sIAAAAAAAAA72db5PjtrHuv8qt8dvJWugGJdHv1naO41PJccr2zb2prdQWR+LOMtaIUyJnvXtS+e63CAoS0Hzwhxyd+yLlzQjshsAG0P38QPFfd6f29+7um3f/uvutOe7vvqFifX93rJ7qu2/uvv22/Xx3f/dyOtx9c9cc+/r0odrV3dfD39987J8Od/d3u0PVdXV3983d3b/vrRG1In2x8tQc/2/UylfnFo6p+7vn6lQfe9uJsOm/J03/fZnp6nOq12OLRaZTvR5b5Jmm7cXyz9++dB8vps+Xf23+Gr1fhaKLjV177PrTy65vTxFLX/nNcE/H7gRG4f1T9fmPx/7U1F3Mj99skZ/mmOXHbZbnh1b6OvbV4RCzP368wG5XV6dd7KZ+dWmxwPquPRyafXxonDYLPBzaah+zfv58wZ3dV30Vs3z+fEGfm2NXn/qY7UuLJWN+qKv43Do3WGD7VD+1n+qY8UuLBdb71tsSgPVLi0Wx+DQ0/Iu7X8BwdJu9ys/f8/yE1+LEaP3nLz/9V3y0zi0WWP9wap9S9p02Czy8Tyxp7xevae8fXppDdFW4tMizvi4KvuYt79/3X56jk2A0/2b8zx/Um8sVEXdvvItCi9LuY3PYn+rjfO9vnEuzu2F7HujNx7p5/BhdyAJ9uVx4q54c6urDgn6cL7tVL54Sa0ugF9EEdVEvoitPuBeJlWheL9wMd0YvYmnvol4sGotYhpzVC39B2n1s267+5eWhP9XxlUO2XLL8pfOL969JMN53z4cmbt62WGz957bN8HButcTLeZwHKz8e93U060CNX+nz7ecmXi9M2y7cYr9vuv4v1emxie8ZsuUib/t/vnT9X03jIU9LlESw+aJxbY/7+tglJta1Ua6PcqOKa+X63VCndE17/K46HB6q3W8Xd8PU776efB6tiaMpRczgV4lkYtrNq9PrmH3b7r/86rqsjy9P3df2z3H55drvPx4OzXMXtfLVtU1AcLBdgR6+a067Q9zBpckS+39tD18e22PUwbXNEg9uSYOsxwqauOU/N8f4yJwbLBuX5tgnRmVskW3dj74fTu3LM3Bg/v76+LuayQrAsTfzItBxkRGCEQ/hGHRc5ARhxAeOQsd+KgwjtgNx6BhPBmJ0dHAkemOTCkVpXy7uf3brh3H5Hf4UjUNXy/7uXFx974pGjvjqfp6vbU+qvZjFr5IFntdJ/D1C/Z/X733KSlw8i/RvuJc/PfdNe+yQA+fj/N423S991Te7HINfOY3D0WZ7GHT466l5fKxPmR6vrV/h8rt68FHvM306zRc7rY6PzsIZ82dbLnb1XO33zfExy9m17WJ3j97mFXNmW85x5Qb8z9WXXdX1f3IKLsfd9dP8cH/21tOwsa+eo6uq07GAo4d2/yXHz7ndDDfuAP217etj31SHv9UeVHIciib5QwXxJLL2VXjvlP0LuIIjBV2Fxyrsyh2w8DjdZHjyRmXBYOSNQfSr/1D3b99+++3bLkCe3c/jW79bfz7OtfqVuAJ/E6+zmYVjttc37v9JK9Q/hC71/k94xYGb9ZIevhltvaaXCcXw95t19ff/2Y5+vFlHw3B3aUdlev2tuxWM6fXwp+z0emj811P7HEz6zIf5K1do0vimvorOiWufIk5+iCUKwtMPyVQh6q7pvmuPn2p8pMb35jRd6OzhIXB2x3d0brbQSfvhQ1fDVEW4uTRc6Kj70vX1U4ajS8OFjvbNqYebm/Bj2+W7oTUp7XyjXXWo8Qkj8Y1sw9e5wieOgKvIwSPkyt1nvaMHYTfR8wdJJ13d/7XtmiElz/lKXuvlLn8ZhibPn2263NnbWFnmO3ubrMtSzn7KncNu24Xu9qfq92//9qec+XVp+QpXmX6WO7nusaGTkr432X7xRhLXQ7yNBKghfbf/Q9P9oTl+rE9NbySEOc4T2ojnHSkjr3Sf0kn8bRSpJK/qQFQzcXxPFZNXuU3oJ45jpJ68ynVUS3Gje5IezXUrs9Jf3v76a931IjE9//W19M41k2J2tiPhrv54BD0d//jajjpWUv089yLczV9P1af61NX/8XLceVvo6Ep+/NquQ3upLzHpIz7sLLCPRcrjn29y3NkxlXXe+dyjOWePXBfRU0YJ2+gsj2c7dmon2e/pCR3R73DSmOx3wnbsnE/ctlcBIdvR2iduWxQ+yHqi5Mmx/137/CXDx7nZEj9yV0FOUmp83IO/XSL7cbQQtz7JhJCDJBFK+ZAJD3aSgkBxL6LCRS4StW3cvl/YIvPxkjY1RkLawEOUEDXiPuCZXtd+/NRN0ravBIUcxDWg5CjJ3DUwTim2F/fz/jH5Vd4Hk7XnU9vXO5Gsxf29HI1ysP+52jcv0yNlrt9J04X+hcQRD7wZESfsxmfMjNmCJJn4ZI+qCFn24xlBQlfK8hDfuxNyUspDOojj6HZqP6hVwcwjplLFbSOJCg5QhjiV9PRLOpRSmlTSx9vkJp6UopI+fkqnVGkFKu4FyzUwsrKEmrg3T4GCG25Me0rbdoW0kPmYhBb38PK8r/raw0JwPXebLZqH1em3t933yezEb7d01xDRMEbT/2n6j+kIh82X7p5OGStPSFrf57/fpJB1bWVVsrZTc1Ixz0k0F8uwjpOxiYt4NpbwE0xaPTfJrDXh5f3JpDrTzdjz4rTKi6k8r9MNGnn9+828dn2duGu2yVJ/IkmIpNTyLqZy6qSv9JebfLdZ9rMCBcXJAi+JwEBxkfDiPWFrxjqxDNk2izyM+86PWTN40vYmsQ7lPM/vRM+LyeEpb0jg871Jhe813pDkJ78bXDUWfreUN6kCvsIblAU9bxNd8BXedibmzo8GTEtjuTH7bW/Sg5DE57mey4ySO2tAlhNr8kw2mfQaEuqE27lQMuE3IN35O8NUu3uFRyzmeQ6nat5rYmg4aNx9W+1+SyVlomV4pf1fr5lUWVv+LoJ+b9KNgMzmpztpne01XTASizgvjOPPa3izziRlOK8Tr1lVk8Kc5+k1kZ8npU1H9zW7b564NvX5ml0xS5Kcurydx4zpM+9IQSJnhJKfn2dIze8V3mIioD+qARXwdb6xLCgdT3XB13nFMor0GlRPFnoNSIfSLdAOX+E3Lib6URxUE1/hH8qLfgog9cVXekOC48ShVBxfN8JD0X5qm/2gubUv/c/tkDCmJlT0utvN7SHRyZjZ52Y38dufqmN3qPqU+OY0u4nf0zB+CaeXNjfx2HS/NE/PqbXEaXUTrxHRGygKE9X7NSNcZ95bv+HtErlcTV7U5Xmi/Gs6M471d25tbLfLxPRLXPk/091h8cnQpNxm/9/Gbf543XScXOohf1HBduj895tQD9dWFvWwnZqj+HlOoif4UtaRwudbj53hS/d9Wk/Ivof13nTfU9Zj5/gS1qFi51mPnuRLWA9SIM9DkgIlvCR0QBmqoRk4w2NI9/Ncpc72JccuoPOJsUucv0t6Cel6wk3qBF7CT0DH85wkzuAlPGDdznMQP4WXsA+5rGc+ymUzrGMuO3ER57KpyI2pjX745qqNc2ZqSFz052iOuDjDa0BL9HzOPLOXivaIdOiHfKZ0GPedz23lupvitklfiaV9zpqeVCE9y3PmcZ7qOL0xczKCPJVx6mPOzp2lKk5dLPeQMXHi5wSBh6Rq6Oc2sZOCCesxldAfpYyzgmlfWBWUjuKnBdNesAoovcTPC6a9BFQ/6SZxYjDhJ67y+VGWdWYw4Q+qen6CEDs1mGEdqXgTB7Fzg+kRy1Xt5PDlqHZz5xZU6aYza6LSzfATVm78vAjqNjP8BFQ4zwlQ4WZ4CKpuMp+fqm4zvERUNs9PxtnS1IhFVDV/2DJVtTn7RkREE6Xx/JOtWSOcqZmBMV+gmc1cITJK7jyJ7HWjMn80bjYKiRNsoB+zT7CBCsCR4NCGlvpZrVzp7fLjRjmyW+SHqWBBezGe+PWfqFVcyHqmUz/3E7QflJQu5jN+3ydo/f3vzb6fvhDoYvvyeV6QxDwFXh9xdQVeE5HvSyTyia81/VbZllNfI/GyC2Hbe+nTh74+/W8zO39p/jsSqtOGi0ZsxgJycb1w8Yi/dm1amobf5hb/FYi8N7BNvcw57pr7Cjn0XfKP2OS+8g19l5t4gUL5xcusY60RLwkp2136lxxnjf1MYUDSvric/9MnkTU8IG07a/jsn9aJeAtJ3I67+b+lE/QXkLovzmYeV414wpL3xdG8Y6rRn7CMiMbXALnJ8dTY5Aipmtdp8epjqbEdG6th1w37lcdRYyEV0ZOvcXWLY6jRvT4iLLvZ1/yfhYr4jCy6S1fcpNB88bB09uQJzv6dW7rj5gnPvq+lO2KWAO27uo2nxNSb++tYwbwPCtLXXGLOEdaIl5gwfR29BUdX4z6xQO06nHdkNe4NC9Wut3lHVePeAoK1627mEdWIv7hwDX58eM7R1IhfKGBft/s5R1ITXpCQ7TmacxQ1PpK5grY7rK89gpqam1DY9mfmrKOnEX9hEfWql8w+chrxFxC6L85mHjWNeAoK3m6WP++IabJih8K3qNZnHS2NjWREAL8O5y2OlMY2rIgS7tTANzhKmhz7TElc3I1bHyFNLDYJPecGR0fnjdO88bnZuPjHRd1Xolw18uYY/3XN/KOi1lLmQdGhO/MOYV0cJI5gJSyHDmB55lPHryI+IschLy6geh27sVGPAT3b8ZehaEfjKu4+oA67/jNk7lkdyFK+nQ4Ev/8Sb+nvG/66ef7mKOSO2zka+bzhnsXdLv2ZIZwvD7/AofJLJ2ap6XFP+ID51dMcRT31ndCxMvc75Vf3qe8U9zRHWY96ChxCv3iapa5HPSWPirtb1RKFPeo9fGz84nauyp7Yb4JHyJ39ZqbSnvAYPk7uuJyrtkd9Bo+WXxzOVNyj3kLHzC/O5qnu8XiJH9a+Bs1NlPf4xAmfKL5OmVer7/FkInQa9ZpLvFKBj4dZ9Ez3NdZuocInsozoAW83k5yrxCf8Rhfp5St0xsHvi5flMyv3ELh/J5fv2rkHwn1/y3fUzMPhvrtbeUtOzXkKfTTJDBwav+Ylc1T6qKf4AfLrSC5Q6lN+Q4fJXafz1PqUx9DBctfjPMU+5TF4yNx1OVO1j/pMHTi/Rusi5T7qO3D4/Jo2zFHvk57wQXTP2RwFPzWq+YfS3SF+rYqfnruBA+r+zJ2l5Ed9xg5EXzWk2Wp+1Gfw4PrF4UxFP+otcojdrSjmqfoZkkLgQLuQE2Yp+/FRjR5uvw7tLdT9+GYXPenu1OI3UPgz7kP2sXdxZ26t8icXpKQAdQOlf+54zR2nG46Pq/f/uTlOg3r4403U/ouhLLHf9GWO1n81H5X6U3ax0u8bjwv9MQ9Bnf/qIHlIXdif/FxydZpmTlfz9vMltuvjtKy8Wh4/zbMbyBIi1v1W870kBOiro4UHt2N3HarNV4+zxOaoH6Q1O37mSM2J7zOtV73vk1+sJr5P1M8cmTnmB6rMVz+zROaYn4TG7C2QSyTmmO+Qwnx1Oldgjq9zAX3ZXedmystxfyF12XU4V1yOeQxoy85CO09ajvnCyvLV1TxhORolMV3ZCZWbyMrRqRKSMZ1J8mpROdaBgKZ8df9aSTkaXBFF2YmwWwjK8R0/oid7GctcOTnuNbYYL16Jk1ry1cfiuZSnJIs7uHhPztORhbfFO2aWiiyc3chXairOk5BjWSJUkJ2MY46AHPMT04+dMVwgHye8YvXYczlPPE74w9qx52+edJzwF1COPYczheNE7RLRjb3qZYFsHPMMVWMnJZgjGqf8IM3YdzVHMs6sBVOKMSwNlwrGybkK9WIxU2fJxTGPYYXR0SFmi8UxjwGt+OpuplQc8xVUir3aYJ5QnK78oU4sq/5ZMnF0PCMqsTOotxCJo9tZRCN26+gbSMTpO5CpEMt7cmuBOLX8pPShG8jDM8dq5hjdbmxcbfgXXO+Of76JPuyYylKIzz0KlFCnuntuj+ANj64bp9EiH9V0Wnnmq/zfFpp48tfMY1cDWdd1dmmS+U3EHvdcndBi5XpwGr3GB1yJkZ/ob1DFfe0+1rvffgI0wwuya6PFPt6e6irt5NxquZfDIcPJ4fAaH9+1h0PToUxr4sltusTfqfqyq7p4OF/bLJmZ+6qP35Zzg7ydPjF6p7rqa/ysjDd0XrvbeYbUbur43Ox2fs/v1017vjS8nW9UbU0dz6m1cryGXho89XxtecsIwz/ej2LMtryF90j+7LpekEHn+M3weSN/sKL21ow5NXXaF6qqpbs5dXViza2htuVnQ7P0rbi/x6Ei7utj31SHaQLrupUtb+G9P1Wf6lNiqjqNFvr0icFT9fmPx/7U1PHv67e7jefmmOfZbXeLca4SiUklcpLlnrq6Ou2mj+v5eeO5yU3W3CHH2ScG1Gl0C5+HtppyFtffucFNvt+hrhI12LnFTeZjCwVSbza2s7TR1N17Glr+BR288G+g2+62nqcoBnvOJzKpMf7PX376r8QYn5vcwt+HU/uU9Og0uoXP96kF5/3tVpz3Dy/NIT4fL00W+lsXBa+vDt/Dg21Th2/G//xBvblcEiuS3nhXBYn7x+awP9Xx/BL7f+Ncm98R2/lAfwIPTGf0JvHDogv6cqirD0t6cr7uZv2AB8ky+hF9Q9ayfsRXt3A/wm+1WNIPdOAtpx+xd3ot68ey8Yi9nyuvH/6StfvYtl39y8tDf6oTK4lsepMlM0OnfA+Eyld47J4PTcKhbXI7fz+3bY7Pc7Ob+D3frsHsj8c9IBTo5rqtb92Lt5+bRLUxbXyrFOD7puv/Up0em8RuJZvexv/+ny9d/1fTekhZU0UXbH+bu9Ee93WKcbitlqYpjrBaP9LJqVI+vBx3Bsh9ff7kDyoKg9YuPdnTvn4Eps6f5JvC8tzVoPf5PKNu2SINpn633zFWH7uX0/mwni8VX41O2swzfkGk3lkFad5rletg33R9ddyhobUfZY/qod399nuDb5P9LPuLf+7r496TJp3ve/kw19xDu//yl/ZTjcL78lmusWPb/ziciuzqnTn7A2zKJrmmm4TdZonRXXU0nal2KDadT7MNGij14xH18PLZjLA5juyke3tyuasXPV6TXNNP1fM4535tQ6ZlkxmmTftfW3GY1zPtNck1/Vj337Yvx139fXOqd94JqavxaaMZ5n95++uvdYeC4fph9gJSdR8HAPVri5aQy4fZ5k7V7xKHOPaun84x6OrxvrFv//anWXH6szx7IILUfp69U9b9y+n46+kFWbx+OOPe+k+5eXfWfJS9YjZH2tc7tF6On8zbwv7r5emhRrPE/Tj7aw5f5NsG7oWXz7JnsgtPnNnbfooPO1/Pvnz/xx/o57ffX6x8qk5N9XCou6/Pn+Qa+vnt9/T9H38Ahs6fzBt0ceJJDvr4ca7J53He/XgUdPhqVbTIN9wc+x+P4VnvN5jd35hhv8msHv8UGwjn8+z1xbSODK/fYK7Z8CiIFvMM//TSd81+QrCldb/Z7Gxo2EOC4wJaLXIw/O8/KrgtwnaLneQ4WGQ8fBdQM+TiH/d3jVEVvvnX3UBQh+Tjmzt6w2/Ku/u7D0192Hd337wbvd8PSOSpNhXPvt29mH/+49xszHmGxmPrr1d39+9W93r1piT9j3/cv7MXmw/MH6yN61/Mheru/p265/LNVpF3oZpcqLwL6e7+HaELaXIheRfy3f07Rhfy5EL2LtR39+80ulBPLtTehcXd/bvivti+oY13XTG5rvCuW9/dv1ujQV1PLlx7F27u7t9t7gt+o9Z+TzeTCzfehdu7+3dbdOF2cuHWu7C8u39XogvLyYWlf/+HcFArdKmaxo4SwWOiR8GLQfz4AaSGsFAEL57GkPKDSA2hofheb97Q1r85ahpHyg8kNYSH0tDzNJaUH0xqiBFVwIunAaX8iFJDnKg1vHgaVMqPKjXEioJxpaaBpfzIUkO8KBhbahpcyo8uNcSMgvGlpgGm/AijIWYIRhhNI4z8CKMhZghGGE0jjMQSZdYoGGEEVik/wmiIGWJ48TTCyI8wGmKG9L2mN2pT+BdPI4z8CKMhZqi41+WbTemvWDSNMPIjjIaYoTWaGDSNMPIjjIaYoQ30PI0w8iOMtqGthKYBRn6AURncTabxRX588Sq4oUzDi/3wYhXaU3gaXexHF5vogjOKp9HFYhM00QVnFIN90I8uHuKF4YziaXSxH108xAvDGcXT6GI/uniIF4YziqfRxX508RAvDGcUT6OL/ejiIWAYrtk8DS/2w4uHiGG4ZvM0vtiPL23iC67Zehpg2g8wPcQMb0DyoacBpv0A0xRcRPQ0wLQfYNqkWVvkeBpfWiRaJr5KtAxokGv58aWHiNErePE0vrQfX3qIGK3gxdP40n586SFiNMGLp/Gl/fjSQ8RohhdP40v78aWHiNEaLbp6Gl/aj69iiBgN89NpeBV+eBUqeKeKaXwVfnwVFLxTxTS+Cj++Cg7eqWIaYIUfYIUO3qliGmCFyOaL4J0qQEbvB1ixDt6pYhpghR9gRXh7LKYBVvgBVpgAW6PbPI2vwo+vogxmBMU0vgo/vtarYKq8ngbY2g+wtQpfPA2wtR9gaxNgaPFbT+Nr7cfX2sTXFlZf0/ha+/G1NvFVwoun8bX242ttykVYTK+n8bUWJeMQMQWcFmtQNfrxtR4ipiDoeRpfaz++1kPIFAwvngbY2g+w9RAyhUZ3ahpfaz++NqvglNpM42vjx9dmiJgC7sybaXxt/PjaDCFToCm1mcbXxo+vzRAxxQYN12YaXxs/vjZDxBQwODfT+Nr48bUx8VWiXk/Da+OH12Yd7vU0vDZCldiEew2ECT+8NkPArGHOuZmG18YPr00ZvngaXxs/vrarYBq0ncbX1o+v7RAxawUGezsNr60fXtshYtaErp2G19YPr+0QMGtG106ja+tH11YH58R2Gl1bP7q2Q8Cs0UzeTqNr60fX1gheBRzpaXRt/ejaDvGyXsOLp9G1FbqXia4NvBhIX350bcuQ+LmdBtfWD65yCJc1LOLKaXCVfnCVJrjgNlNOo6v0o6scAmazQl+5nIZX6YdXOUTMRsGLp/FV+vFVDhGzIXjxNL5KP77KIWQ2cJsppwFW+gFWDiGzgVO5nAZY6QdYaVRVGJ3lNMBKP8DKIWQ2MDrLaYCVQlwdYmYDo7ME+qoUWIeg2Wyhxr5CEqvQWFdD3GxglI2fyeuFzLoaQmcLA238TF4vlNZVOBMbP5PXC7F1FU7Gxs/k9UJvXYXzsfEzeb2QXFfhlGz8TF4vVNdVOCsbP5PXC+F1FU7Mxs/k9UJ7XQ3xtEVb2PiRvFyEnwpvnwop/BOJfwinLdoFFdT4RfSpsIihkMwvdX4j3W/RRqqQ0C+VfhUWYhXS+qXYr8JqhkJyv9T7VZAhKST4S8V/lPzh0oEkf6n5GxkfSqMKif5S9VdBVVYh2V/o/spI+VBcVUD4V0L5V0bMx9MeSP9KaP/KyPl4Z1dA/VdC/ldG0d+iREoB/V8JAKCMph9YNQACUIIBKCPrB1YtQAGUwADKKPuBVRuAACVIgDLifmDVBixACRigjMCPcyMFeIASQEAZkR+nRwowASWggDJCP84oFeACSoABZcR+nAsrwAaUgAPK6P04HVYADyjBB5SR/AO7HiAESiACZVT/bXGv+c16tRbXg/gTlEAZ4X+LamsFMIESnEBxuFBVgBQogQoUh2tVBWCBErRAGQCw3eCvD8JPAANlGABOsBVABkowA2UwAM6xFaAGSmADZVBAIGkA5EAJdKAMDcBpugLwQAl6oAwRwJm6AgBBCYKgDBTAyboCDEEJiKAMF8D5ugIYQQmOoAwawCm7AiRBCZSgDB0IJM0AJihBE5QBBIGkHfAEJYCCMowgUDQApKAEU1CGE2y3sP8AKyjBFZRBBdsSzh9AFpRAC8rQgnKFlg/AFpSAC8rwAsw1FMALSvAFZZABTrsAYFCCMCgDDQKLP2AMSkAGZbhBYPEHmEEJzqAMOghsXoA0KIEalMEHJSwZAGxQgjYoAxBKmPID3KAEb1AGIZQwZQfAQQnioAxECOx8gDkoAR2UAQklTNwAdlCCOyiDEkqE4xQAD0qQB2VgQgn3TYAelGAPyuCEEiETBeCDEvRBGaBQbu918YY28np0wEgE3jpcbwACoQSCUOtwvQEYhBIQQq3D9QbAEEpwCLUJ1xsARChBItQmXG8AFKEEi1CGL5QlHHqAI5TgEWoEErhgAERCCSShDGUIJPwASihBJZQhDYGEH4AJJciEMrAhkPADNqEEnFCGNwQSfoAnlOATyiAHtVrhGwCiTzAKZbCDWilsAMSf4BTKoIdAyg1IhRKoQhn8oFYEOwBwhRK8QhkGEUi6AbJQglkowyECSTfAFkpwC2VQRCBpBuRCCXShDI4IJM2AXiiBL5QhEoGkHwAMJQiGMlAikHQDhqEExFCGSwSSboAxlOAYyrCJQNINUIYSLEMZPBFIugHNUAJnKEMoAkk3ABpKEA01Ig2ctgCmoQTUUIZTBJJugDWU4BpqBBt4CQJkQwm0oUa2gZNuADeUoBvKAAu1YjiBAeBQgnAoAy3USmMDIAIF5VDluAgW2AAIQUE6VDkugmtsAJ31lYd9x/PkG2SAAO4ggTvI4AtcuRDAHSRwBxl8oVYwByLAO0jwDjL8Apc+BHgHCd5Bhl+oFcwECAAPEsCDDMBQCu5kBIgHCeJBhmAoBXcyAsiDBPIggzDw4S4CyIME8iCDMGD5RYB4kCAeZBAGPkkMiAcJ4kEqeCCYAPAgATzIEAx8FhkADxLAgwzAgFkoAd5BgneQARgwCyXAO0jwDjL8AleOBHgHCd5Bhl/gLJYA7yDBO8gADJzFEgAeJIAHGYKBs1gCxIME8SCDMHAWSwB5kEAeZBgGzmIJMA+SzzoYiIGzWEJPO8jHHSgsOxN64GHyxENYdib4zIMIP4MxAlk0oece5IMPpMNZNKFnH+TDDwZk4Cya0OMP8vkHWoezaEKPQMhnIAzJwPoDoacg5GMQhmTgLJzQkxDyUQhDMnAWTuhpCEE+yJAMnIUTIB8kyAcZkoGzcALkgwT5IEMycBZOgHyQIB80kg+YRRMgHyTIBxmSgbNwAuSDBPkggzJwFk4AfZBAH2RQBs7CCaAPEuiDDMrAWTgB9EECfZBBGTgLJ4A+SKAPMigDZ+EE0AcJ9EEj+sBLKEAfJNAHGZSBs3AC6IME+iBN4SycAPsgwT5IczgLJwA/SMAP0jqchROgHyToBxmaEcjCCeAPEviD9DqShQP+QYJ/0Mg/cBYO+AcJ/kF6G8nCAQAhAUDIAI1AFg4ACAkAQsUqkoUDAkKCgFChIlk4QCAkEAgZphHKwgEEIQFByEANLOYSgCAkIAhFnrIgQEFIUBAaKQicxwCCkIAgVIRPkxKAICQgCBXhA6UEIAgJCEJF+EwpAQpCgoKQwRoKP6BMgIOQ4CA0Pnih8COkgISQICE0PnyBH1QmgEJIoBAybCP0MCiIQMFCyMANhR92JkBDSNAQGmkIDmGAQ0jgEDJ8A1eCAIeQwCFk8AauBAENIUFDyOANXAkCGkKChpDBG7gSBDSEBA2hdfBYMwEaQoKGkMEbgUoO4BASOITGJzNwJQd4CAkeQoZvBCo5wENI8BAyfCNQyQEeQoKHkOEbgUoO8BASPIQM3whUcoCHkOAhtFlHKikAREgAEdpsIpUUICIkiAgZwBGopAAQIQFE6AxEcCUFgAgJIEIGcAQqKQBESAARMnwjUEkBHkKCh9DIQ3AIAh5CgofQNnzKngAPIcFDaBs+aE+Ah5DgIWT4RqCSAjyEBA8hwzcClRTgISR4CBm+EaikAA8hwUNo5CG4kgI8hAQPoZGH4AwC8BASPIRGHoIzCMBDSPAQGnkIziAADyHBQ6gMn7wnwENI8BAan/LASxjgISR4CI08BFdSgIeQ4CFUFpFKCgAREkCEzkAEV1IAiJAAInQGIriSAkCEBBChMxDBlRQAIiSACJ2BCK6kABAhAUR4FT6JxYCHsOAhvFLhSooBEGEBRHh8/gNWUgx4CAsewisOV1IMgAgLIMIjEMGVFAMgwgKI8BmIwJ2QARBhAUR4FX7qmwEPYcFD2PANWAkxwCEscAiPOASuYwx4CAsewgZw4EqIARBhAURYhc9CMyAiLIgIn3/mCf/sB2AiLJgIjz/1hCshBlSEBRXh8eeecCXEgIuw4CI8PgcCKyEGXIQFF+HxV59wJcQAjLAAI6zCJ7MYgBEWYITDT4Iw4CIsuAiHnwRhgEVYYBEOPwnCgIqwoCIcfhKEARRhAUU4/CQIAybCgokwhU9mMWAiLJgIU/hkFgMkwgKJMIVPZjEgIiyICFP4ZBYDIsKCiDCFT2YxACIsgAhT+GQWAyDCAogwRU5mMSAiLIgIU+RkFgMkwvIXojh8MovRj0TJX4niyMksRr8UJX8qyjAOXAkx+rGoya9FhX+tgOHvRYkQ5PAPFjD6ySj5m1EjE4GVEKNfjZI/GzUyEVgJMfrhKPnLUYZx4EqI0W9HyR+P4vAzmIx+Pkr+ftT4OEjgehCAgonwyERgJcSAibBgIjwyEZxBACbCgonw+DgIziAAEmGBRHh8HARnEICIsCAibAAHroQYABEWQITHx0HwEgZ4CAsewuPjILASYoBDWOAQ1ptwJcSAh7DgIXzmIbASYsBDWPAQ1mW4EmIARFgAET4DEVgJMQAiLIAIj0AEV0IMgAgLIMKGbwQqIcBDWPAQLjhSCQEgwgKIsAEcgUoIABEWQISLIlIJASTCAolwsY5UQoCJsGAibBhHqBICUIQFFOEi/DNnDKAICyjChnHgSgggERZIhA3hCFRCgIiwICJsAEegEgJAhAUQYQM4ApUQACIsgAifgQh6vIMBD2HBQ3g9lsLo+Q4GPIQFD+GRhyj0s34MgAgLIMKR50MYEBEWRITDz4cwICIsiAiHnw9hQERYEBEOPx/CgIiwICIcfj6EARBhAUQ4/HwIAx7Cgodw5PkQBjyEBQ/hyPMhDHgICx7CkedDGPAQFjyEI8+HMOAhLHgIR54PYYBDWOAQjjwfwoCGsKAhHHs+hAEOYYFDOPZ8CAMcwgKHcOT5EAY4hAUO4djzIQx4CAsewttIFQJ4CAsewttIFQJ4CAsewttIFQJ4CAsewttIFQJ4CAsewttIFQJ4CAsewttIFQJ4CAsewttIFQJ4CAsewttIFQJ4CAsewmWkCgE8hAUP4TJShQAewoKHcBmpQgAPYcFDuIxUIYCHsOAhXEaqEMBDWPAQLiNVCMAhLHAIl5EqBNAQFjSEy1gVAmgICxrCZawKATSEBQ3hMlaFABrCgoboVaQK0QCHaIFD9CpShWiAQ7TAIXoVrkI0wCFa4BC9ilQhGuAQLXCIXoWrEA1oiBY0RK8iVYgGNEQLGqJXkSpEAxyiBQ7Rq0gVogEQ0QKI6FX4x2E0ACJaABG9ClYhGvAQLXiIHt95odBPcGrAQ7TgIXrkIYR+3UADHKIFDtEjDoEwQwMaogUN0SMNIfR8vwYwRAsYosf3XxB6wF8DGKIFDNEjDCH0hL8GLEQLFqLHt2AQekRfAxaiBQvRIwsh9Iy+BjBECxiix3dhEKriNKAhWtAQPb4Og/CvuoP4EzhEU/gXmTXgIVrwEE1j/MEfdwdARAsgoml88wqMfwBEtAAienxIhGH8AyCiBRDR4zMi+B0EGhARLYiINoRD4fcQaIBEtEAienxIhGEEAySiBRLRFD4erQES0QKJ6BGJMJwBgIhoQUT0+OtYeAEFQEQLIKI5/JuUGgARLYCIHoEIficC4CFa8BBt+IZiOIMBD9GCh2geIxDOYMBDtOAhenxGBHcfxJ/AIXr8cSx8OYg+QUO0oRvw3R8awBAtYIjmTfCVTRrAEC1giDZwA7+1SQMYogUM0VwGX9ykAQzR8n0aBm5glK7RGzXkKzUM3MDvQdLorRrytRrjAyL49qEXa8g3a4zPh+D7h16uMXm7hg6+EEnD92uI6DNwA78TSaNXbMh3bBi4gV+LpNFbNuRrNgzbwG9G0uhFG/JNGwZtBN5rgt61IV+2ocNvQ9DodRuChGgDNvBZEA1AiBYgRBuugV8DoQEH0YKD6PHBELj2AgyiBQbRhmpAFVQDCKIFBNEGakANVgMGogUD0ePbN/Dl6PUuIvYM0MAvTdIAgGgBQPT4Cg489wD/0IJ/aMMz8KuTNOAfWvAPbYBGIHMBAEQLAKIN0AgkLgCAaAFAtAEa+B1KGgAQLQCINkADv0ZJAwCiBQDRBmjgNylpAEC0ACDaAI3Ay5QAANECgOgRgDBe/AEB0YKA6PWY+eEIBAhECwSiRwQSuoUgBAUE0ettJPsFGEQLDKIN11AM03fAQbTgINqADaVh+g5AiBYgRBuyoTQsPwEJ0YKE6M1Y/sLyE5AQLUiINmRDaZi8AxKiBQnRhmwoDZNvQEK0ICHakA0F39ikAQnRgoTo8ckQ+CogDUiIFiREjw+GwPfqaEBCtCAheiQhGpaPAIRoAUL0CEI0jD/AQbTgIHo75n8w/gAH0YKD6JGDFDD+AAbRAoNogzVUAeMPYBAtMIg2WEMVMP4ABtECg2iDNRR8244GGEQLDKIN1lAFjD+AQbTAIHoblqE1wCBaYBBtsIaC793RAINogUG0wRqqgPELMIgWGEQbrKEKGL8Ag2iBQXQ5xh+MX4BBtMAguhyLXxi/AINogUG0wRoKvpRGAwyiBQbRIwaBGEgDDKIFBtGljuyhgINowUH0+FxIYA8FIEQLEKLH50Lgq3U0ACFagBA9ghD4eh0NOIgWHESPHAS+JUcDDKIFBtEjBlnDGQgoiBYUpBgpyBq+DA5AkEJAkGKEIGs0gwrAQArBQIrxN7LWaAYVgIEUgoEUIwNZoxlUAARSCARSjE+EbNAMKgACKQQCKUYEskEzqAAEpBAEpBgJyAbFXwEASCEASDECkA2KvwLwD/s38/73T/Wpr/c/ju+Bf/fu7v37/stzfXf/r7v355fD0+UF9P+6I333zb/+fX+nafzvdjX+d3hNx/kfZP9hm+rt8I9/X18gb/5se2M+G7r3vtr/86Xrn6tTfewfHtrPdef2gotrL7g8m15zpunDwftG5Hwjst1cZ9vaN13/VJ0em6PXQ2eceGt7SHlWH16aw97rIzt9ZNvHTZ613ce27eru+dD01efGH0fHLm9sL9Vsu6M517AzqLy2hlezDL889KfaD76tY9XeqiLzVu3a474+dp5BXl8N6pXtps4z+HhqX55da1snKod3Foyhb2fF8GNQ4z8253gYjvKP/9hmjszHunn82Ls+hweXrqGxtgZVZqQ1x64+eQapdMbYhlqRGWpP1ef62J8af7ZurhZtjHHmGD81R2DQCQM7tbjIM3iq9s1L58VqqZzbVmSuT6OdL54dcu2UeXbM9PFCcuWMv101c3tlrJ3a1rfofD8urMXc/vW1F+OlE24qd0L/3uz7j37UuotuUdqozVt5qg99fXp53ld93TX/XfuGC3c6sDWcFx1iZ3Bmgt1jOG+xqY6PB69fhXMP1uf1cHiZ1/gPyuvesA+6Rp1IOc/7bWktqvM/Nud/DD/GOP5jbUfbtuFN3rA/NEfa1ztvuAtnjIZaJMtOu/fmTeHcMtvdbd76MJiaLMPasVfkd+mp/VR7m+6gwly/3Ca/R+1z37RHb8XSzhqYmQUMlp5P7bNnZ+10aZsZNe3+i8zi2FlBdV7aJGJPkzs24zXFebmiIm+sdtWxOfb1qdr5W5o7WINAlGWrHix5s3fjrlR5YzVaEWGwcveHTWl3c/tlNxs7n+zE2uStrbuP9e63qjk++F/evTWbvHV/tOQvXsMRlKshlTmKxtCprnxL7jxQeSugsbRrD4ema9qjb85NutSMb9ge/bXezYp15hK/+9gc9qfa65E7UjZJs3vSAOjm2N1XvTd42vmymbv4rjnt/N1DOyu9th28lFaZX9xYbY5T60Ot7iyYeZuBNffcHr48ihu83rr28la70V770nfNvoZGS9do3pq1O9TVyd+v3BTN3uG8PWJ3aHe//d74BYTy18HM73poj/Vz2xz7rjqdqi++QXdHzV1JBoOnuntuRX0zCKFXa9vMRWCYtXs/41buGqhsMpQZz3YV2FWHw0O1+83bidy1PjP02qdBF3hqjt6OpJyoU7Ys0Jl35GLSvxnOvVCXBSEz9tpj159edn3rRaBzP2z2p+w/Lvvnams30nOMDr/aMf7jsi6tMkOjPX6qP58nlHdLS/fLbcimiZci1ZaSVhPh3Og+1VVfi3RBuUWIvghH68wIMibByuUWS5oyb4wxVh8OzbOYLK5ooe1GMCDSfLOHRu5R7nSmOSNoFgjflpsaUOZkOduaLqiu9jOcIcyxtq+6j8NX7Ft/lXEThMzUXW6Uro5haxUrZ6ztikN5S/W+fqRT5Wdx3kKztje3zOxsc+q9lWHjBF5pd2KbACqbEhJZ7WdjJzLZiZyZ1w7qYnXciU3HnUyZ1dv+VP3ufQN3+q9suajPK48q7VpkZbHhB7zGntsMZHiE5Hxb8taioQsPnzwhYOMu2isrG2s7kNYDaVvG2n6xXtteWHnRqmkDE8ztDpoYbj2qM4sssJywO/PPvS7sOBd5a1V99INYOUHMmTplfexeTvW4D/gZlbvclXljNho7vjw9+MXWQBwdY3khORo734IxH/LD3LW5yZv6o81P9bDvTldQ756s86K2/tzXx70ULYYjHk7n8m7nh1P79M/ODzdy5rJVZLTOi7rHuq+qh4eqk8rQduVOK7s+2Tpd2alMlp2QXcPYRipnrozXLvg9cOPB6t2Z2exj3T+0L8ddvW9O9a6X5WPhhu02b0d9rPuhtD+1jZhPLlDI1AgcW783/cf2pT+1fTXp5srdz+waRRaVkV3Z2N6U4Xm4XPfTuayc4R5euXNOH63Ct7J3tbCL5Spvvj/W/URfG043OHcg+6a2Hz50dT+M2UQeLd14LbLv6XPb18e+qQ7+uuHSQc3Z1rqq7+vOXzAKd5Zv82b5ZMBcI2u7wdocX9mtTW1t1mCxC23tHmcJ4vDUbXYXHhqxnq7dtKHMGxdvt147XyRzMKbEypV/yM6LtV1/LqA4U7mdAizlJKMXa5k8zMiRXb0za5pv1C2kN3mT52JtSJlB9eImkcUqb731bE6qjQ25Fhf0cvjfh0pMgo1yreatkp5VlGVt2DWat/YNRv2+bV3mlomPmg7JvIVzM2x5oOxKquyUVLYUIZvIk+W7bIk0Z25KTTddyF0pbmtXCJvYqsL6VBel3S4M9sgFZ9KFpuuap2cRkKuNu4vYxN9m2sOvx553EZunZIqFTdcNO6SHjlyd23I6tbL/sAuD2thvqux3t1IFWxWBM9FM0/Wn5vHRT1xduW1tkb3dLpW9ycrWb2SVJdrYcsgKBbzJmxmHuvrgrYfuoFuSYjl5kTfAciHwktNzjy9aUqYMfWhFBe1ONXv4gvN2/6fq2SidfTtm5v4e625L27wv/FQ9j5b6diqhulNZZx6teKpOv1XdpM7fulWyDXuyYUq2UGWbY7PV8HTmev5UffYPzjgJqbV9jkEbesrmEGQnPVmkzLYN2zY6k8U9VZ+9L+4qOta2nRS2Q1YiJBsOZL2ybcO2jS7yZsdE1XXG3y64djzs5FzbpWFlyxm7gLNtw+vLjMpbH6UU7J5XsMuh7Yf9hyXrZBVysl7ZtmHbRmcqAAOV9gQTJ0BsDaFsVaHslkH25AjZpJJtqcf2jIAu83pwbPtIWuSm2pkL4FgHeLuesxeUNroyxdLR2q599uetmwRmCsPP1X7fHB+9pMC57fZeKqvFK7sBKbsXkJXyyZ5jYHtajzMlgolm4R1CON86W8VdNPrMVM8YDzA7z03eDmHMtZAoutRzlbcCjwLQwIdEublyi0OrJZAdWNrYtc8uDJxJzcEweMLq2W5hHWUmqWezmLS6+3JmwX+xB2+bO//KvM34ufWPlDjfOXP3vdTd093cBY6ZwOhU7Wlfe/NOeQdU7O6my7wFBp3xc8Fv5kFhdMRv7ZrJ21lldkJudpJZspyqLztZlZFHTvNu/dnOR//IoYtvMkXR08NL50kD7pmrPAu13NqUN7jnW86ZA4Tgt4tvtcpbhU51f6qO3aHqRWnkBCTZbI9sbs0WoLBdLXTmEYVT3b+cjv3pRXB79+Zmij5GhhS9dofUlm9kAQ6VtvuFzdIy12oglW3dTC0TTne7yl8gt+6ZLSt6KSuDka2waWvzO3tonTPPNhiPoAZZucXN9lLjX7ZzmzzZJJgzV0rjz1uJXDHF6vDKJmdqa/M2m/XT1iYQ9uguZyIp49qHls6XtBxNWb6n7JgSXxJtm/nbE/ycSda6ujrt/AO/HpCwczvzntXP1UlGtotNtMqba9bQhOW4j4Bolbesd3U/kbE3znQrL/quzdJLO642aMnmumwTeM5UZTurpnvenclj57qyWYyyhIfstCLbH9Y2xDIrgm5Q3ie0buWm3KX9itY2WQTClzUzM8s03rpGApaN487aVtabskUO2VlDtjRiG/CceVy5q/vJOrVxtjv7VZVFZ8reVrLzhmx32Ir9nIlIu74S6ra7S3JmJjM5xO/eqkzBsPvS9fWTlzi65+Mv4oANe5uWky19yUp5bJdV3lxoVF4o9K0EnS4Qt7W+zjxH1rcTFutRNGstbz0IpA1u3mmXBLKRQjZ2+CIkZebw/an6NJTkftLsMgrOCw1r6MPLcYJaty7CzFxj5Ulzt0Cx+7i6SElWkyRLvsmWtry6KFl503RwPCFvbh1qlRBlswhlfZE94kZWd+XVRa/Ji6WXo1kj9mPN4A2im4JlPqU0Ptvi31u3Pqe86TKakbvd1j1yYxM/sgksXXi01f/ZnjTWNu3VlLdxj/69E4h2JRdbR+nOuwvbuKgbdn+y4aIzIRTogDjV6h6+sI/jkP3CvLpI5nZpydQARscI8JTu6K8vHi8P51zEVjsP1nkpF6jEnUHNVOa8A2Lu8aBMogWe83IfF7bsjDPXEm/g3IrI6m2by4Ji/7G1M9nuQ2STebYIjzPJtf+MknPb7D62uSwo9h82VyerDZPtD1tBlnOOR/7j/u65eR7x7jfv/vHvf/8/SGmAbVySAQA="; \ No newline at end of file diff --git a/docs/assets/style.css b/docs/assets/style.css index 598eb6fc..9d619a64 100644 --- a/docs/assets/style.css +++ b/docs/assets/style.css @@ -1,87 +1,186 @@ :root { - /* Light */ - --light-color-background: #f2f4f8; - --light-color-background-secondary: #eff0f1; - --light-color-warning-text: #222; - --light-color-background-warning: #e6e600; - --light-color-icon-background: var(--light-color-background); - --light-color-accent: #c5c7c9; - --light-color-active-menu-item: var(--light-color-accent); - --light-color-text: #222; - --light-color-text-aside: #6e6e6e; - --light-color-link: #1f70c2; - - --light-color-ts-keyword: #056bd6; - --light-color-ts-project: #b111c9; - --light-color-ts-module: var(--light-color-ts-project); - --light-color-ts-namespace: var(--light-color-ts-project); - --light-color-ts-enum: #7e6f15; - --light-color-ts-enum-member: var(--light-color-ts-enum); - --light-color-ts-variable: #4760ec; - --light-color-ts-function: #572be7; - --light-color-ts-class: #1f70c2; - --light-color-ts-interface: #108024; - --light-color-ts-constructor: var(--light-color-ts-class); - --light-color-ts-property: var(--light-color-ts-variable); - --light-color-ts-method: var(--light-color-ts-function); - --light-color-ts-call-signature: var(--light-color-ts-method); - --light-color-ts-index-signature: var(--light-color-ts-property); - --light-color-ts-constructor-signature: var(--light-color-ts-constructor); - --light-color-ts-parameter: var(--light-color-ts-variable); - /* type literal not included as links will never be generated to it */ - --light-color-ts-type-parameter: #a55c0e; - --light-color-ts-accessor: var(--light-color-ts-property); - --light-color-ts-get-signature: var(--light-color-ts-accessor); - --light-color-ts-set-signature: var(--light-color-ts-accessor); - --light-color-ts-type-alias: #d51270; - /* reference not included as links will be colored with the kind that it points to */ - - --light-external-icon: url("data:image/svg+xml;utf8,"); - --light-color-scheme: light; - - /* Dark */ - --dark-color-background: #2b2e33; - --dark-color-background-secondary: #1e2024; - --dark-color-background-warning: #bebe00; - --dark-color-warning-text: #222; - --dark-color-icon-background: var(--dark-color-background-secondary); - --dark-color-accent: #9096a2; - --dark-color-active-menu-item: #5d5d6a; - --dark-color-text: #f5f5f5; - --dark-color-text-aside: #dddddd; - --dark-color-link: #00aff4; - - --dark-color-ts-keyword: #3399ff; - --dark-color-ts-project: #e358ff; - --dark-color-ts-module: var(--dark-color-ts-project); - --dark-color-ts-namespace: var(--dark-color-ts-project); - --dark-color-ts-enum: #f4d93e; - --dark-color-ts-enum-member: var(--dark-color-ts-enum); - --dark-color-ts-variable: #798dff; - --dark-color-ts-function: #a280ff; - --dark-color-ts-class: #8ac4ff; - --dark-color-ts-interface: #6cff87; - --dark-color-ts-constructor: var(--dark-color-ts-class); - --dark-color-ts-property: var(--dark-color-ts-variable); - --dark-color-ts-method: var(--dark-color-ts-function); - --dark-color-ts-call-signature: var(--dark-color-ts-method); - --dark-color-ts-index-signature: var(--dark-color-ts-property); - --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor); - --dark-color-ts-parameter: var(--dark-color-ts-variable); - /* type literal not included as links will never be generated to it */ - --dark-color-ts-type-parameter: #e07d13; - --dark-color-ts-accessor: var(--dark-color-ts-property); - --dark-color-ts-get-signature: var(--dark-color-ts-accessor); - --dark-color-ts-set-signature: var(--dark-color-ts-accessor); - --dark-color-ts-type-alias: #ff6492; - /* reference not included as links will be colored with the kind that it points to */ - - --dark-external-icon: url("data:image/svg+xml;utf8,"); - --dark-color-scheme: dark; + /* Light */ + --light-color-background: #f2f4f8; + --light-color-background-secondary: #eff0f1; + --light-color-warning-text: #222; + --light-color-background-warning: #e6e600; + --light-color-icon-background: var(--light-color-background); + --light-color-accent: #c5c7c9; + --light-color-active-menu-item: var(--light-color-accent); + --light-color-text: #222; + --light-color-text-aside: #6e6e6e; + --light-color-link: #1f70c2; + --light-color-focus-outline: #3584e4; + + --light-color-ts-keyword: #056bd6; + --light-color-ts-project: #b111c9; + --light-color-ts-module: var(--light-color-ts-project); + --light-color-ts-namespace: var(--light-color-ts-project); + --light-color-ts-enum: #7e6f15; + --light-color-ts-enum-member: var(--light-color-ts-enum); + --light-color-ts-variable: #4760ec; + --light-color-ts-function: #572be7; + --light-color-ts-class: #1f70c2; + --light-color-ts-interface: #108024; + --light-color-ts-constructor: var(--light-color-ts-class); + --light-color-ts-property: var(--light-color-ts-variable); + --light-color-ts-method: var(--light-color-ts-function); + --light-color-ts-call-signature: var(--light-color-ts-method); + --light-color-ts-index-signature: var(--light-color-ts-property); + --light-color-ts-constructor-signature: var(--light-color-ts-constructor); + --light-color-ts-parameter: var(--light-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --light-color-ts-type-parameter: #a55c0e; + --light-color-ts-accessor: var(--light-color-ts-property); + --light-color-ts-get-signature: var(--light-color-ts-accessor); + --light-color-ts-set-signature: var(--light-color-ts-accessor); + --light-color-ts-type-alias: #d51270; + /* reference not included as links will be colored with the kind that it points to */ + --light-color-document: #000000; + + --light-external-icon: url("data:image/svg+xml;utf8,"); + --light-color-scheme: light; + + /* Dark */ + --dark-color-background: #2b2e33; + --dark-color-background-secondary: #1e2024; + --dark-color-background-warning: #bebe00; + --dark-color-warning-text: #222; + --dark-color-icon-background: var(--dark-color-background-secondary); + --dark-color-accent: #9096a2; + --dark-color-active-menu-item: #5d5d6a; + --dark-color-text: #f5f5f5; + --dark-color-text-aside: #dddddd; + --dark-color-link: #00aff4; + --dark-color-focus-outline: #4c97f2; + + --dark-color-ts-keyword: #3399ff; + --dark-color-ts-project: #e358ff; + --dark-color-ts-module: var(--dark-color-ts-project); + --dark-color-ts-namespace: var(--dark-color-ts-project); + --dark-color-ts-enum: #f4d93e; + --dark-color-ts-enum-member: var(--dark-color-ts-enum); + --dark-color-ts-variable: #798dff; + --dark-color-ts-function: #a280ff; + --dark-color-ts-class: #8ac4ff; + --dark-color-ts-interface: #6cff87; + --dark-color-ts-constructor: var(--dark-color-ts-class); + --dark-color-ts-property: var(--dark-color-ts-variable); + --dark-color-ts-method: var(--dark-color-ts-function); + --dark-color-ts-call-signature: var(--dark-color-ts-method); + --dark-color-ts-index-signature: var(--dark-color-ts-property); + --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor); + --dark-color-ts-parameter: var(--dark-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --dark-color-ts-type-parameter: #e07d13; + --dark-color-ts-accessor: var(--dark-color-ts-property); + --dark-color-ts-get-signature: var(--dark-color-ts-accessor); + --dark-color-ts-set-signature: var(--dark-color-ts-accessor); + --dark-color-ts-type-alias: #ff6492; + /* reference not included as links will be colored with the kind that it points to */ + --dark-color-document: #ffffff; + + --dark-external-icon: url("data:image/svg+xml;utf8,"); + --dark-color-scheme: dark; } @media (prefers-color-scheme: light) { - :root { + :root { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-active-menu-item: var(--light-color-active-menu-item); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + --color-focus-outline: var(--light-color-focus-outline); + + --color-ts-keyword: var(--light-color-ts-keyword); + --color-ts-module: var(--light-color-ts-module); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-enum-member: var(--light-color-ts-enum-member); + --color-ts-variable: var(--light-color-ts-variable); + --color-ts-function: var(--light-color-ts-function); + --color-ts-class: var(--light-color-ts-class); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-constructor: var(--light-color-ts-constructor); + --color-ts-property: var(--light-color-ts-property); + --color-ts-method: var(--light-color-ts-method); + --color-ts-call-signature: var(--light-color-ts-call-signature); + --color-ts-index-signature: var(--light-color-ts-index-signature); + --color-ts-constructor-signature: var( + --light-color-ts-constructor-signature + ); + --color-ts-parameter: var(--light-color-ts-parameter); + --color-ts-type-parameter: var(--light-color-ts-type-parameter); + --color-ts-accessor: var(--light-color-ts-accessor); + --color-ts-get-signature: var(--light-color-ts-get-signature); + --color-ts-set-signature: var(--light-color-ts-set-signature); + --color-ts-type-alias: var(--light-color-ts-type-alias); + --color-document: var(--light-color-document); + + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-active-menu-item: var(--dark-color-active-menu-item); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + --color-focus-outline: var(--dark-color-focus-outline); + + --color-ts-keyword: var(--dark-color-ts-keyword); + --color-ts-module: var(--dark-color-ts-module); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-enum-member: var(--dark-color-ts-enum-member); + --color-ts-variable: var(--dark-color-ts-variable); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-constructor: var(--dark-color-ts-constructor); + --color-ts-property: var(--dark-color-ts-property); + --color-ts-method: var(--dark-color-ts-method); + --color-ts-call-signature: var(--dark-color-ts-call-signature); + --color-ts-index-signature: var(--dark-color-ts-index-signature); + --color-ts-constructor-signature: var( + --dark-color-ts-constructor-signature + ); + --color-ts-parameter: var(--dark-color-ts-parameter); + --color-ts-type-parameter: var(--dark-color-ts-type-parameter); + --color-ts-accessor: var(--dark-color-ts-accessor); + --color-ts-get-signature: var(--dark-color-ts-get-signature); + --color-ts-set-signature: var(--dark-color-ts-set-signature); + --color-ts-type-alias: var(--dark-color-ts-type-alias); + --color-document: var(--dark-color-document); + + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } +} + +html { + color-scheme: var(--color-scheme); +} + +body { + margin: 0; +} + +:root[data-theme="light"] { --color-background: var(--light-color-background); --color-background-secondary: var(--light-color-background-secondary); --color-background-warning: var(--light-color-background-warning); @@ -92,6 +191,7 @@ --color-text: var(--light-color-text); --color-text-aside: var(--light-color-text-aside); --color-link: var(--light-color-link); + --color-focus-outline: var(--light-color-focus-outline); --color-ts-keyword: var(--light-color-ts-keyword); --color-ts-module: var(--light-color-ts-module); @@ -108,7 +208,7 @@ --color-ts-call-signature: var(--light-color-ts-call-signature); --color-ts-index-signature: var(--light-color-ts-index-signature); --color-ts-constructor-signature: var( - --light-color-ts-constructor-signature + --light-color-ts-constructor-signature ); --color-ts-parameter: var(--light-color-ts-parameter); --color-ts-type-parameter: var(--light-color-ts-type-parameter); @@ -116,14 +216,13 @@ --color-ts-get-signature: var(--light-color-ts-get-signature); --color-ts-set-signature: var(--light-color-ts-set-signature); --color-ts-type-alias: var(--light-color-ts-type-alias); + --color-document: var(--light-color-document); --external-icon: var(--light-external-icon); --color-scheme: var(--light-color-scheme); - } } -@media (prefers-color-scheme: dark) { - :root { +:root[data-theme="dark"] { --color-background: var(--dark-color-background); --color-background-secondary: var(--dark-color-background-secondary); --color-background-warning: var(--dark-color-background-warning); @@ -134,6 +233,7 @@ --color-text: var(--dark-color-text); --color-text-aside: var(--dark-color-text-aside); --color-link: var(--dark-color-link); + --color-focus-outline: var(--dark-color-focus-outline); --color-ts-keyword: var(--dark-color-ts-keyword); --color-ts-module: var(--dark-color-ts-module); @@ -150,7 +250,7 @@ --color-ts-call-signature: var(--dark-color-ts-call-signature); --color-ts-index-signature: var(--dark-color-ts-index-signature); --color-ts-constructor-signature: var( - --dark-color-ts-constructor-signature + --dark-color-ts-constructor-signature ); --color-ts-parameter: var(--dark-color-ts-parameter); --color-ts-type-parameter: var(--dark-color-ts-type-parameter); @@ -158,99 +258,20 @@ --color-ts-get-signature: var(--dark-color-ts-get-signature); --color-ts-set-signature: var(--dark-color-ts-set-signature); --color-ts-type-alias: var(--dark-color-ts-type-alias); + --color-document: var(--dark-color-document); --external-icon: var(--dark-external-icon); --color-scheme: var(--dark-color-scheme); - } -} - -html { - color-scheme: var(--color-scheme); -} - -body { - margin: 0; } -:root[data-theme="light"] { - --color-background: var(--light-color-background); - --color-background-secondary: var(--light-color-background-secondary); - --color-background-warning: var(--light-color-background-warning); - --color-warning-text: var(--light-color-warning-text); - --color-icon-background: var(--light-color-icon-background); - --color-accent: var(--light-color-accent); - --color-active-menu-item: var(--light-color-active-menu-item); - --color-text: var(--light-color-text); - --color-text-aside: var(--light-color-text-aside); - --color-link: var(--light-color-link); - - --color-ts-keyword: var(--light-color-ts-keyword); - --color-ts-module: var(--light-color-ts-module); - --color-ts-namespace: var(--light-color-ts-namespace); - --color-ts-enum: var(--light-color-ts-enum); - --color-ts-enum-member: var(--light-color-ts-enum-member); - --color-ts-variable: var(--light-color-ts-variable); - --color-ts-function: var(--light-color-ts-function); - --color-ts-class: var(--light-color-ts-class); - --color-ts-interface: var(--light-color-ts-interface); - --color-ts-constructor: var(--light-color-ts-constructor); - --color-ts-property: var(--light-color-ts-property); - --color-ts-method: var(--light-color-ts-method); - --color-ts-call-signature: var(--light-color-ts-call-signature); - --color-ts-index-signature: var(--light-color-ts-index-signature); - --color-ts-constructor-signature: var(--light-color-ts-constructor-signature); - --color-ts-parameter: var(--light-color-ts-parameter); - --color-ts-type-parameter: var(--light-color-ts-type-parameter); - --color-ts-accessor: var(--light-color-ts-accessor); - --color-ts-get-signature: var(--light-color-ts-get-signature); - --color-ts-set-signature: var(--light-color-ts-set-signature); - --color-ts-type-alias: var(--light-color-ts-type-alias); - - --external-icon: var(--light-external-icon); - --color-scheme: var(--light-color-scheme); -} - -:root[data-theme="dark"] { - --color-background: var(--dark-color-background); - --color-background-secondary: var(--dark-color-background-secondary); - --color-background-warning: var(--dark-color-background-warning); - --color-warning-text: var(--dark-color-warning-text); - --color-icon-background: var(--dark-color-icon-background); - --color-accent: var(--dark-color-accent); - --color-active-menu-item: var(--dark-color-active-menu-item); - --color-text: var(--dark-color-text); - --color-text-aside: var(--dark-color-text-aside); - --color-link: var(--dark-color-link); - - --color-ts-keyword: var(--dark-color-ts-keyword); - --color-ts-module: var(--dark-color-ts-module); - --color-ts-namespace: var(--dark-color-ts-namespace); - --color-ts-enum: var(--dark-color-ts-enum); - --color-ts-enum-member: var(--dark-color-ts-enum-member); - --color-ts-variable: var(--dark-color-ts-variable); - --color-ts-function: var(--dark-color-ts-function); - --color-ts-class: var(--dark-color-ts-class); - --color-ts-interface: var(--dark-color-ts-interface); - --color-ts-constructor: var(--dark-color-ts-constructor); - --color-ts-property: var(--dark-color-ts-property); - --color-ts-method: var(--dark-color-ts-method); - --color-ts-call-signature: var(--dark-color-ts-call-signature); - --color-ts-index-signature: var(--dark-color-ts-index-signature); - --color-ts-constructor-signature: var(--dark-color-ts-constructor-signature); - --color-ts-parameter: var(--dark-color-ts-parameter); - --color-ts-type-parameter: var(--dark-color-ts-type-parameter); - --color-ts-accessor: var(--dark-color-ts-accessor); - --color-ts-get-signature: var(--dark-color-ts-get-signature); - --color-ts-set-signature: var(--dark-color-ts-set-signature); - --color-ts-type-alias: var(--dark-color-ts-type-alias); - - --external-icon: var(--dark-external-icon); - --color-scheme: var(--dark-color-scheme); +*:focus-visible, +.tsd-accordion-summary:focus-visible svg { + outline: 2px solid var(--color-focus-outline); } .always-visible, .always-visible .tsd-signatures { - display: inherit !important; + display: inherit !important; } h1, @@ -259,1150 +280,1169 @@ h3, h4, h5, h6 { - line-height: 1.2; -} - -h1 > a:not(.link), -h2 > a:not(.link), -h3 > a:not(.link), -h4 > a:not(.link), -h5 > a:not(.link), -h6 > a:not(.link) { - text-decoration: none; - color: var(--color-text); + line-height: 1.2; } h1 { - font-size: 1.875rem; - margin: 0.67rem 0; + font-size: 1.875rem; + margin: 0.67rem 0; } h2 { - font-size: 1.5rem; - margin: 0.83rem 0; + font-size: 1.5rem; + margin: 0.83rem 0; } h3 { - font-size: 1.25rem; - margin: 1rem 0; + font-size: 1.25rem; + margin: 1rem 0; } h4 { - font-size: 1.05rem; - margin: 1.33rem 0; + font-size: 1.05rem; + margin: 1.33rem 0; } h5 { - font-size: 1rem; - margin: 1.5rem 0; + font-size: 1rem; + margin: 1.5rem 0; } h6 { - font-size: 0.875rem; - margin: 2.33rem 0; -} - -.uppercase { - text-transform: uppercase; + font-size: 0.875rem; + margin: 2.33rem 0; } dl, menu, ol, ul { - margin: 1em 0; + margin: 1em 0; } dd { - margin: 0 0 0 40px; + margin: 0 0 0 40px; } .container { - max-width: 1700px; - padding: 0 2rem; + max-width: 1700px; + padding: 0 2rem; } /* Footer */ footer { - border-top: 1px solid var(--color-accent); - padding-top: 1rem; - padding-bottom: 1rem; - max-height: 3.5rem; + border-top: 1px solid var(--color-accent); + padding-top: 1rem; + padding-bottom: 1rem; + max-height: 3.5rem; } -.tsd-generator { - margin: 0 1em; +footer > p { + margin: 0 1em; } .container-main { - margin: 0 auto; - /* toolbar, footer, margin */ - min-height: calc(100vh - 41px - 56px - 4rem); + margin: 0 auto; + /* toolbar, footer, margin */ + min-height: calc(100vh - 41px - 56px - 4rem); } @keyframes fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } + from { + opacity: 0; + } + to { + opacity: 1; + } } @keyframes fade-out { - from { - opacity: 1; - visibility: visible; - } - to { - opacity: 0; - } + from { + opacity: 1; + visibility: visible; + } + to { + opacity: 0; + } } @keyframes fade-in-delayed { - 0% { - opacity: 0; - } - 33% { - opacity: 0; - } - 100% { - opacity: 1; - } + 0% { + opacity: 0; + } + 33% { + opacity: 0; + } + 100% { + opacity: 1; + } } @keyframes fade-out-delayed { - 0% { - opacity: 1; - visibility: visible; - } - 66% { - opacity: 0; - } - 100% { - opacity: 0; - } + 0% { + opacity: 1; + visibility: visible; + } + 66% { + opacity: 0; + } + 100% { + opacity: 0; + } } @keyframes pop-in-from-right { - from { - transform: translate(100%, 0); - } - to { - transform: translate(0, 0); - } + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } } @keyframes pop-out-to-right { - from { - transform: translate(0, 0); - visibility: visible; - } - to { - transform: translate(100%, 0); - } + from { + transform: translate(0, 0); + visibility: visible; + } + to { + transform: translate(100%, 0); + } } body { - background: var(--color-background); - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", - Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; - font-size: 16px; - color: var(--color-text); + background: var(--color-background); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", + Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + font-size: 16px; + color: var(--color-text); } a { - color: var(--color-link); - text-decoration: none; + color: var(--color-link); + text-decoration: none; } a:hover { - text-decoration: underline; + text-decoration: underline; } a.external[target="_blank"] { - background-image: var(--external-icon); - background-position: top 3px right; - background-repeat: no-repeat; - padding-right: 13px; + background-image: var(--external-icon); + background-position: top 3px right; + background-repeat: no-repeat; + padding-right: 13px; +} +a.tsd-anchor-link { + color: var(--color-text); } code, pre { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - padding: 0.2em; - margin: 0; - font-size: 0.875rem; - border-radius: 0.8em; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 0.2em; + margin: 0; + font-size: 0.875rem; + border-radius: 0.8em; } pre { - position: relative; - white-space: pre; - white-space: pre-wrap; - word-wrap: break-word; - padding: 10px; - border: 1px solid var(--color-accent); + position: relative; + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; + padding: 10px; + border: 1px solid var(--color-accent); } pre code { - padding: 0; - font-size: 100%; + padding: 0; + font-size: 100%; } pre > button { - position: absolute; - top: 10px; - right: 10px; - opacity: 0; - transition: opacity 0.1s; - box-sizing: border-box; + position: absolute; + top: 10px; + right: 10px; + opacity: 0; + transition: opacity 0.1s; + box-sizing: border-box; } pre:hover > button, pre > button.visible { - opacity: 1; + opacity: 1; } blockquote { - margin: 1em 0; - padding-left: 1em; - border-left: 4px solid gray; + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid gray; } .tsd-typography { - line-height: 1.333em; + line-height: 1.333em; } .tsd-typography ul { - list-style: square; - padding: 0 0 0 20px; - margin: 0; + list-style: square; + padding: 0 0 0 20px; + margin: 0; } .tsd-typography .tsd-index-panel h3, .tsd-index-panel .tsd-typography h3, .tsd-typography h4, .tsd-typography h5, .tsd-typography h6 { - font-size: 1em; + font-size: 1em; } .tsd-typography h5, .tsd-typography h6 { - font-weight: normal; + font-weight: normal; } .tsd-typography p, .tsd-typography ul, .tsd-typography ol { - margin: 1em 0; + margin: 1em 0; } .tsd-typography table { - border-collapse: collapse; - border: none; + border-collapse: collapse; + border: none; } .tsd-typography td, .tsd-typography th { - padding: 6px 13px; - border: 1px solid var(--color-accent); + padding: 6px 13px; + border: 1px solid var(--color-accent); } .tsd-typography thead, .tsd-typography tr:nth-child(even) { - background-color: var(--color-background-secondary); + background-color: var(--color-background-secondary); } .tsd-breadcrumb { - margin: 0; - padding: 0; - color: var(--color-text-aside); + margin: 0; + padding: 0; + color: var(--color-text-aside); } .tsd-breadcrumb a { - color: var(--color-text-aside); - text-decoration: none; + color: var(--color-text-aside); + text-decoration: none; } .tsd-breadcrumb a:hover { - text-decoration: underline; + text-decoration: underline; } .tsd-breadcrumb li { - display: inline; + display: inline; } .tsd-breadcrumb li:after { - content: " / "; + content: " / "; } .tsd-comment-tags { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } dl.tsd-comment-tag-group { - display: flex; - align-items: center; - overflow: hidden; - margin: 0.5em 0; + display: flex; + align-items: center; + overflow: hidden; + margin: 0.5em 0; } dl.tsd-comment-tag-group dt { - display: flex; - margin-right: 0.5em; - font-size: 0.875em; - font-weight: normal; + display: flex; + margin-right: 0.5em; + font-size: 0.875em; + font-weight: normal; } dl.tsd-comment-tag-group dd { - margin: 0; + margin: 0; } code.tsd-tag { - padding: 0.25em 0.4em; - border: 0.1em solid var(--color-accent); - margin-right: 0.25em; - font-size: 70%; + padding: 0.25em 0.4em; + border: 0.1em solid var(--color-accent); + margin-right: 0.25em; + font-size: 70%; } h1 code.tsd-tag:first-of-type { - margin-left: 0.25em; + margin-left: 0.25em; } dl.tsd-comment-tag-group dd:before, dl.tsd-comment-tag-group dd:after { - content: " "; + content: " "; } dl.tsd-comment-tag-group dd pre, dl.tsd-comment-tag-group dd:after { - clear: both; + clear: both; } dl.tsd-comment-tag-group p { - margin: 0; + margin: 0; } .tsd-panel.tsd-comment .lead { - font-size: 1.1em; - line-height: 1.333em; - margin-bottom: 2em; + font-size: 1.1em; + line-height: 1.333em; + margin-bottom: 2em; } .tsd-panel.tsd-comment .lead:last-child { - margin-bottom: 0; + margin-bottom: 0; } .tsd-filter-visibility h4 { - font-size: 1rem; - padding-top: 0.75rem; - padding-bottom: 0.5rem; - margin: 0; + font-size: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.5rem; + margin: 0; } .tsd-filter-item:not(:last-child) { - margin-bottom: 0.5rem; + margin-bottom: 0.5rem; } .tsd-filter-input { - display: flex; - width: fit-content; - width: -moz-fit-content; - align-items: center; - user-select: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - cursor: pointer; + display: flex; + width: -moz-fit-content; + width: fit-content; + align-items: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; } .tsd-filter-input input[type="checkbox"] { - cursor: pointer; - position: absolute; - width: 1.5em; - height: 1.5em; - opacity: 0; + cursor: pointer; + position: absolute; + width: 1.5em; + height: 1.5em; + opacity: 0; } .tsd-filter-input input[type="checkbox"]:disabled { - pointer-events: none; + pointer-events: none; } .tsd-filter-input svg { - cursor: pointer; - width: 1.5em; - height: 1.5em; - margin-right: 0.5em; - border-radius: 0.33em; - /* Leaving this at full opacity breaks event listeners on Firefox. + cursor: pointer; + width: 1.5em; + height: 1.5em; + margin-right: 0.5em; + border-radius: 0.33em; + /* Leaving this at full opacity breaks event listeners on Firefox. Don't remove unless you know what you're doing. */ - opacity: 0.99; + opacity: 0.99; } -.tsd-filter-input input[type="checkbox"]:focus + svg { - transform: scale(0.95); -} -.tsd-filter-input input[type="checkbox"]:focus:not(:focus-visible) + svg { - transform: scale(1); +.tsd-filter-input input[type="checkbox"]:focus-visible + svg { + outline: 2px solid var(--color-focus-outline); } .tsd-checkbox-background { - fill: var(--color-accent); + fill: var(--color-accent); } input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { - stroke: var(--color-text); + stroke: var(--color-text); } .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { - fill: var(--color-background); - stroke: var(--color-accent); - stroke-width: 0.25rem; + fill: var(--color-background); + stroke: var(--color-accent); + stroke-width: 0.25rem; } .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { - stroke: var(--color-accent); + stroke: var(--color-accent); +} + +.settings-label { + font-weight: bold; + text-transform: uppercase; + display: inline-block; } -.tsd-theme-toggle { - padding-top: 0.75rem; +.tsd-filter-visibility .settings-label { + margin: 0.75rem 0 0.5rem 0; } -.tsd-theme-toggle > h4 { - display: inline; - vertical-align: middle; - margin-right: 0.75rem; + +.tsd-theme-toggle .settings-label { + margin: 0.75rem 0.75rem 0 0; } .tsd-hierarchy { - list-style: square; - margin: 0; + list-style: square; + margin: 0; } .tsd-hierarchy .target { - font-weight: bold; + font-weight: bold; } .tsd-full-hierarchy:not(:last-child) { - margin-bottom: 1em; - padding-bottom: 1em; - border-bottom: 1px solid var(--color-accent); + margin-bottom: 1em; + padding-bottom: 1em; + border-bottom: 1px solid var(--color-accent); } .tsd-full-hierarchy, .tsd-full-hierarchy ul { - list-style: none; - margin: 0; - padding: 0; + list-style: none; + margin: 0; + padding: 0; } .tsd-full-hierarchy ul { - padding-left: 1.5rem; + padding-left: 1.5rem; } .tsd-full-hierarchy a { - padding: 0.25rem 0 !important; - font-size: 1rem; - display: inline-flex; - align-items: center; - color: var(--color-text); + padding: 0.25rem 0 !important; + font-size: 1rem; + display: inline-flex; + align-items: center; + color: var(--color-text); } .tsd-panel-group.tsd-index-group { - margin-bottom: 0; + margin-bottom: 0; } .tsd-index-panel .tsd-index-list { - list-style: none; - line-height: 1.333em; - margin: 0; - padding: 0.25rem 0 0 0; - overflow: hidden; - display: grid; - grid-template-columns: repeat(3, 1fr); - column-gap: 1rem; - grid-template-rows: auto; + list-style: none; + line-height: 1.333em; + margin: 0; + padding: 0.25rem 0 0 0; + overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + column-gap: 1rem; + grid-template-rows: auto; } @media (max-width: 1024px) { - .tsd-index-panel .tsd-index-list { - grid-template-columns: repeat(2, 1fr); - } + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(2, 1fr); + } } @media (max-width: 768px) { - .tsd-index-panel .tsd-index-list { - grid-template-columns: repeat(1, 1fr); - } + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(1, 1fr); + } } .tsd-index-panel .tsd-index-list li { - -webkit-page-break-inside: avoid; - -moz-page-break-inside: avoid; - -ms-page-break-inside: avoid; - -o-page-break-inside: avoid; - page-break-inside: avoid; + -webkit-page-break-inside: avoid; + -moz-page-break-inside: avoid; + -ms-page-break-inside: avoid; + -o-page-break-inside: avoid; + page-break-inside: avoid; } .tsd-flag { - display: inline-block; - padding: 0.25em 0.4em; - border-radius: 4px; - color: var(--color-comment-tag-text); - background-color: var(--color-comment-tag); - text-indent: 0; - font-size: 75%; - line-height: 1; - font-weight: normal; + display: inline-block; + padding: 0.25em 0.4em; + border-radius: 4px; + color: var(--color-comment-tag-text); + background-color: var(--color-comment-tag); + text-indent: 0; + font-size: 75%; + line-height: 1; + font-weight: normal; } .tsd-anchor { - position: relative; - top: -100px; + position: relative; + top: -100px; } .tsd-member { - position: relative; + position: relative; } .tsd-member .tsd-anchor + h3 { - display: flex; - align-items: center; - margin-top: 0; - margin-bottom: 0; - border-bottom: none; + display: flex; + align-items: center; + margin-top: 0; + margin-bottom: 0; + border-bottom: none; } .tsd-navigation.settings { - margin: 1rem 0; + margin: 1rem 0; } .tsd-navigation > a, .tsd-navigation .tsd-accordion-summary { - width: calc(100% - 0.25rem); - display: flex; - align-items: center; + width: calc(100% - 0.25rem); + display: flex; + align-items: center; } .tsd-navigation a, .tsd-navigation summary > span, .tsd-page-navigation a { - display: flex; - width: calc(100% - 0.25rem); - align-items: center; - padding: 0.25rem; - color: var(--color-text); - text-decoration: none; - box-sizing: border-box; + display: flex; + width: calc(100% - 0.25rem); + align-items: center; + padding: 0.25rem; + color: var(--color-text); + text-decoration: none; + box-sizing: border-box; } .tsd-navigation a.current, .tsd-page-navigation a.current { - background: var(--color-active-menu-item); + background: var(--color-active-menu-item); } .tsd-navigation a:hover, .tsd-page-navigation a:hover { - text-decoration: underline; + text-decoration: underline; } .tsd-navigation ul, .tsd-page-navigation ul { - margin-top: 0; - margin-bottom: 0; - padding: 0; - list-style: none; + margin-top: 0; + margin-bottom: 0; + padding: 0; + list-style: none; } .tsd-navigation li, .tsd-page-navigation li { - padding: 0; - max-width: 100%; + padding: 0; + max-width: 100%; +} +.tsd-navigation .tsd-nav-link { + display: none; } .tsd-nested-navigation { - margin-left: 3rem; + margin-left: 3rem; } .tsd-nested-navigation > li > details { - margin-left: -1.5rem; + margin-left: -1.5rem; } .tsd-small-nested-navigation { - margin-left: 1.5rem; + margin-left: 1.5rem; } .tsd-small-nested-navigation > li > details { - margin-left: -1.5rem; + margin-left: -1.5rem; } +.tsd-page-navigation-section { + margin-left: 10px; +} +.tsd-page-navigation-section > summary { + padding: 0.25rem; +} +.tsd-page-navigation-section > div { + margin-left: 20px; +} .tsd-page-navigation ul { - padding-left: 1.75rem; + padding-left: 1.75rem; } #tsd-sidebar-links a { - margin-top: 0; - margin-bottom: 0.5rem; - line-height: 1.25rem; + margin-top: 0; + margin-bottom: 0.5rem; + line-height: 1.25rem; } #tsd-sidebar-links a:last-of-type { - margin-bottom: 0; + margin-bottom: 0; } a.tsd-index-link { - padding: 0.25rem 0 !important; - font-size: 1rem; - line-height: 1.25rem; - display: inline-flex; - align-items: center; - color: var(--color-text); + padding: 0.25rem 0 !important; + font-size: 1rem; + line-height: 1.25rem; + display: inline-flex; + align-items: center; + color: var(--color-text); } .tsd-accordion-summary { - list-style-type: none; /* hide marker on non-safari */ - outline: none; /* broken on safari, so just hide it */ + list-style-type: none; /* hide marker on non-safari */ + outline: none; /* broken on safari, so just hide it */ } .tsd-accordion-summary::-webkit-details-marker { - display: none; /* hide marker on safari */ + display: none; /* hide marker on safari */ } .tsd-accordion-summary, .tsd-accordion-summary a { - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; - cursor: pointer; + cursor: pointer; } .tsd-accordion-summary a { - width: calc(100% - 1.5rem); + width: calc(100% - 1.5rem); } .tsd-accordion-summary > * { - margin-top: 0; - margin-bottom: 0; - padding-top: 0; - padding-bottom: 0; + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; } -.tsd-index-accordion .tsd-accordion-summary > svg { - margin-left: 0.25rem; +.tsd-accordion .tsd-accordion-summary > svg { + margin-left: 0.25rem; + vertical-align: text-top; } .tsd-index-content > :not(:first-child) { - margin-top: 0.75rem; + margin-top: 0.75rem; } .tsd-index-heading { - margin-top: 1.5rem; - margin-bottom: 0.75rem; + margin-top: 1.5rem; + margin-bottom: 0.75rem; } .tsd-kind-icon { - margin-right: 0.5rem; - width: 1.25rem; - height: 1.25rem; - min-width: 1.25rem; - min-height: 1.25rem; + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; + min-width: 1.25rem; + min-height: 1.25rem; } .tsd-kind-icon path { - transform-origin: center; - transform: scale(1.1); + transform-origin: center; + transform: scale(1.1); } .tsd-signature > .tsd-kind-icon { - margin-right: 0.8rem; + margin-right: 0.8rem; } .tsd-panel { - margin-bottom: 2.5rem; + margin-bottom: 2.5rem; } .tsd-panel.tsd-member { - margin-bottom: 4rem; + margin-bottom: 4rem; } .tsd-panel:empty { - display: none; + display: none; } .tsd-panel > h1, .tsd-panel > h2, .tsd-panel > h3 { - margin: 1.5rem -1.5rem 0.75rem -1.5rem; - padding: 0 1.5rem 0.75rem 1.5rem; + margin: 1.5rem -1.5rem 0.75rem -1.5rem; + padding: 0 1.5rem 0.75rem 1.5rem; } .tsd-panel > h1.tsd-before-signature, .tsd-panel > h2.tsd-before-signature, .tsd-panel > h3.tsd-before-signature { - margin-bottom: 0; - border-bottom: none; + margin-bottom: 0; + border-bottom: none; } .tsd-panel-group { - margin: 4rem 0; + margin: 2rem 0; } .tsd-panel-group.tsd-index-group { - margin: 2rem 0; + margin: 2rem 0; } .tsd-panel-group.tsd-index-group details { - margin: 2rem 0; + margin: 2rem 0; +} +.tsd-panel-group > .tsd-accordion-summary { + margin-bottom: 1rem; } #tsd-search { - transition: background-color 0.2s; + transition: background-color 0.2s; } #tsd-search .title { - position: relative; - z-index: 2; + position: relative; + z-index: 2; } #tsd-search .field { - position: absolute; - left: 0; - top: 0; - right: 2.5rem; - height: 100%; + position: absolute; + left: 0; + top: 0; + right: 2.5rem; + height: 100%; } #tsd-search .field input { - box-sizing: border-box; - position: relative; - top: -50px; - z-index: 1; - width: 100%; - padding: 0 10px; - opacity: 0; - outline: 0; - border: 0; - background: transparent; - color: var(--color-text); + box-sizing: border-box; + position: relative; + top: -50px; + z-index: 1; + width: 100%; + padding: 0 10px; + opacity: 0; + outline: 0; + border: 0; + background: transparent; + color: var(--color-text); } #tsd-search .field label { - position: absolute; - overflow: hidden; - right: -40px; + position: absolute; + overflow: hidden; + right: -40px; } #tsd-search .field input, #tsd-search .title, #tsd-toolbar-links a { - transition: opacity 0.2s; + transition: opacity 0.2s; } #tsd-search .results { - position: absolute; - visibility: hidden; - top: 40px; - width: 100%; - margin: 0; - padding: 0; - list-style: none; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); + position: absolute; + visibility: hidden; + top: 40px; + width: 100%; + margin: 0; + padding: 0; + list-style: none; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); } #tsd-search .results li { - background-color: var(--color-background); - line-height: initial; - padding: 4px; + background-color: var(--color-background); + line-height: initial; + padding: 4px; } #tsd-search .results li:nth-child(even) { - background-color: var(--color-background-secondary); + background-color: var(--color-background-secondary); } #tsd-search .results li.state { - display: none; + display: none; } #tsd-search .results li.current:not(.no-results), #tsd-search .results li:hover:not(.no-results) { - background-color: var(--color-accent); + background-color: var(--color-accent); } #tsd-search .results a { - display: flex; - align-items: center; - padding: 0.25rem; - box-sizing: border-box; + display: flex; + align-items: center; + padding: 0.25rem; + box-sizing: border-box; } #tsd-search .results a:before { - top: 10px; + top: 10px; } #tsd-search .results span.parent { - color: var(--color-text-aside); - font-weight: normal; + color: var(--color-text-aside); + font-weight: normal; } #tsd-search.has-focus { - background-color: var(--color-accent); + background-color: var(--color-accent); } #tsd-search.has-focus .field input { - top: 0; - opacity: 1; + top: 0; + opacity: 1; } #tsd-search.has-focus .title, #tsd-search.has-focus #tsd-toolbar-links a { - z-index: 0; - opacity: 0; + z-index: 0; + opacity: 0; } #tsd-search.has-focus .results { - visibility: visible; + visibility: visible; } #tsd-search.loading .results li.state.loading { - display: block; + display: block; } #tsd-search.failure .results li.state.failure { - display: block; + display: block; } #tsd-toolbar-links { - position: absolute; - top: 0; - right: 2rem; - height: 100%; - display: flex; - align-items: center; - justify-content: flex-end; + position: absolute; + top: 0; + right: 2rem; + height: 100%; + display: flex; + align-items: center; + justify-content: flex-end; } #tsd-toolbar-links a { - margin-left: 1.5rem; + margin-left: 1.5rem; } #tsd-toolbar-links a:hover { - text-decoration: underline; + text-decoration: underline; } .tsd-signature { - margin: 0 0 1rem 0; - padding: 1rem 0.5rem; - border: 1px solid var(--color-accent); - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - font-size: 14px; - overflow-x: auto; + margin: 0 0 1rem 0; + padding: 1rem 0.5rem; + border: 1px solid var(--color-accent); + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 14px; + overflow-x: auto; } .tsd-signature-keyword { - color: var(--color-ts-keyword); - font-weight: normal; + color: var(--color-ts-keyword); + font-weight: normal; } .tsd-signature-symbol { - color: var(--color-text-aside); - font-weight: normal; + color: var(--color-text-aside); + font-weight: normal; } .tsd-signature-type { - font-style: italic; - font-weight: normal; + font-style: italic; + font-weight: normal; } .tsd-signatures { - padding: 0; - margin: 0 0 1em 0; - list-style-type: none; + padding: 0; + margin: 0 0 1em 0; + list-style-type: none; } .tsd-signatures .tsd-signature { - margin: 0; - border-color: var(--color-accent); - border-width: 1px 0; - transition: background-color 0.1s; + margin: 0; + border-color: var(--color-accent); + border-width: 1px 0; + transition: background-color 0.1s; +} +.tsd-signatures .tsd-index-signature:not(:last-child) { + margin-bottom: 1em; +} +.tsd-signatures .tsd-index-signature .tsd-signature { + border-width: 1px; } .tsd-description .tsd-signatures .tsd-signature { - border-width: 1px; + border-width: 1px; } ul.tsd-parameter-list, ul.tsd-type-parameter-list { - list-style: square; - margin: 0; - padding-left: 20px; + list-style: square; + margin: 0; + padding-left: 20px; } ul.tsd-parameter-list > li.tsd-parameter-signature, ul.tsd-type-parameter-list > li.tsd-parameter-signature { - list-style: none; - margin-left: -20px; + list-style: none; + margin-left: -20px; } ul.tsd-parameter-list h5, ul.tsd-type-parameter-list h5 { - font-size: 16px; - margin: 1em 0 0.5em 0; + font-size: 16px; + margin: 1em 0 0.5em 0; } .tsd-sources { - margin-top: 1rem; - font-size: 0.875em; + margin-top: 1rem; + font-size: 0.875em; } .tsd-sources a { - color: var(--color-text-aside); - text-decoration: underline; + color: var(--color-text-aside); + text-decoration: underline; } .tsd-sources ul { - list-style: none; - padding: 0; + list-style: none; + padding: 0; } .tsd-page-toolbar { - position: sticky; - z-index: 1; - top: 0; - left: 0; - width: 100%; - color: var(--color-text); - background: var(--color-background-secondary); - border-bottom: 1px var(--color-accent) solid; - transition: transform 0.3s ease-in-out; + position: sticky; + z-index: 1; + top: 0; + left: 0; + width: 100%; + color: var(--color-text); + background: var(--color-background-secondary); + border-bottom: 1px var(--color-accent) solid; + transition: transform 0.3s ease-in-out; } .tsd-page-toolbar a { - color: var(--color-text); - text-decoration: none; + color: var(--color-text); + text-decoration: none; } .tsd-page-toolbar a.title { - font-weight: bold; + font-weight: bold; } .tsd-page-toolbar a.title:hover { - text-decoration: underline; + text-decoration: underline; } .tsd-page-toolbar .tsd-toolbar-contents { - display: flex; - justify-content: space-between; - height: 2.5rem; - margin: 0 auto; + display: flex; + justify-content: space-between; + height: 2.5rem; + margin: 0 auto; } .tsd-page-toolbar .table-cell { - position: relative; - white-space: nowrap; - line-height: 40px; + position: relative; + white-space: nowrap; + line-height: 40px; } .tsd-page-toolbar .table-cell:first-child { - width: 100%; + width: 100%; } .tsd-page-toolbar .tsd-toolbar-icon { - box-sizing: border-box; - line-height: 0; - padding: 12px 0; + box-sizing: border-box; + line-height: 0; + padding: 12px 0; } .tsd-widget { - display: inline-block; - overflow: hidden; - opacity: 0.8; - height: 40px; - transition: - opacity 0.1s, - background-color 0.2s; - vertical-align: bottom; - cursor: pointer; + display: inline-block; + overflow: hidden; + opacity: 0.8; + height: 40px; + transition: + opacity 0.1s, + background-color 0.2s; + vertical-align: bottom; + cursor: pointer; } .tsd-widget:hover { - opacity: 0.9; + opacity: 0.9; } .tsd-widget.active { - opacity: 1; - background-color: var(--color-accent); + opacity: 1; + background-color: var(--color-accent); } .tsd-widget.no-caption { - width: 40px; + width: 40px; } .tsd-widget.no-caption:before { - margin: 0; + margin: 0; } .tsd-widget.options, .tsd-widget.menu { - display: none; + display: none; } input[type="checkbox"] + .tsd-widget:before { - background-position: -120px 0; + background-position: -120px 0; } input[type="checkbox"]:checked + .tsd-widget:before { - background-position: -160px 0; + background-position: -160px 0; } img { - max-width: 100%; + max-width: 100%; } .tsd-anchor-icon { - display: inline-flex; - align-items: center; - margin-left: 0.5rem; - vertical-align: middle; - color: var(--color-text); + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + vertical-align: middle; + color: var(--color-text); } .tsd-anchor-icon svg { - width: 1em; - height: 1em; - visibility: hidden; + width: 1em; + height: 1em; + visibility: hidden; } .tsd-anchor-link:hover > .tsd-anchor-icon svg { - visibility: visible; + visibility: visible; } .deprecated { - text-decoration: line-through !important; + text-decoration: line-through !important; } .warning { - padding: 1rem; - color: var(--color-warning-text); - background: var(--color-background-warning); + padding: 1rem; + color: var(--color-warning-text); + background: var(--color-background-warning); } .tsd-kind-project { - color: var(--color-ts-project); + color: var(--color-ts-project); } .tsd-kind-module { - color: var(--color-ts-module); + color: var(--color-ts-module); } .tsd-kind-namespace { - color: var(--color-ts-namespace); + color: var(--color-ts-namespace); } .tsd-kind-enum { - color: var(--color-ts-enum); + color: var(--color-ts-enum); } .tsd-kind-enum-member { - color: var(--color-ts-enum-member); + color: var(--color-ts-enum-member); } .tsd-kind-variable { - color: var(--color-ts-variable); + color: var(--color-ts-variable); } .tsd-kind-function { - color: var(--color-ts-function); + color: var(--color-ts-function); } .tsd-kind-class { - color: var(--color-ts-class); + color: var(--color-ts-class); } .tsd-kind-interface { - color: var(--color-ts-interface); + color: var(--color-ts-interface); } .tsd-kind-constructor { - color: var(--color-ts-constructor); + color: var(--color-ts-constructor); } .tsd-kind-property { - color: var(--color-ts-property); + color: var(--color-ts-property); } .tsd-kind-method { - color: var(--color-ts-method); + color: var(--color-ts-method); } .tsd-kind-call-signature { - color: var(--color-ts-call-signature); + color: var(--color-ts-call-signature); } .tsd-kind-index-signature { - color: var(--color-ts-index-signature); + color: var(--color-ts-index-signature); } .tsd-kind-constructor-signature { - color: var(--color-ts-constructor-signature); + color: var(--color-ts-constructor-signature); } .tsd-kind-parameter { - color: var(--color-ts-parameter); + color: var(--color-ts-parameter); } .tsd-kind-type-literal { - color: var(--color-ts-type-literal); + color: var(--color-ts-type-literal); } .tsd-kind-type-parameter { - color: var(--color-ts-type-parameter); + color: var(--color-ts-type-parameter); } .tsd-kind-accessor { - color: var(--color-ts-accessor); + color: var(--color-ts-accessor); } .tsd-kind-get-signature { - color: var(--color-ts-get-signature); + color: var(--color-ts-get-signature); } .tsd-kind-set-signature { - color: var(--color-ts-set-signature); + color: var(--color-ts-set-signature); } .tsd-kind-type-alias { - color: var(--color-ts-type-alias); + color: var(--color-ts-type-alias); } /* if we have a kind icon, don't color the text by kind */ .tsd-kind-icon ~ span { - color: var(--color-text); + color: var(--color-text); } * { - scrollbar-width: thin; - scrollbar-color: var(--color-accent) var(--color-icon-background); + scrollbar-width: thin; + scrollbar-color: var(--color-accent) var(--color-icon-background); } *::-webkit-scrollbar { - width: 0.75rem; + width: 0.75rem; } *::-webkit-scrollbar-track { - background: var(--color-icon-background); + background: var(--color-icon-background); } *::-webkit-scrollbar-thumb { - background-color: var(--color-accent); - border-radius: 999rem; - border: 0.25rem solid var(--color-icon-background); + background-color: var(--color-accent); + border-radius: 999rem; + border: 0.25rem solid var(--color-icon-background); } /* mobile */ @media (max-width: 769px) { - .tsd-widget.options, - .tsd-widget.menu { - display: inline-block; - } - - .container-main { - display: flex; - } - html .col-content { - float: none; - max-width: 100%; - width: 100%; - } - html .col-sidebar { - position: fixed !important; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - z-index: 1024; - top: 0 !important; - bottom: 0 !important; - left: auto !important; - right: 0 !important; - padding: 1.5rem 1.5rem 0 0; - width: 75vw; - visibility: hidden; - background-color: var(--color-background); - transform: translate(100%, 0); - } - html .col-sidebar > *:last-child { - padding-bottom: 20px; - } - html .overlay { - content: ""; - display: block; - position: fixed; - z-index: 1023; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.75); - visibility: hidden; - } - - .to-has-menu .overlay { - animation: fade-in 0.4s; - } - - .to-has-menu .col-sidebar { - animation: pop-in-from-right 0.4s; - } - - .from-has-menu .overlay { - animation: fade-out 0.4s; - } - - .from-has-menu .col-sidebar { - animation: pop-out-to-right 0.4s; - } - - .has-menu body { - overflow: hidden; - } - .has-menu .overlay { - visibility: visible; - } - .has-menu .col-sidebar { - visibility: visible; - transform: translate(0, 0); - display: flex; - flex-direction: column; - gap: 1.5rem; - max-height: 100vh; - padding: 1rem 2rem; - } - .has-menu .tsd-navigation { - max-height: 100%; - } + .tsd-widget.options, + .tsd-widget.menu { + display: inline-block; + } + + .container-main { + display: flex; + } + html .col-content { + float: none; + max-width: 100%; + width: 100%; + } + html .col-sidebar { + position: fixed !important; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 1024; + top: 0 !important; + bottom: 0 !important; + left: auto !important; + right: 0 !important; + padding: 1.5rem 1.5rem 0 0; + width: 75vw; + visibility: hidden; + background-color: var(--color-background); + transform: translate(100%, 0); + } + html .col-sidebar > *:last-child { + padding-bottom: 20px; + } + html .overlay { + content: ""; + display: block; + position: fixed; + z-index: 1023; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + visibility: hidden; + } + + .to-has-menu .overlay { + animation: fade-in 0.4s; + } + + .to-has-menu .col-sidebar { + animation: pop-in-from-right 0.4s; + } + + .from-has-menu .overlay { + animation: fade-out 0.4s; + } + + .from-has-menu .col-sidebar { + animation: pop-out-to-right 0.4s; + } + + .has-menu body { + overflow: hidden; + } + .has-menu .overlay { + visibility: visible; + } + .has-menu .col-sidebar { + visibility: visible; + transform: translate(0, 0); + display: flex; + flex-direction: column; + gap: 1.5rem; + max-height: 100vh; + padding: 1rem 2rem; + } + .has-menu .tsd-navigation { + max-height: 100%; + } + #tsd-toolbar-links { + display: none; + } + .tsd-navigation .tsd-nav-link { + display: flex; + } } /* one sidebar */ @media (min-width: 770px) { - .container-main { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); - grid-template-areas: "sidebar content"; - margin: 2rem auto; - } - - .col-sidebar { - grid-area: sidebar; - } - .col-content { - grid-area: content; - padding: 0 1rem; - } + .container-main { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); + grid-template-areas: "sidebar content"; + margin: 2rem auto; + } + + .col-sidebar { + grid-area: sidebar; + } + .col-content { + grid-area: content; + padding: 0 1rem; + } } @media (min-width: 770px) and (max-width: 1399px) { - .col-sidebar { - max-height: calc(100vh - 2rem - 42px); - overflow: auto; - position: sticky; - top: 42px; - padding-top: 1rem; - } - .site-menu { - margin-top: 1rem; - } + .col-sidebar { + max-height: calc(100vh - 2rem - 42px); + overflow: auto; + position: sticky; + top: 42px; + padding-top: 1rem; + } + .site-menu { + margin-top: 1rem; + } } /* two sidebars */ @media (min-width: 1200px) { - .container-main { - grid-template-columns: minmax(0, 1fr) minmax(0, 2.5fr) minmax(0, 20rem); - grid-template-areas: "sidebar content toc"; - } - - .col-sidebar { - display: contents; - } - - .page-menu { - grid-area: toc; - padding-left: 1rem; - } - .site-menu { - grid-area: sidebar; - } - - .site-menu { - margin-top: 1rem 0; - } - - .page-menu, - .site-menu { - max-height: calc(100vh - 2rem - 42px); - overflow: auto; - position: sticky; - top: 42px; - } + .container-main { + grid-template-columns: minmax(0, 1fr) minmax(0, 2.5fr) minmax(0, 20rem); + grid-template-areas: "sidebar content toc"; + } + + .col-sidebar { + display: contents; + } + + .page-menu { + grid-area: toc; + padding-left: 1rem; + } + .site-menu { + grid-area: sidebar; + } + + .site-menu { + margin-top: 1rem 0; + } + + .page-menu, + .site-menu { + max-height: calc(100vh - 2rem - 42px); + overflow: auto; + position: sticky; + top: 42px; + } } diff --git a/docs/classes/Box.html b/docs/classes/Box.html index 909efc5a..71d7c825 100644 --- a/docs/classes/Box.html +++ b/docs/classes/Box.html @@ -1,4381 +1,121 @@ - - - - - - Box | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class Box

-
-
-

collider - box

-
-
-
-

- Hierarchy (view full) -

- -
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - - -
-
-
-

Properties

-
- - -
- _group: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- _height: - number -
-

inner height

-
- -
-
- - -
- _width: - number -
-

inner width

-
- -
-
- - -
- angle: - number -
-
-

body angle in radians use deg2rad to convert

-
-
- -
-
- - -
- bbox: - BBox -
-
-

bounding box cache, without padding

-
-
- -
-
- - -
- calcPoints: - SATVector[] -
- -
-
- - -
- centered: - boolean = false -
-
-

is body centered

-
-
- -
-
- - -
- convexPolygons: - SATPolygon[] -
-
-

optimization for convex polygons

-
-
- -
-
- - -
- dirty: - boolean = false -
-
-

- was the polygon modified and needs update in the next - checkCollision -

-
-
- -
-
- - -
- edges: - SATVector[] -
- -
-
- - -
- isConvex: - true = true -
-
-

boxes are convex

-
-
- -
-
- - -
- isStatic: - boolean -
-
-

static bodies don't move but they collide

-
-
- -
-
- - -
- isTrigger: - boolean -
-
-

trigger bodies move but are like ghosts

-
-
- -
-
- - -
- maxX: - number -
-
-

maximum x bound of body

-
-
- -
-
- - -
- maxY: - number -
-
-

maximum y bound of body

-
-
- -
-
- - -
- minX: - number -
-
-

minimum x bound of body

-
-
- -
-
- - -
- minY: - number -
-
-

minimum y bound of body

-
-
- -
-
- - -
- normals: - SATVector[] -
- -
-
- - -
- offset: - SATVector -
-
-

each body may have offset from center

-
-
- -
-
- - -
- padding: - number -
-
-

- bodies are not reinserted during update if their bbox didnt move - outside bbox + padding -

-
-
- -
-
- - -
- points: - SATVector[] -
- -
-
- - -
- pointsBackup: - Vector[] -
-
-

backup of points used for scaling

-
-
- -
-
- - -
- pos: - SATVector -
- -
-
- - -
- scaleVector: - Vector = ... -
-
-

scale Vector of body

-
-
- -
-
- - -
- system?: - System<Body> -
-
-

reference to collision system

-
-
- -
-
- - -
- type: - Box | Point = BodyType.Box -
-

type of body

-
- -
-
- - -
- typeGroup: - Box | Point = BodyGroup.Box -
-
-

faster than type

-
-
- -
-
-
-

Accessors

-
- - -
    -
  • - get group(): number -
  • -
  • -
    -

    group for collision filtering

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set group(group): void -
  • -
  • -
    -

    group for collision filtering

    -
    -
    -

    Parameters

    -
      -
    • - group: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get height(): number -
  • -
  • -
    -

    get box height

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set height(height): void -
  • -
  • -
    -

    set box height, update points

    -
    -
    -

    Parameters

    -
      -
    • - height: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get isCentered(): boolean -
  • -
  • -
    -

    is polygon centered?

    -
    -

    - Returns boolean -

    -
    - -
  • -
  • - set isCentered(isCentered): void -
  • -
  • -
    -

    flag to set is polygon centered

    -
    -
    -

    Parameters

    -
      -
    • - isCentered: - boolean -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scale(): number -
  • -
  • -
    -

    allow approx getting of scale

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set scale(scale): void -
  • -
  • -
    -

    allow easier setting of scale

    -
    -
    -

    Parameters

    -
      -
    • - scale: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleX(): number -
  • -
  • -
    -

    - allow exact getting of scale x - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleY(): number -
  • -
  • -
    -

    - allow exact getting of scale y - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get width(): number -
  • -
  • -
    -

    get box width

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set width(width): void -
  • -
  • -
    -

    set box width, update points

    -
    -
    -

    Parameters

    -
      -
    • - width: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get x(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set x(x): void -
  • -
  • -
    -

    updating this.pos.x by this.x = x updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get y(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set y(y): void -
  • -
  • -
    -

    updating this.pos.y by this.y = y updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - y: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
-

Methods

-
- - - -
-
- - -
    - -
  • -
    -

    Draws exact collider on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Draws Bounding Box on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - - -
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - if true, polygon is not an invalid, self-crossing polygon -

    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    update instantly or mark as dirty

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean - = false -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - inner function for after position change update aabb in - system and convex inner polygons -

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean = ... -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
-
- -
-
-

- Generated using - TypeDoc -

-
-
- - +Box | Detect-Collisions

collider - box

+

Hierarchy (view full)

Constructors

Properties

_group: number

group for collision filtering

+
_height: number

inner height

+
_width: number

inner width

+
angle: number

body angle in radians use deg2rad to convert

+
bbox: BBox

bounding box cache, without padding

+
calcPoints: SATVector[]
centered: boolean = false

is body centered

+
convexPolygons: SATPolygon[]

optimization for convex polygons

+
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

+
edges: SATVector[]
isConvex: true = true

boxes are convex

+
isStatic: boolean

static bodies don't move but they collide

+
isTrigger: boolean

trigger bodies move but are like ghosts

+
maxX: number

maximum x bound of body

+
maxY: number

maximum y bound of body

+
minX: number

minimum x bound of body

+
minY: number

minimum y bound of body

+
normals: SATVector[]
offset: SATVector

each body may have offset from center

+
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

+
points: SATVector[]
pointsBackup: Vector[]

backup of points used for scaling

+
scaleVector: Vector = ...

scale Vector of body

+
system?: System<Body>

reference to collision system

+
type: Box | Point = BodyType.Box

type of body

+
typeGroup: Box | Point = BodyGroup.Box

faster than type

+

Accessors

  • get group(): number
  • group for collision filtering

    +

    Returns number

  • set group(group): void
  • group for collision filtering

    +

    Parameters

    • group: number

    Returns void

  • get height(): number
  • get box height

    +

    Returns number

  • set height(height): void
  • set box height, update points

    +

    Parameters

    • height: number

    Returns void

  • get isCentered(): boolean
  • is polygon centered?

    +

    Returns boolean

  • set isCentered(isCentered): void
  • flag to set is polygon centered

    +

    Parameters

    • isCentered: boolean

    Returns void

  • get scale(): number
  • allow approx getting of scale

    +

    Returns number

  • set scale(scale): void
  • allow easier setting of scale

    +

    Parameters

    • scale: number

    Returns void

  • get scaleX(): number
  • allow exact getting of scale x - use setScale(x, y) to set

    +

    Returns number

  • get scaleY(): number
  • allow exact getting of scale y - use setScale(x, y) to set

    +

    Returns number

Methods

  • inner function for after position change update aabb in system and convex inner polygons

    +

    Parameters

    • updateNow: boolean = ...

    Returns void

diff --git a/docs/classes/Circle.html b/docs/classes/Circle.html index 13e4b247..33832e63 100644 --- a/docs/classes/Circle.html +++ b/docs/classes/Circle.html @@ -1,2798 +1,82 @@ - - - - - - Circle | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class Circle

-
-
-

collider - circle

-
-
-
-

- Hierarchy (view full) -

- -
-
-

Implements

- -
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - - -
-
-
-

Properties

-
- - -
- _group: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- angle: - number -
-
-

for compatibility reasons circle has angle

-
-
- -
-
- - -
- bbox: - BBox -
-
-

bounding box cache, without padding

-
-
- -
-
- - -
- dirty: - boolean = false -
-
-

- was the polygon modified and needs update in the next - checkCollision -

-
-
- -
-
- - -
- isCentered: - true = true -
-

always centered

-
- -
-
- - -
- isConvex: - true = true -
-
-

flag to show is it a convex body or non convex polygon

-
-
- -
-
- - -
- isStatic: - boolean -
-
-

static bodies don't move but they collide

-
-
- -
-
- - -
- isTrigger: - boolean -
-
-

trigger bodies move but are like ghosts

-
-
- -
-
- - -
- maxX: - number -
-
-

maximum x bound of body

-
-
- -
-
- - -
- maxY: - number -
-
-

maximum y bound of body

-
-
- -
-
- - -
- minX: - number -
-
-

minimum x bound of body

-
-
- -
-
- - -
- minY: - number -
-
-

minimum y bound of body

-
-
- -
-
- - -
- offset: - SATVector -
-

offset

-
- -
-
- - -
- offsetCopy: - Vector = ... -
-
-

offset copy without angle applied

-
-
- -
-
- - -
- padding: - number -
-
-

- bodies are not reinserted during update if their bbox didnt move - outside bbox + padding -

-
-
- -
-
- - -
- pos: - SATVector -
- -
-
- - -
- r: - number -
- -
-
- - -
- system?: - System<Body> -
-
-

reference to collision system

-
-
- -
-
- - -
- type: - Circle = BodyType.Circle -
-

circle type

-
- -
-
- - -
- typeGroup: - Circle = BodyGroup.Circle -
-
-

faster than type

-
-
- -
-
- - -
- unscaledRadius: - number -
-
-

saved initial radius - internal

-
-
- -
-
-
-

Accessors

-
- - -
    -
  • - get group(): number -
  • -
  • -
    -

    group for collision filtering

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set group(group): void -
  • -
  • -
    -

    group for collision filtering

    -
    -
    -

    Parameters

    -
      -
    • - group: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scale(): number -
  • -
  • -
    -

    allow get scale

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set scale(scale): void -
  • -
  • -
    -

    shorthand for setScale()

    -
    -
    -

    Parameters

    -
      -
    • - scale: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleX(): number -
  • -
  • -
    -

    scaleX = scale in case of Circles

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleY(): number -
  • -
  • -
    -

    scaleY = scale in case of Circles

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get x(): number -
  • -
  • -
    -

    get this.pos.x

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set x(x): void -
  • -
  • -
    -

    updating this.pos.x by this.x = x updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get y(): number -
  • -
  • -
    -

    get this.pos.y

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set y(y): void -
  • -
  • -
    -

    updating this.pos.y by this.y = y updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - y: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
-

Methods

-
- - -
    - -
  • -
    -

    - Draws collider on a CanvasRenderingContext2D's current - path -

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Draws Bounding Box on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    update instantly or mark as dirty

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean - = false -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    update scale

    -
    -
    -

    Parameters

    -
      -
    • - scaleX: - number -
    • -
    • - _scaleY: - number - = scaleX -
    • -
    • - update: - boolean = true -
    • -
    -
    -

    - Returns - Circle -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - inner function for after position change update aabb in - system -

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean = ... -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- -
-
-

- Generated using - TypeDoc -

-
-
- - +Circle | Detect-Collisions

collider - circle

+

Hierarchy (view full)

Implements

Constructors

Properties

_group: number

group for collision filtering

+
angle: number

for compatibility reasons circle has angle

+
bbox: BBox

bounding box cache, without padding

+
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

+
isCentered: true = true

always centered

+
isConvex: true = true

flag to show is it a convex body or non convex polygon

+
isStatic: boolean

static bodies don't move but they collide

+
isTrigger: boolean

trigger bodies move but are like ghosts

+
maxX: number

maximum x bound of body

+
maxY: number

maximum y bound of body

+
minX: number

minimum x bound of body

+
minY: number

minimum y bound of body

+
offset: SATVector

offset

+
offsetCopy: Vector = ...

offset copy without angle applied

+
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

+
r: number
system?: System<Body>

reference to collision system

+
type: Circle = BodyType.Circle

circle type

+
typeGroup: Circle = BodyGroup.Circle

faster than type

+
unscaledRadius: number

saved initial radius - internal

+

Accessors

  • get scaleX(): number
  • scaleX = scale in case of Circles

    +

    Returns number

  • get scaleY(): number
  • scaleY = scale in case of Circles

    +

    Returns number

Methods

  • Draws collider on a CanvasRenderingContext2D's current path

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • update instantly or mark as dirty

    +

    Parameters

    • updateNow: boolean = false

    Returns void

  • inner function for after position change update aabb in system

    +

    Parameters

    • updateNow: boolean = ...

    Returns void

diff --git a/docs/classes/Ellipse.html b/docs/classes/Ellipse.html index e7c19919..6629cc7b 100644 --- a/docs/classes/Ellipse.html +++ b/docs/classes/Ellipse.html @@ -1,4502 +1,123 @@ - - - - - - Ellipse | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class Ellipse

-
-
-
-

collider - ellipse

-
-
-
-
-

- Hierarchy (view full) -

- -
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - - -
-
-
-

Properties

-
- - -
- _group: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- _radiusX: - number -
-
-

inner initial params save

-
-
- -
-
- - -
- _radiusY: - number -
- -
-
- - -
- _step: - number -
- -
-
- - -
- angle: - number -
-
-

body angle in radians use deg2rad to convert

-
-
- -
-
- - -
- bbox: - BBox -
-
-

bounding box cache, without padding

-
-
- -
-
- - -
- calcPoints: - SATVector[] -
- -
-
- - -
- centered: - boolean = false -
-
-

is body centered

-
-
- -
-
- - -
- convexPolygons: - SATPolygon[] -
-
-

optimization for convex polygons

-
-
- -
-
- - -
- dirty: - boolean = false -
-
-

- was the polygon modified and needs update in the next - checkCollision -

-
-
- -
-
- - -
- edges: - SATVector[] -
- -
-
- - -
- isConvex: - true = true -
-
-

ellipses are convex

-
-
- -
-
- - -
- isStatic: - boolean -
-
-

static bodies don't move but they collide

-
-
- -
-
- - -
- isTrigger: - boolean -
-
-

trigger bodies move but are like ghosts

-
-
- -
-
- - -
- maxX: - number -
-
-

maximum x bound of body

-
-
- -
-
- - -
- maxY: - number -
-
-

maximum y bound of body

-
-
- -
-
- - -
- minX: - number -
-
-

minimum x bound of body

-
-
- -
-
- - -
- minY: - number -
-
-

minimum y bound of body

-
-
- -
-
- - -
- normals: - SATVector[] -
- -
-
- - -
- offset: - SATVector -
-
-

each body may have offset from center

-
-
- -
-
- - -
- padding: - number -
-
-

- bodies are not reinserted during update if their bbox didnt move - outside bbox + padding -

-
-
- -
-
- - -
- points: - SATVector[] -
- -
-
- - -
- pointsBackup: - Vector[] -
-
-

backup of points used for scaling

-
-
- -
-
- - -
- pos: - SATVector -
- -
-
- - -
- scaleVector: - Vector = ... -
-
-

scale Vector of body

-
-
- -
-
- - -
- system?: - System<Body> -
-
-

reference to collision system

-
-
- -
-
- - -
- type: - Ellipse = BodyType.Ellipse -
-

ellipse type

-
- -
-
- - -
- typeGroup: - Ellipse = BodyGroup.Ellipse -
-
-

faster than type

-
-
- -
-
-
-

Accessors

-
- - -
    -
  • - get group(): number -
  • -
  • -
    -

    group for collision filtering

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set group(group): void -
  • -
  • -
    -

    group for collision filtering

    -
    -
    -

    Parameters

    -
      -
    • - group: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get isCentered(): boolean -
  • -
  • -
    -

    is body centered?

    -
    -

    - Returns boolean -

    -
    - -
  • -
  • - set isCentered(_isCentered): void -
  • -
  • -
    -

    flag to set is body centered

    -
    -
    -

    Parameters

    -
      -
    • - _isCentered: - boolean -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get radiusX(): number -
  • -
  • -
    -

    get ellipse radiusX

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set radiusX(radiusX): void -
  • -
  • -
    -

    set ellipse radiusX, update points

    -
    -
    -

    Parameters

    -
      -
    • - radiusX: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get radiusY(): number -
  • -
  • -
    -

    get ellipse radiusY

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set radiusY(radiusY): void -
  • -
  • -
    -

    set ellipse radiusY, update points

    -
    -
    -

    Parameters

    -
      -
    • - radiusY: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scale(): number -
  • -
  • -
    -

    allow approx getting of scale

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set scale(scale): void -
  • -
  • -
    -

    allow easier setting of scale

    -
    -
    -

    Parameters

    -
      -
    • - scale: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleX(): number -
  • -
  • -
    -

    - allow exact getting of scale x - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleY(): number -
  • -
  • -
    -

    - allow exact getting of scale y - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get step(): number -
  • -
  • -
    -

    get ellipse step number

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set step(step): void -
  • -
  • -
    -

    set ellipse step number

    -
    -
    -

    Parameters

    -
      -
    • - step: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get x(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set x(x): void -
  • -
  • -
    -

    updating this.pos.x by this.x = x updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get y(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set y(y): void -
  • -
  • -
    -

    updating this.pos.y by this.y = y updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - y: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
-

Methods

-
- - -
    - -
  • -
    -

    do not attempt to use Polygon.center()

    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Draws exact collider on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Draws Bounding Box on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - - -
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - if true, polygon is not an invalid, self-crossing polygon -

    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    update instantly or mark as dirty

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean - = false -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - inner function for after position change update aabb in - system and convex inner polygons -

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean = ... -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
-
- -
-
-

- Generated using - TypeDoc -

-
-
- - +Ellipse | Detect-Collisions

collider - ellipse

+

Hierarchy (view full)

Constructors

Properties

_group: number

group for collision filtering

+
_radiusX: number

inner initial params save

+
_radiusY: number
_step: number
angle: number

body angle in radians use deg2rad to convert

+
bbox: BBox

bounding box cache, without padding

+
calcPoints: SATVector[]
centered: boolean = false

is body centered

+
convexPolygons: SATPolygon[]

optimization for convex polygons

+
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

+
edges: SATVector[]
isConvex: true = true

ellipses are convex

+
isStatic: boolean

static bodies don't move but they collide

+
isTrigger: boolean

trigger bodies move but are like ghosts

+
maxX: number

maximum x bound of body

+
maxY: number

maximum y bound of body

+
minX: number

minimum x bound of body

+
minY: number

minimum y bound of body

+
normals: SATVector[]
offset: SATVector

each body may have offset from center

+
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

+
points: SATVector[]
pointsBackup: Vector[]

backup of points used for scaling

+
scaleVector: Vector = ...

scale Vector of body

+
system?: System<Body>

reference to collision system

+
type: Ellipse = BodyType.Ellipse

ellipse type

+
typeGroup: Ellipse = BodyGroup.Ellipse

faster than type

+

Accessors

  • get group(): number
  • group for collision filtering

    +

    Returns number

  • set group(group): void
  • group for collision filtering

    +

    Parameters

    • group: number

    Returns void

  • get isCentered(): boolean
  • is body centered?

    +

    Returns boolean

  • set isCentered(_isCentered): void
  • flag to set is body centered

    +

    Parameters

    • _isCentered: boolean

    Returns void

  • get scale(): number
  • allow approx getting of scale

    +

    Returns number

  • set scale(scale): void
  • allow easier setting of scale

    +

    Parameters

    • scale: number

    Returns void

  • get scaleX(): number
  • allow exact getting of scale x - use setScale(x, y) to set

    +

    Returns number

  • get scaleY(): number
  • allow exact getting of scale y - use setScale(x, y) to set

    +

    Returns number

Methods

  • inner function for after position change update aabb in system and convex inner polygons

    +

    Parameters

    • updateNow: boolean = ...

    Returns void

diff --git a/docs/classes/Line.html b/docs/classes/Line.html index ac12fcc3..11cf7c0c 100644 --- a/docs/classes/Line.html +++ b/docs/classes/Line.html @@ -1,4224 +1,110 @@ - - - - - - Line | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class Line

-
-
-

collider - line

-
-
-
-

- Hierarchy (view full) -

- -
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - - -
-
-
-

Properties

-
- - -
- _group: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- angle: - number -
-
-

body angle in radians use deg2rad to convert

-
-
- -
-
- - -
- bbox: - BBox -
-
-

bounding box cache, without padding

-
-
- -
-
- - -
- calcPoints: - SATVector[] -
- -
-
- - -
- centered: - boolean = false -
-
-

is body centered

-
-
- -
-
- - -
- convexPolygons: - SATPolygon[] -
-
-

optimization for convex polygons

-
-
- -
-
- - -
- dirty: - boolean = false -
-
-

- was the polygon modified and needs update in the next - checkCollision -

-
-
- -
-
- - -
- edges: - SATVector[] -
- -
-
- - -
- isConvex: - true = true -
-

line is convex

-
- -
-
- - -
- isStatic: - boolean -
-
-

static bodies don't move but they collide

-
-
- -
-
- - -
- isTrigger: - boolean -
-
-

trigger bodies move but are like ghosts

-
-
- -
-
- - -
- maxX: - number -
-
-

maximum x bound of body

-
-
- -
-
- - -
- maxY: - number -
-
-

maximum y bound of body

-
-
- -
-
- - -
- minX: - number -
-
-

minimum x bound of body

-
-
- -
-
- - -
- minY: - number -
-
-

minimum y bound of body

-
-
- -
-
- - -
- normals: - SATVector[] -
- -
-
- - -
- offset: - SATVector -
-
-

each body may have offset from center

-
-
- -
-
- - -
- padding: - number -
-
-

- bodies are not reinserted during update if their bbox didnt move - outside bbox + padding -

-
-
- -
-
- - -
- points: - SATVector[] -
- -
-
- - -
- pointsBackup: - Vector[] -
-
-

backup of points used for scaling

-
-
- -
-
- - -
- pos: - SATVector -
- -
-
- - -
- scaleVector: - Vector = ... -
-
-

scale Vector of body

-
-
- -
-
- - -
- system?: - System<Body> -
-
-

reference to collision system

-
-
- -
-
- - -
- type: - Line = BodyType.Line -
-

line type

-
- -
-
- - -
- typeGroup: - Line = BodyGroup.Line -
-
-

faster than type

-
-
- -
-
-
-

Accessors

-
- - - -
-
- - -
    -
  • - get group(): number -
  • -
  • -
    -

    group for collision filtering

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set group(group): void -
  • -
  • -
    -

    group for collision filtering

    -
    -
    -

    Parameters

    -
      -
    • - group: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get isCentered(): boolean -
  • -
  • -
    -

    is polygon centered?

    -
    -

    - Returns boolean -

    -
    - -
  • -
  • - set isCentered(isCentered): void -
  • -
  • -
    -

    flag to set is polygon centered

    -
    -
    -

    Parameters

    -
      -
    • - isCentered: - boolean -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scale(): number -
  • -
  • -
    -

    allow approx getting of scale

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set scale(scale): void -
  • -
  • -
    -

    allow easier setting of scale

    -
    -
    -

    Parameters

    -
      -
    • - scale: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleX(): number -
  • -
  • -
    -

    - allow exact getting of scale x - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleY(): number -
  • -
  • -
    -

    - allow exact getting of scale y - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - - -
-
- - -
    -
  • - get x(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set x(x): void -
  • -
  • -
    -

    updating this.pos.x by this.x = x updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get y(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set y(y): void -
  • -
  • -
    -

    updating this.pos.y by this.y = y updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - y: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
-

Methods

-
- - -
    - -
  • -
    -

    Draws exact collider on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Draws Bounding Box on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - if true, polygon is not an invalid, self-crossing polygon -

    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    update instantly or mark as dirty

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean - = false -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - inner function for after position change update aabb in - system and convex inner polygons -

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean = ... -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
-
- -
-
-

- Generated using - TypeDoc -

-
-
- - +Line | Detect-Collisions

collider - line

+

Hierarchy (view full)

Constructors

Properties

_group: number

group for collision filtering

+
angle: number

body angle in radians use deg2rad to convert

+
bbox: BBox

bounding box cache, without padding

+
calcPoints: SATVector[]
centered: boolean = false

is body centered

+
convexPolygons: SATPolygon[]

optimization for convex polygons

+
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

+
edges: SATVector[]
isConvex: true = true

line is convex

+
isStatic: boolean

static bodies don't move but they collide

+
isTrigger: boolean

trigger bodies move but are like ghosts

+
maxX: number

maximum x bound of body

+
maxY: number

maximum y bound of body

+
minX: number

minimum x bound of body

+
minY: number

minimum y bound of body

+
normals: SATVector[]
offset: SATVector

each body may have offset from center

+
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

+
points: SATVector[]
pointsBackup: Vector[]

backup of points used for scaling

+
scaleVector: Vector = ...

scale Vector of body

+
system?: System<Body>

reference to collision system

+
type: Line = BodyType.Line

line type

+
typeGroup: Line = BodyGroup.Line

faster than type

+

Accessors

  • get group(): number
  • group for collision filtering

    +

    Returns number

  • set group(group): void
  • group for collision filtering

    +

    Parameters

    • group: number

    Returns void

  • get isCentered(): boolean
  • is polygon centered?

    +

    Returns boolean

  • set isCentered(isCentered): void
  • flag to set is polygon centered

    +

    Parameters

    • isCentered: boolean

    Returns void

  • get scale(): number
  • allow approx getting of scale

    +

    Returns number

  • set scale(scale): void
  • allow easier setting of scale

    +

    Parameters

    • scale: number

    Returns void

  • get scaleX(): number
  • allow exact getting of scale x - use setScale(x, y) to set

    +

    Returns number

  • get scaleY(): number
  • allow exact getting of scale y - use setScale(x, y) to set

    +

    Returns number

Methods

  • inner function for after position change update aabb in system and convex inner polygons

    +

    Parameters

    • updateNow: boolean = ...

    Returns void

diff --git a/docs/classes/Point.html b/docs/classes/Point.html index 81e69b2a..a0b4286f 100644 --- a/docs/classes/Point.html +++ b/docs/classes/Point.html @@ -1,4391 +1,121 @@ - - - - - - Point | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class Point

-
-
-
-

collider - point (very tiny box)

-
-
-
-
-

- Hierarchy (view full) -

-
    -
  • - Box -
      -
    • Point
    • -
    -
  • -
-
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - - -
-
-
-

Properties

-
- - -
- _group: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- _height: - number -
-

inner height

-
- -
-
- - -
- _width: - number -
-

inner width

-
- -
-
- - -
- angle: - number -
-
-

body angle in radians use deg2rad to convert

-
-
- -
-
- - -
- bbox: - BBox -
-
-

bounding box cache, without padding

-
-
- -
-
- - -
- calcPoints: - SATVector[] -
- -
-
- - -
- centered: - boolean = false -
-
-

is body centered

-
-
- -
-
- - -
- convexPolygons: - SATPolygon[] -
-
-

optimization for convex polygons

-
-
- -
-
- - -
- dirty: - boolean = false -
-
-

- was the polygon modified and needs update in the next - checkCollision -

-
-
- -
-
- - -
- edges: - SATVector[] -
- -
-
- - -
- isConvex: - true = true -
-
-

boxes are convex

-
-
- -
-
- - -
- isStatic: - boolean -
-
-

static bodies don't move but they collide

-
-
- -
-
- - -
- isTrigger: - boolean -
-
-

trigger bodies move but are like ghosts

-
-
- -
-
- - -
- maxX: - number -
-
-

maximum x bound of body

-
-
- -
-
- - -
- maxY: - number -
-
-

maximum y bound of body

-
-
- -
-
- - -
- minX: - number -
-
-

minimum x bound of body

-
-
- -
-
- - -
- minY: - number -
-
-

minimum y bound of body

-
-
- -
-
- - -
- normals: - SATVector[] -
- -
-
- - -
- offset: - SATVector -
-
-

each body may have offset from center

-
-
- -
-
- - -
- padding: - number -
-
-

- bodies are not reinserted during update if their bbox didnt move - outside bbox + padding -

-
-
- -
-
- - -
- points: - SATVector[] -
- -
-
- - -
- pointsBackup: - Vector[] -
-
-

backup of points used for scaling

-
-
- -
-
- - -
- pos: - SATVector -
- -
-
- - -
- scaleVector: - Vector = ... -
-
-

scale Vector of body

-
-
- -
-
- - -
- system?: - System<Body> -
-
-

reference to collision system

-
-
- -
-
- - -
- type: - Point = BodyType.Point -
-

point type

-
- -
-
- - -
- typeGroup: - Point = BodyGroup.Point -
-
-

faster than type

-
-
- -
-
-
-

Accessors

-
- - -
    -
  • - get group(): number -
  • -
  • -
    -

    group for collision filtering

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set group(group): void -
  • -
  • -
    -

    group for collision filtering

    -
    -
    -

    Parameters

    -
      -
    • - group: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get height(): number -
  • -
  • -
    -

    get box height

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set height(height): void -
  • -
  • -
    -

    set box height, update points

    -
    -
    -

    Parameters

    -
      -
    • - height: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get isCentered(): boolean -
  • -
  • -
    -

    is polygon centered?

    -
    -

    - Returns boolean -

    -
    - -
  • -
  • - set isCentered(isCentered): void -
  • -
  • -
    -

    flag to set is polygon centered

    -
    -
    -

    Parameters

    -
      -
    • - isCentered: - boolean -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scale(): number -
  • -
  • -
    -

    allow approx getting of scale

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set scale(scale): void -
  • -
  • -
    -

    allow easier setting of scale

    -
    -
    -

    Parameters

    -
      -
    • - scale: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleX(): number -
  • -
  • -
    -

    - allow exact getting of scale x - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleY(): number -
  • -
  • -
    -

    - allow exact getting of scale y - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get width(): number -
  • -
  • -
    -

    get box width

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set width(width): void -
  • -
  • -
    -

    set box width, update points

    -
    -
    -

    Parameters

    -
      -
    • - width: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get x(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set x(x): void -
  • -
  • -
    -

    updating this.pos.x by this.x = x updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get y(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set y(y): void -
  • -
  • -
    -

    updating this.pos.y by this.y = y updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - y: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
-

Methods

-
- - - -
-
- - -
    - -
  • -
    -

    Draws exact collider on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Draws Bounding Box on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - - -
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - if true, polygon is not an invalid, self-crossing polygon -

    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    update instantly or mark as dirty

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean - = false -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - isCentered: - boolean = ... -
    • -
    -
    -

    - Returns void -

    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - inner function for after position change update aabb in - system and convex inner polygons -

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean = ... -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - update the position of the decomposed convex polygons (if - any), called after the position of the body has changed -

    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - - -
-
- - -
    - -
  • -
    -

    do not attempt to use Polygon.updateIsConvex()

    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- -
-
-

- Generated using - TypeDoc -

-
-
- - +Point | Detect-Collisions

collider - point (very tiny box)

+

Hierarchy (view full)

Constructors

Properties

_group: number

group for collision filtering

+
_height: number

inner height

+
_width: number

inner width

+
angle: number

body angle in radians use deg2rad to convert

+
bbox: BBox

bounding box cache, without padding

+
calcPoints: SATVector[]
centered: boolean = false

is body centered

+
convexPolygons: SATPolygon[]

optimization for convex polygons

+
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

+
edges: SATVector[]
isConvex: true = true

boxes are convex

+
isStatic: boolean

static bodies don't move but they collide

+
isTrigger: boolean

trigger bodies move but are like ghosts

+
maxX: number

maximum x bound of body

+
maxY: number

maximum y bound of body

+
minX: number

minimum x bound of body

+
minY: number

minimum y bound of body

+
normals: SATVector[]
offset: SATVector

each body may have offset from center

+
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

+
points: SATVector[]
pointsBackup: Vector[]

backup of points used for scaling

+
scaleVector: Vector = ...

scale Vector of body

+
system?: System<Body>

reference to collision system

+
type: Point = BodyType.Point

point type

+
typeGroup: Point = BodyGroup.Point

faster than type

+

Accessors

  • get group(): number
  • group for collision filtering

    +

    Returns number

  • set group(group): void
  • group for collision filtering

    +

    Parameters

    • group: number

    Returns void

  • get height(): number
  • get box height

    +

    Returns number

  • set height(height): void
  • set box height, update points

    +

    Parameters

    • height: number

    Returns void

  • get isCentered(): boolean
  • is polygon centered?

    +

    Returns boolean

  • set isCentered(isCentered): void
  • flag to set is polygon centered

    +

    Parameters

    • isCentered: boolean

    Returns void

  • get scale(): number
  • allow approx getting of scale

    +

    Returns number

  • set scale(scale): void
  • allow easier setting of scale

    +

    Parameters

    • scale: number

    Returns void

  • get scaleX(): number
  • allow exact getting of scale x - use setScale(x, y) to set

    +

    Returns number

  • get scaleY(): number
  • allow exact getting of scale y - use setScale(x, y) to set

    +

    Returns number

  • get width(): number
  • get box width

    +

    Returns number

  • set width(width): void
  • set box width, update points

    +

    Parameters

    • width: number

    Returns void

Methods

  • Draws exact collider on canvas context

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • Draws Bounding Box on canvas context

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • inner function for after position change update aabb in system and convex inner polygons

    +

    Parameters

    • updateNow: boolean = ...

    Returns void

diff --git a/docs/classes/Polygon.html b/docs/classes/Polygon.html index 9a9b267c..abbf8abb 100644 --- a/docs/classes/Polygon.html +++ b/docs/classes/Polygon.html @@ -1,4022 +1,108 @@ - - - - - - Polygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class Polygon

-
-
-
-

collider - polygon

-
-
-
-
-

- Hierarchy (view full) -

- -
-
-

Implements

- -
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - - -
-
-
-

Properties

-
- - -
- _group: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- angle: - number -
-
-

body angle in radians use deg2rad to convert

-
-
- -
-
- - -
- bbox: - BBox -
-
-

bounding box cache, without padding

-
-
- -
-
- - -
- calcPoints: - SATVector[] -
- -
-
- - -
- centered: - boolean = false -
-
-

is body centered

-
-
- -
-
- - -
- convexPolygons: - SATPolygon[] -
-
-

optimization for convex polygons

-
-
- -
-
- - -
- dirty: - boolean = false -
-
-

- was the polygon modified and needs update in the next - checkCollision -

-
-
- -
-
- - -
- edges: - SATVector[] -
- -
-
- - -
- isConvex: - boolean -
-
-

- is it a convex polgyon as opposed to a hollow inside (concave) - polygon -

-
-
- -
-
- - -
- isStatic: - boolean -
-
-

static bodies don't move but they collide

-
-
- -
-
- - -
- isTrigger: - boolean -
-
-

trigger bodies move but are like ghosts

-
-
- -
-
- - -
- maxX: - number -
-
-

maximum x bound of body

-
-
- -
-
- - -
- maxY: - number -
-
-

maximum y bound of body

-
-
- -
-
- - -
- minX: - number -
-
-

minimum x bound of body

-
-
- -
-
- - -
- minY: - number -
-
-

minimum y bound of body

-
-
- -
-
- - -
- normals: - SATVector[] -
- -
-
- - -
- offset: - SATVector -
-
-

each body may have offset from center

-
-
- -
-
- - -
- padding: - number -
-
-

- bodies are not reinserted during update if their bbox didnt move - outside bbox + padding -

-
-
- -
-
- - -
- points: - SATVector[] -
- -
-
- - -
- pointsBackup: - Vector[] -
-
-

backup of points used for scaling

-
-
- -
-
- - -
- pos: - SATVector -
- -
-
- - -
- scaleVector: - Vector = ... -
-
-

scale Vector of body

-
-
- -
-
- - -
- system?: - System<Body> -
-
-

reference to collision system

-
-
- -
-
- - -
- type: - Ellipse | Polygon | Box | Line | Point = BodyType.Polygon -
-

type of body

-
- -
-
- - -
- typeGroup: - Ellipse | Polygon | Box | Line | Point = BodyGroup.Polygon -
-
-

faster than type

-
-
- -
-
-
-

Accessors

-
- - -
    -
  • - get group(): number -
  • -
  • -
    -

    group for collision filtering

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set group(group): void -
  • -
  • -
    -

    group for collision filtering

    -
    -
    -

    Parameters

    -
      -
    • - group: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get isCentered(): boolean -
  • -
  • -
    -

    is polygon centered?

    -
    -

    - Returns boolean -

    -
    - -
  • -
  • - set isCentered(isCentered): void -
  • -
  • -
    -

    flag to set is polygon centered

    -
    -
    -

    Parameters

    -
      -
    • - isCentered: - boolean -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scale(): number -
  • -
  • -
    -

    allow approx getting of scale

    -
    -

    - Returns number -

    -
    - -
  • -
  • - set scale(scale): void -
  • -
  • -
    -

    allow easier setting of scale

    -
    -
    -

    Parameters

    -
      -
    • - scale: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleX(): number -
  • -
  • -
    -

    - allow exact getting of scale x - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleY(): number -
  • -
  • -
    -

    - allow exact getting of scale y - use setScale(x, y) to set -

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get x(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set x(x): void -
  • -
  • -
    -

    updating this.pos.x by this.x = x updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    -
  • - get y(): number -
  • -
  • -

    - Returns number -

    - -
  • -
  • - set y(y): void -
  • -
  • -
    -

    updating this.pos.y by this.y = y updates AABB

    -
    -
    -

    Parameters

    -
      -
    • - y: - number -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
-

Methods

-
- - -
    - -
  • -
    -

    Draws exact collider on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Draws Bounding Box on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - - -
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - if true, polygon is not an invalid, self-crossing polygon -

    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    update instantly or mark as dirty

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean - = false -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - isCentered: - boolean = ... -
    • -
    -
    -

    - Returns void -

    - -
  • -
-
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    - inner function for after position change update aabb in - system and convex inner polygons -

    -
    -
    -

    Parameters

    -
      -
    • - update: - boolean = ... -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - update the position of the decomposed convex polygons (if - any), called after the position of the body has changed -

    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    updates convex polygons cache in body

    -
    -
    -

    Parameters

    - -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    after points update set is convex

    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- -
-
-

- Generated using - TypeDoc -

-
-
- - +Polygon | Detect-Collisions

collider - polygon

+

Hierarchy (view full)

Implements

Constructors

Properties

_group: number

group for collision filtering

+
angle: number

body angle in radians use deg2rad to convert

+
bbox: BBox

bounding box cache, without padding

+
calcPoints: SATVector[]
centered: boolean = false

is body centered

+
convexPolygons: SATPolygon[]

optimization for convex polygons

+
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

+
edges: SATVector[]
isConvex: boolean

is it a convex polgyon as opposed to a hollow inside (concave) polygon

+
isStatic: boolean

static bodies don't move but they collide

+
isTrigger: boolean

trigger bodies move but are like ghosts

+
maxX: number

maximum x bound of body

+
maxY: number

maximum y bound of body

+
minX: number

minimum x bound of body

+
minY: number

minimum y bound of body

+
normals: SATVector[]
offset: SATVector

each body may have offset from center

+
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

+
points: SATVector[]
pointsBackup: Vector[]

backup of points used for scaling

+
scaleVector: Vector = ...

scale Vector of body

+
system?: System<Body>

reference to collision system

+
type:
    | Ellipse
    | Polygon
    | Box
    | Line
    | Point = BodyType.Polygon

type of body

+
typeGroup:
    | Ellipse
    | Polygon
    | Box
    | Line
    | Point = BodyGroup.Polygon

faster than type

+

Accessors

  • get scaleX(): number
  • allow exact getting of scale x - use setScale(x, y) to set

    +

    Returns number

  • get scaleY(): number
  • allow exact getting of scale y - use setScale(x, y) to set

    +

    Returns number

Methods

  • if true, polygon is not an invalid, self-crossing polygon

    +

    Returns boolean

  • update instantly or mark as dirty

    +

    Parameters

    • updateNow: boolean = false

    Returns void

  • inner function for after position change update aabb in system and convex inner polygons

    +

    Parameters

    • updateNow: boolean = ...

    Returns void

  • update the position of the decomposed convex polygons (if any), called +after the position of the body has changed

    +

    Returns void

diff --git a/docs/classes/RBush.html b/docs/classes/RBush.html index 606bddc2..af87d37c 100644 --- a/docs/classes/RBush.html +++ b/docs/classes/RBush.html @@ -1,1600 +1,28 @@ - - - - - - RBush | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class RBush<T>

-
-
-

Type Parameters

-
    -
  • - T -
  • -
-
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - -
    - -
  • -
    -

    - Constructs an RBush, a high-performance 2D - spatial index for points and rectangles. Based on an - optimized R-tree data structure with - bulk-insertion support. -

    -
    -
    -

    Type Parameters

    -
      -
    • - T -
    • -
    -
    -
    -

    Parameters

    -
      -
    • - Optional - maxEntries: - number -
      -

      - An optional argument to RBush defines the maximum - number of entries in a tree node. 9 (used - by default) is a reasonable choice for most - applications. Higher value means faster insertion and - slower search, and vice versa. -

      -
      -
      -
    • -
    -
    -

    - Returns - RBush<T> -

    -
    - -
  • -
-
-
-
-

Methods

-
- - -
    - -
  • -
    -

    Returns all items contained in the tree.

    -
    -

    - Returns - T[] -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Removes all items.

    -
    -

    - Returns - RBush<T> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Returns true if there are any items - intersecting the given bounding box, otherwise - false. -

    -
    -
    -

    Parameters

    -
      -
    • - box: - BBox -
      -

      The bounding box in which to search.

      -
      -
      -
    • -
    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Compares the minimum x coordinate of two items. Returns -1 - if a's x-coordinate is smaller, 1 if - b's x coordinate is smaller, or 0 if - they're equal. -

    -

    - By default, RBush assumes the format of data - points to be an object with minX, - minY, maxX, and maxY. - However, you can specify a custom item format by overriding - toBBox(), compareMinX(), and - compareMinY(). -

    -
    -
    -

    Parameters

    -
      -
    • - a: - T -
      -

      The first item to compare.

      -
      -
      -
    • -
    • - b: - T -
      -

      The second item to compare.

      -
      -
      -
    • -
    -
    -

    - Returns number -

    -
    -

    Example

    -
    class MyRBush<T> extends RBush<T> {
    toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
    compareMinX(a, b) { return a.x - b.x; }
    compareMinY(a, b) { return a.y - b.y; }
    }
    const tree = new MyRBush<[number, number]>();
    tree.insert([20, 50]); // accepts [x, y] points -
    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Compares the minimum y coordinate of two items. Returns -1 - if a's x-coordinate is smaller, 1 if - b's x coordinate is smaller, or 0 if - they're equal. -

    -

    - By default, RBush assumes the format of data - points to be an object with minX, - minY, maxX, and maxY. - However, you can specify a custom item format by overriding - toBBox(), compareMinX(), and - compareMinY(). -

    -
    -
    -

    Parameters

    -
      -
    • - a: - T -
      -

      The first item to compare.

      -
      -
      -
    • -
    • - b: - T -
      -

      The second item to compare.

      -
      -
      -
    • -
    -
    -

    - Returns number -

    -
    -

    Example

    -
    class MyRBush<T> extends RBush<T> {
    toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
    compareMinX(a, b) { return a.x - b.x; }
    compareMinY(a, b) { return a.y - b.y; }
    }
    const tree = new MyRBush<[number, number]>();
    tree.insert([20, 50]); // accepts [x, y] points -
    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Imports previously exported data into the tree (i.e., data - that was emitted by toJSON()). -

    -

    - Importing and exporting as JSON allows you to use RBush on - both the server (using Node.js) and the browser combined, - e.g. first indexing the data on the server and and then - importing the resulting tree data on the client for - searching. -

    -

    - Note that the maxEntries option from the - constructor must be the same in both trees for export/import - to work properly. -

    -
    -
    -

    Parameters

    -
      -
    • - data: - any -
      -

      The previously exported JSON data.

      -
      -
      -
    • -
    -
    -

    - Returns - RBush<T> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Inserts an item. To insert many items at once, use - load(). -

    -
    -
    -

    Parameters

    -
      -
    • - item: - T -
      -

      The item to insert.

      -
      -
      -
    • -
    -
    -

    - Returns - RBush<T> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Bulk-inserts the given items into the tree.

    -

    - Bulk insertion is usually ~2-3 times faster than inserting - items one by one. After bulk loading (bulk insertion into an - empty tree), subsequent query performance is also ~20-30% - better. -

    -

    - Note that when you do bulk insertion into an existing tree, - it bulk-loads the given data into a separate tree and - inserts the smaller tree into the larger tree. This means - that bulk insertion works very well for clustered data - (where items in one update are close to each other), but - makes query performance worse if the data is scattered. -

    -
    -
    -

    Parameters

    -
      -
    • - items: - readonly T[] -
      -

      The items to load.

      -
      -
      -
    • -
    -
    -

    - Returns - RBush<T> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Removes a previously inserted item, comparing by reference. -

    -

    To remove all items, use clear().

    -
    -
    -

    Parameters

    -
      -
    • - item: - T -
      -

      The item to remove.

      -
      -
      -
    • -
    • - Optional - equals: - ((a, - b) => boolean) -
      -

      - A custom function that allows comparing by value - instead. Useful when you have only a copy of the - object you need removed (e.g. loaded from server). -

      -
      -
      -
        -
      • -
          -
        • - (a, - b): boolean -
        • -
        • -
          -

          Parameters

          -
            -
          • - a: - T -
          • -
          • - b: - T -
          • -
          -
          -

          - Returns - boolean -

          -
        • -
        -
      • -
      -
    • -
    -
    -

    - Returns - RBush<T> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Returns an array of data items (points or rectangles) that - the given bounding box intersects. -

    -

    - Note that the search method accepts a bounding box in - {minX, minY, maxX, maxY} format regardless of - the data format. -

    -
    -
    -

    Parameters

    -
      -
    • - box: - BBox -
      -

      The bounding box in which to search.

      -
      -
      -
    • -
    -
    -

    - Returns - T[] -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Returns the bounding box for the provided item.

    -

    - By default, RBush assumes the format of data - points to be an object with minX, - minY, maxX, and maxY. - However, you can specify a custom item format by overriding - toBBox(), compareMinX(), and - compareMinY(). -

    -
    -
    -

    Parameters

    -
      -
    • - item: - T -
      -

      The item whose bounding box should be returned.

      -
      -
      -
    • -
    -
    -

    - Returns - BBox -

    -
    -

    Example

    -
    class MyRBush<T> extends RBush<T> {
    toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
    compareMinX(a, b) { return a.x - b.x; }
    compareMinY(a, b) { return a.y - b.y; }
    }
    const tree = new MyRBush<[number, number]>();
    tree.insert([20, 50]); // accepts [x, y] points -
    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Exports the tree's contents as a JSON object.

    -

    - Importing and exporting as JSON allows you to use RBush on - both the server (using Node.js) and the browser combined, - e.g. first indexing the data on the server and and then - importing the resulting tree data on the client for - searching. -

    -

    - Note that the maxEntries option from the - constructor must be the same in both trees for export/import - to work properly. -

    -
    -

    - Returns any -

    -
    - -
  • -
-
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +RBush | Detect-Collisions

Constructors

Properties

_maxEntries: number
_minEntries: number
data: any

Methods

  • Parameters

    • bbox: any
    • path: any
    • level: any

    Returns void

  • Parameters

    • node: any
    • result: any

    Returns any

  • Parameters

    • node: any
    • m: any
    • M: any
    • compare: any

    Returns number

  • Parameters

    • items: any
    • left: any
    • right: any
    • height: any

    Returns {
        children: any;
        height: number;
        leaf: boolean;
        maxX: number;
        maxY: number;
        minX: number;
        minY: number;
    }

    • children: any
    • height: number
    • leaf: boolean
    • maxX: number
    • maxY: number
    • minX: number
    • minY: number
  • Parameters

    • node: any
    • m: any
    • M: any

    Returns void

  • Parameters

    • node: any
    • m: any
    • M: any

    Returns any

  • Parameters

    • bbox: any
    • node: any
    • level: any
    • path: any

    Returns any

  • Parameters

    • item: any
    • level: any
    • isNode: any

    Returns void

  • Parameters

    • insertPath: any
    • level: any

    Returns void

  • Parameters

    • node: any
    • newNode: any

    Returns void

  • Parameters

    • bbox: any

    Returns boolean

  • Parameters

    • a: any
    • b: any

    Returns number

  • Parameters

    • a: any
    • b: any

    Returns number

  • Parameters

    • bbox: any

    Returns any[]

diff --git a/docs/classes/Response.html b/docs/classes/Response.html index 6b9ec2e2..d5c1bfb4 100644 --- a/docs/classes/Response.html +++ b/docs/classes/Response.html @@ -1,689 +1,10 @@ - - - - - - Response | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class Response

-
- -
-
-
- - - -
-
-

Constructors

- -
-
-

Properties

- -
-
-

Methods

- -
-
-
-
-
-
-

Constructors

-
- - -
    - -
  • -

    - Returns - Response -

    - -
  • -
-
-
-
-

Properties

-
- - -
- a: - any -
- -
-
- - -
- aInB: - boolean -
- -
-
- - -
- b: - any -
- -
-
- - -
- bInA: - boolean -
- -
-
- - -
- overlap: - number -
- -
-
- - -
- overlapN: - SATVector -
- -
-
- - -
- overlapV: - SATVector -
- -
-
-
-

Methods

-
- - -
    - -
  • -

    - Returns - Response -

    - -
  • -
-
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Response | Detect-Collisions

Constructors

Properties

Methods

Constructors

  • Returns Response

Properties

a: any
aInB: boolean
b: any
bInA: boolean
overlap: number
overlapN: SATVector
overlapV: SATVector

Methods

  • Returns Response

diff --git a/docs/classes/SATCircle.html b/docs/classes/SATCircle.html index b63bf860..ecb4e46d 100644 --- a/docs/classes/SATCircle.html +++ b/docs/classes/SATCircle.html @@ -1,500 +1,5 @@ - - - - - - SATCircle | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class SATCircle

-
-
-
-

- This is simple circle with a center {pos} position and radius {r}. -

-
-
-
-
-

- Hierarchy (view full) -

-
    -
  • - SATCircle - -
  • -
-
- -
-
-
- - - -
-
-

Constructors

- -
-
-

Properties

-
- - pos - - r -
-
-
-
-
-
-
-

Constructors

-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - Optional - pos: - SATVector -
    • -
    • - Optional - r: - number -
    • -
    -
    -

    - Returns - SATCircle -

    - -
  • -
-
-
-
-

Properties

-
- - -
- pos: - SATVector -
- -
-
- - -
- r: - number -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +SATCircle | Detect-Collisions

This is simple circle with a center {pos} position and radius {r}.

+

Hierarchy (view full)

Constructors

Properties

pos +r +

Constructors

  • Parameters

    Returns SATCircle

Properties

r: number
diff --git a/docs/classes/SATPolygon.html b/docs/classes/SATPolygon.html index 5a00db3a..633f03d1 100644 --- a/docs/classes/SATPolygon.html +++ b/docs/classes/SATPolygon.html @@ -1,1190 +1,16 @@ - - - - - - SATPolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class SATPolygon

-
-
-

- Hierarchy (view full) -

-
    -
  • - SATPolygon - -
  • -
-
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATPolygon -

    - -
  • -
-
-
-
-

Properties

-
- - -
- angle: - number -
- -
-
- - -
- calcPoints: - SATVector[] -
- -
-
- - -
- edges: - SATVector[] -
- -
-
- - -
- normals: - SATVector[] -
- -
-
- - -
- offset: - SATVector -
- -
-
- - -
- points: - SATVector[] -
- -
-
- - -
- pos: - SATVector -
- -
-
-
-

Methods

-
- - -
    - -
  • -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - angle: - number -
    • -
    -
    -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - angle: - number -
    • -
    -
    -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATPolygon -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    • - y: - number -
    • -
    -
    -

    - Returns - SATPolygon -

    - -
  • -
-
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +SATPolygon | Detect-Collisions

Hierarchy (view full)

Constructors

Properties

angle: number
calcPoints: SATVector[]
edges: SATVector[]
normals: SATVector[]
offset: SATVector
points: SATVector[]

Methods

  • Parameters

    • angle: number

    Returns SATPolygon

  • Parameters

    • angle: number

    Returns SATPolygon

  • Parameters

    • x: number
    • y: number

    Returns SATPolygon

diff --git a/docs/classes/SATVector.html b/docs/classes/SATVector.html index ee37ddb3..88d4f6b9 100644 --- a/docs/classes/SATVector.html +++ b/docs/classes/SATVector.html @@ -1,1584 +1,24 @@ - - - - - - SATVector | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class SATVector

-
-
-
-

- This is a simple 2D vector/point class,Vector has two parameters - {x},{y}. -

-
-
-
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - -
    - -
  • -
    -

    Vector has two properties

    -
    -
    -

    Parameters

    -
      -
    • - Optional - x: - number -
      -

      The x-coordinate of the Vector.

      -
      -
      -
    • -
    • - Optional - y: - number -
      -

      The y-coordinate of the Vector.

      -
      -
      -
    • -
    -
    -

    - Returns - SATVector -

    -
    - -
  • -
-
-
-
-

Properties

-
- - -
- x: - number -
- -
-
- - -
- y: - number -
- -
-
-
-

Methods

-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns number -

    - -
  • -
-
-
- - -
    - -
  • -

    - Returns number -

    - -
  • -
-
-
- - -
    - -
  • -

    - Returns number -

    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - angle: - number -
    • -
    -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    • - Optional - y: - number -
    • -
    -
    -

    - Returns - SATVector -

    - -
  • -
-
-
- - -
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    - -
  • -
-
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +SATVector | Detect-Collisions

This is a simple 2D vector/point class,Vector has two parameters {x},{y}.

+

Constructors

Properties

x +y +

Methods

Constructors

  • Vector has two properties

    +

    Parameters

    • Optionalx: number

      The x-coordinate of the Vector.

      +
    • Optionaly: number

      The y-coordinate of the Vector.

      +

    Returns SATVector

Properties

x: number
y: number

Methods

  • Parameters

    Returns number

  • Returns number

  • Returns number

  • Parameters

    • angle: number

    Returns SATVector

  • Parameters

    • x: number
    • Optionaly: number

    Returns SATVector

diff --git a/docs/classes/System.html b/docs/classes/System.html index 9e3c1ce5..46585742 100644 --- a/docs/classes/System.html +++ b/docs/classes/System.html @@ -1,3645 +1,75 @@ - - - - - - System | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Class System<TBody>

-
-
-

collision system

-
-
-
-

Type Parameters

- -
-
-

Hierarchy

-
    -
  • - BaseSystem<TBody> -
      -
    • System
    • -
    -
  • -
-
- -
-
-
- - - - -
-
-
-
-

Constructors

-
- - -
    - -
  • -
    -

    - Constructs an RBush, a high-performance 2D - spatial index for points and rectangles. Based on an - optimized R-tree data structure with - bulk-insertion support. -

    -
    -
    -

    Type Parameters

    - -
    -
    -

    Parameters

    -
      -
    • - Optional - maxEntries: - number -
      -

      - An optional argument to RBush defines the maximum - number of entries in a tree node. 9 (used - by default) is a reasonable choice for most - applications. Higher value means faster insertion and - slower search, and vice versa. -

      -
      -
      -
    • -
    -
    -

    - Returns - System<TBody> -

    -
    - -
  • -
-
-
-
-

Properties

-
- - -
- data: - ChildrenData<TBody> -
- -
-
- - -
- ray: - Line -
-

for raycasting

-
- -
-
- - -
- response: - Response = ... -
-
-

the last collision result

-
-
- -
-
-
-

Methods

-
- - -
    - -
  • -
    -

    Returns all items contained in the tree.

    -
    -

    - Returns - TBody[] -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    check all bodies collisions with callback

    -
    -
    -

    Parameters

    - -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    check all bodies collisions in area with callback

    -
    -
    -

    Parameters

    - -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    check do 2 objects collide

    -
    -
    -

    Parameters

    - -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    check one body collisions with callback

    -
    -
    -

    Parameters

    - -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Removes all items.

    -
    -

    - Returns - RBush<TBody> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Returns true if there are any items - intersecting the given bounding box, otherwise - false. -

    -
    -
    -

    Parameters

    -
      -
    • - box: - BBox -
      -

      The bounding box in which to search.

      -
      -
      -
    • -
    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Compares the minimum x coordinate of two items. Returns -1 - if a's x-coordinate is smaller, 1 if - b's x coordinate is smaller, or 0 if - they're equal. -

    -

    - By default, RBush assumes the format of data - points to be an object with minX, - minY, maxX, and maxY. - However, you can specify a custom item format by overriding - toBBox(), compareMinX(), and - compareMinY(). -

    -
    -
    -

    Parameters

    -
      -
    • - a: - TBody -
      -

      The first item to compare.

      -
      -
      -
    • -
    • - b: - TBody -
      -

      The second item to compare.

      -
      -
      -
    • -
    -
    -

    - Returns number -

    -
    -

    Example

    -
    class MyRBush<T> extends RBush<T> {
    toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
    compareMinX(a, b) { return a.x - b.x; }
    compareMinY(a, b) { return a.y - b.y; }
    }
    const tree = new MyRBush<[number, number]>();
    tree.insert([20, 50]); // accepts [x, y] points -
    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Compares the minimum y coordinate of two items. Returns -1 - if a's x-coordinate is smaller, 1 if - b's x coordinate is smaller, or 0 if - they're equal. -

    -

    - By default, RBush assumes the format of data - points to be an object with minX, - minY, maxX, and maxY. - However, you can specify a custom item format by overriding - toBBox(), compareMinX(), and - compareMinY(). -

    -
    -
    -

    Parameters

    -
      -
    • - a: - TBody -
      -

      The first item to compare.

      -
      -
      -
    • -
    • - b: - TBody -
      -

      The second item to compare.

      -
      -
      -
    • -
    -
    -

    - Returns number -

    -
    -

    Example

    -
    class MyRBush<T> extends RBush<T> {
    toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
    compareMinX(a, b) { return a.x - b.x; }
    compareMinY(a, b) { return a.y - b.y; }
    }
    const tree = new MyRBush<[number, number]>();
    tree.insert([20, 50]); // accepts [x, y] points -
    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    create box at position with options and add to system

    -
    -
    -

    Parameters

    - -
    -

    - Returns - Box -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - create circle at position with options and add to system -

    -
    -
    -

    Parameters

    - -
    -

    - Returns - Circle -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - create ellipse at position with options and add to system -

    -
    -
    -

    Parameters

    -
      -
    • - position: - PotentialVector -
    • -
    • - radiusX: - number -
    • -
    • - radiusY: - number - = radiusX -
    • -
    • - Optional - step: - number -
    • -
    • - Optional - options: - BodyOptions -
    • -
    -
    -

    - Returns - Ellipse -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    create line at position with options and add to system

    -
    -
    -

    Parameters

    - -
    -

    - Returns - Line -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    create point at position with options and add to system

    -
    -
    -

    Parameters

    - -
    -

    - Returns - Point -

    -
    - -
  • -
-
-
- - - -
-
- - -
    - -
  • -
    -

    draw exact bodies colliders outline

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    draw bounding boxes hierarchy outline

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - Imports previously exported data into the tree (i.e., data - that was emitted by toJSON()). -

    -

    - Importing and exporting as JSON allows you to use RBush on - both the server (using Node.js) and the browser combined, - e.g. first indexing the data on the server and and then - importing the resulting tree data on the client for - searching. -

    -

    - Note that the maxEntries option from the - constructor must be the same in both trees for export/import - to work properly. -

    -
    -
    -

    Parameters

    -
      -
    • - data: - any -
      -

      The previously exported JSON data.

      -
      -
      -
    • -
    -
    -

    - Returns - RBush<TBody> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    get object potential colliders

    -
    -
    -

    Parameters

    - -
    -

    - Returns - TBody[] -

    -
    -

    Deprecated

    -

    - because it's slower to use than checkOne() or checkAll() -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - re-insert body into collision tree and update its bbox every - body can be part of only one system -

    -
    -
    -

    Parameters

    - -
    -

    - Returns - RBush<TBody> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Bulk-inserts the given items into the tree.

    -

    - Bulk insertion is usually ~2-3 times faster than inserting - items one by one. After bulk loading (bulk insertion into an - empty tree), subsequent query performance is also ~20-30% - better. -

    -

    - Note that when you do bulk insertion into an existing tree, - it bulk-loads the given data into a separate tree and - inserts the smaller tree into the larger tree. This means - that bulk insertion works very well for clustered data - (where items in one update are close to each other), but - makes query performance worse if the data is scattered. -

    -
    -
    -

    Parameters

    -
      -
    • - items: - readonly TBody[] -
      -

      The items to load.

      -
      -
      -
    • -
    -
    -

    - Returns - RBush<TBody> -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    raycast to get collider of ray from start to end

    -
    -
    -

    Parameters

    -
      -
    • - start: - Vector -
    • -
    • - end: - Vector -
    • -
    • - allow: - ((body, - ray) => boolean) - = returnTrue -
        -
      • -
          -
        • - (body, - ray): boolean -
        • -
        • -
          -

          Parameters

          - -
          -

          - Returns - boolean -

          -
        • -
        -
      • -
      -
    • -
    -
    -

    - Returns null | RaycastHit<TBody> -

    -
    - -
  • -
-
-
- - - -
-
- - -
    - -
  • -
    -

    - Returns an array of data items (points or rectangles) that - the given bounding box intersects. -

    -

    - Note that the search method accepts a bounding box in - {minX, minY, maxX, maxY} format regardless of - the data format. -

    -
    -
    -

    Parameters

    -
      -
    • - box: - BBox -
      -

      The bounding box in which to search.

      -
      -
      -
    • -
    -
    -

    - Returns - TBody[] -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    separate (move away) bodies

    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    separate (move away) 1 body

    -
    -
    -

    Parameters

    - -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Returns the bounding box for the provided item.

    -

    - By default, RBush assumes the format of data - points to be an object with minX, - minY, maxX, and maxY. - However, you can specify a custom item format by overriding - toBBox(), compareMinX(), and - compareMinY(). -

    -
    -
    -

    Parameters

    -
      -
    • - item: - TBody -
      -

      The item whose bounding box should be returned.

      -
      -
      -
    • -
    -
    -

    - Returns - BBox -

    -
    -

    Example

    -
    class MyRBush<T> extends RBush<T> {
    toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
    compareMinX(a, b) { return a.x - b.x; }
    compareMinY(a, b) { return a.y - b.y; }
    }
    const tree = new MyRBush<[number, number]>();
    tree.insert([20, 50]); // accepts [x, y] points -
    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    Exports the tree's contents as a JSON object.

    -

    - Importing and exporting as JSON allows you to use RBush on - both the server (using Node.js) and the browser combined, - e.g. first indexing the data on the server and and then - importing the resulting tree data on the client for - searching. -

    -

    - Note that the maxEntries option from the - constructor must be the same in both trees for export/import - to work properly. -

    -
    -

    - Returns any -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    - used to find body deep inside data with finder function - returning boolean found or not -

    -
    -
    -

    Parameters

    - -
    -

    - Returns undefined | TBody -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    update all bodies aabb

    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    updates body in collision tree

    -
    -
    -

    Parameters

    - -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- -
-
-

- Generated using - TypeDoc -

-
-
- - +System | Detect-Collisions

Class System<TBody>

collision system

+

Type Parameters

Hierarchy

Constructors

Properties

_maxEntries: number
_minEntries: number
ray: Line

for raycasting

+
response: Response = ...

the last collision result

+

Methods

  • Parameters

    • bbox: any
    • path: any
    • level: any

    Returns void

  • Parameters

    • node: any
    • result: any

    Returns any

  • Parameters

    • node: any
    • m: any
    • M: any
    • compare: any

    Returns number

  • Parameters

    • items: any
    • left: any
    • right: any
    • height: any

    Returns {
        children: any;
        height: number;
        leaf: boolean;
        maxX: number;
        maxY: number;
        minX: number;
        minY: number;
    }

    • children: any
    • height: number
    • leaf: boolean
    • maxX: number
    • maxY: number
    • minX: number
    • minY: number
  • Parameters

    • node: any
    • m: any
    • M: any

    Returns void

  • Parameters

    • node: any
    • m: any
    • M: any

    Returns any

  • Parameters

    • bbox: any
    • node: any
    • level: any
    • path: any

    Returns any

  • Parameters

    • path: any

    Returns void

  • Parameters

    • item: any
    • level: any
    • isNode: any

    Returns void

  • Parameters

    • insertPath: any
    • level: any

    Returns void

  • Parameters

    • node: any
    • newNode: any

    Returns void

  • Returns any

  • check do 2 objects collide

    +

    Parameters

    Returns boolean

  • Parameters

    • bbox: any

    Returns boolean

  • Parameters

    • a: any
    • b: any

    Returns number

  • Parameters

    • a: any
    • b: any

    Returns number

  • create box at position with options and add to system

    +

    Parameters

    Returns Box

  • create ellipse at position with options and add to system

    +

    Parameters

    Returns Ellipse

  • draw exact bodies colliders outline

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • draw bounding boxes hierarchy outline

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • get object potential colliders

    +

    Parameters

    Returns TBody[]

    because it's slower to use than checkOne() or checkAll()

    +
  • re-insert body into collision tree and update its bbox +every body can be part of only one system

    +

    Parameters

    Returns this

  • remove body aabb from collision tree

    +

    Parameters

    Returns this

  • Parameters

    • bbox: any

    Returns any[]

  • separate (move away) bodies

    +

    Returns void

  • separate (move away) 1 body

    +

    Parameters

    Returns void

  • Parameters

    • item: any

    Returns any

  • Returns any

  • used to find body deep inside data with finder function returning boolean found or not

    +

    Parameters

    Returns undefined | TBody

  • update all bodies aabb

    +

    Returns void

  • updates body in collision tree

    +

    Parameters

    Returns void

diff --git a/docs/demo/canvas.d.ts b/docs/demo/canvas.d.ts index 7d48b0a6..45b0fe39 100644 --- a/docs/demo/canvas.d.ts +++ b/docs/demo/canvas.d.ts @@ -1,14 +1,14 @@ export class TestCanvas { - constructor(test: any); - test: any; - element: HTMLDivElement; - canvas: HTMLCanvasElement; - context: CanvasRenderingContext2D | null; - bvhCheckbox: Element | null; - fps: number; - frame: number; - started: number; - update(): void; + constructor(test: any); + test: any; + element: HTMLDivElement; + canvas: HTMLCanvasElement; + context: CanvasRenderingContext2D | null; + bvhCheckbox: Element | null; + fps: number; + frame: number; + started: number; + update(): void; } export function loop(callback: any): void; export const width: number; diff --git a/docs/demo/canvas.js b/docs/demo/canvas.js index a161d560..a9b0263a 100644 --- a/docs/demo/canvas.js +++ b/docs/demo/canvas.js @@ -2,71 +2,67 @@ const width = window.innerWidth || 1024; const height = window.innerHeight || 768; class TestCanvas { - constructor(test) { - this.test = test; - this.element = document.createElement("div"); - this.element.id = "debug"; - this.element.innerHTML = `${this.test.legend} + constructor(test) { + this.test = test; + this.element = document.createElement("div"); + this.element.id = "debug"; + this.element.innerHTML = `${this.test.legend}
`; - this.canvas = document.createElement("canvas"); - this.canvas.width = width; - this.canvas.height = height; - this.context = this.canvas.getContext("2d"); - this.context.font = "24px Arial"; - this.test.context = this.context; - this.bvhCheckbox = this.element.querySelector("#bvh"); - if (this.canvas instanceof Node) { - this.element.appendChild(this.canvas); + this.canvas = document.createElement("canvas"); + this.canvas.width = width; + this.canvas.height = height; + this.context = this.canvas.getContext("2d"); + this.context.font = "24px Arial"; + this.test.context = this.context; + this.bvhCheckbox = this.element.querySelector("#bvh"); + if (this.canvas instanceof Node) { + this.element.appendChild(this.canvas); + } + this.fps = 0; + this.frame = 0; + this.started = Date.now(); + loop(this.update.bind(this)); } - this.fps = 0; - this.frame = 0; - this.started = Date.now(); - loop(this.update.bind(this)); - } - update() { - this.frame++; - const timeDiff = Date.now() - this.started; - if (timeDiff >= 1000) { - this.fps = this.frame / (timeDiff / 1000); - this.frame = 0; - this.started = Date.now(); + update() { + this.frame++; + const timeDiff = Date.now() - this.started; + if (timeDiff >= 1000) { + this.fps = this.frame / (timeDiff / 1000); + this.frame = 0; + this.started = Date.now(); + } + // Clear the canvas + this.context.fillStyle = "#000000"; + this.context.fillRect(0, 0, width, height); + // Render the bodies + this.context.strokeStyle = "#FFFFFF"; + this.context.beginPath(); + this.test.physics.draw(this.context); + this.context.stroke(); + // Render the BVH + if (this.bvhCheckbox.checked) { + this.context.strokeStyle = "#00FF00"; + this.context.beginPath(); + this.test.physics.drawBVH(this.context); + this.context.stroke(); + } + // Render the FPS + this.context.fillStyle = "#FFCC00"; + this.context.fillText(`FPS: ${this.fps ? this.fps.toFixed(0) : "?"}`, 24, 48); + if (this.test.drawCallback) { + this.test.drawCallback(); + } } - // Clear the canvas - this.context.fillStyle = "#000000"; - this.context.fillRect(0, 0, width, height); - // Render the bodies - this.context.strokeStyle = "#FFFFFF"; - this.context.beginPath(); - this.test.physics.draw(this.context); - this.context.stroke(); - // Render the BVH - if (this.bvhCheckbox.checked) { - this.context.strokeStyle = "#00FF00"; - this.context.beginPath(); - this.test.physics.drawBVH(this.context); - this.context.stroke(); - } - // Render the FPS - this.context.fillStyle = "#FFCC00"; - this.context.fillText( - `FPS: ${this.fps ? this.fps.toFixed(0) : "?"}`, - 24, - 48, - ); - if (this.test.drawCallback) { - this.test.drawCallback(); - } - } } function loop(callback) { - // interval for fps instead of setTimeout - // and ms = 1 which is lowest nonzero value - // for responsiveness of user input - setInterval(callback, 1); + // interval for fps instead of setTimeout + // and ms = 1 which is lowest nonzero value + // for responsiveness of user input + setInterval(callback, 1); } module.exports.TestCanvas = TestCanvas; module.exports.loop = loop; diff --git a/docs/demo/demo.js b/docs/demo/demo.js index a5e860bc..1678a7a2 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -1,902 +1,791 @@ -/******/ (() => { - // webpackBootstrap - /******/ var __webpack_modules__ = { - /***/ "./node_modules/.pnpm/json-stringify-safe@5.0.1/node_modules/json-stringify-safe/stringify.js": - /*!****************************************************************************************************!*\ - !*** ./node_modules/.pnpm/json-stringify-safe@5.0.1/node_modules/json-stringify-safe/stringify.js ***! - \****************************************************************************************************/ - /***/ (module, exports) => { - exports = module.exports = stringify; - exports.getSerialize = serializer; - - function stringify(obj, replacer, spaces, cycleReplacer) { - return JSON.stringify( - obj, - serializer(replacer, cycleReplacer), - spaces, - ); - } +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ - function serializer(replacer, cycleReplacer) { - var stack = [], - keys = []; - - if (cycleReplacer == null) - cycleReplacer = function (key, value) { - if (stack[0] === value) return "[Circular ~]"; - return ( - "[Circular ~." + - keys.slice(0, stack.indexOf(value)).join(".") + - "]" - ); - }; - - return function (key, value) { - if (stack.length > 0) { - var thisPos = stack.indexOf(this); - ~thisPos ? stack.splice(thisPos + 1) : stack.push(this); - ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key); - if (~stack.indexOf(value)) - value = cycleReplacer.call(this, key, value); - } else stack.push(value); - - return replacer == null ? value : replacer.call(this, key, value); - }; - } +/***/ "./node_modules/json-stringify-safe/stringify.js": +/*!*******************************************************!*\ + !*** ./node_modules/json-stringify-safe/stringify.js ***! + \*******************************************************/ +/***/ ((module, exports) => { - /***/ - }, - - /***/ "./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js": - /*!****************************************************************************************************!*\ - !*** ./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js ***! - \****************************************************************************************************/ - /***/ ( - __unused_webpack_module, - __webpack_exports__, - __webpack_require__, - ) => { - "use strict"; - __webpack_require__.r(__webpack_exports__); - /* harmony export */ __webpack_require__.d(__webpack_exports__, { - /* harmony export */ decomp: () => /* binding */ decomp, - /* harmony export */ isSimple: () => /* binding */ isSimple, - /* harmony export */ makeCCW: () => /* binding */ makeCCW, - /* harmony export */ quickDecomp: () => /* binding */ quickDecomp, - /* harmony export */ removeCollinearPoints: () => - /* binding */ removeCollinearPoints, - /* harmony export */ removeDuplicatePoints: () => - /* binding */ removeDuplicatePoints, - /* harmony export */ - }); - const tmpPoint1 = [0, 0]; - const tmpPoint2 = [0, 0]; - const tmpLine1 = [ - [0, 0], - [0, 0], - ]; - const tmpLine2 = [ - [0, 0], - [0, 0], - ]; +exports = module.exports = stringify +exports.getSerialize = serializer - /** - * Compute the intersection between two lines. - * @param l1 Line vector 1 - * @param l2 Line vector 2 - * @param precision Precision to use when checking if the lines are parallel - * @return The intersection point. - */ - function lineInt(l1, l2, precision) { - if (precision === void 0) { - precision = 0; - } - precision = precision || 0; - const i = [0, 0]; // point - const a1 = l1[1][1] - l1[0][1]; - const b1 = l1[0][0] - l1[1][0]; - const c1 = a1 * l1[0][0] + b1 * l1[0][1]; - const a2 = l2[1][1] - l2[0][1]; - const b2 = l2[0][0] - l2[1][0]; - const c2 = a2 * l2[0][0] + b2 * l2[0][1]; - const det = a1 * b2 - a2 * b1; - if (!scalarsEqual(det, 0, precision)) { - // lines are not parallel - i[0] = (b2 * c1 - b1 * c2) / det; - i[1] = (a1 * c2 - a2 * c1) / det; - } - return i; - } +function stringify(obj, replacer, spaces, cycleReplacer) { + return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces) +} - /** - * Checks if two line segments intersects. - * @param p1 The start vertex of the first line segment. - * @param p2 The end vertex of the first line segment. - * @param q1 The start vertex of the second line segment. - * @param q2 The end vertex of the second line segment. - * @return True if the two line segments intersect - */ - function lineSegmentsIntersect(p1, p2, q1, q2) { - const dx = p2[0] - p1[0]; - const dy = p2[1] - p1[1]; - const da = q2[0] - q1[0]; - const db = q2[1] - q1[1]; - - // segments are parallel - if (da * dy - db * dx === 0) { - return false; - } - const s = - (dx * (q1[1] - p1[1]) + dy * (p1[0] - q1[0])) / (da * dy - db * dx); - const t = - (da * (p1[1] - q1[1]) + db * (q1[0] - p1[0])) / (db * dx - da * dy); - return s >= 0 && s <= 1 && t >= 0 && t <= 1; - } +function serializer(replacer, cycleReplacer) { + var stack = [], keys = [] - /** - * Get the area of a triangle spanned by the three given points. Note that the area will be negative if the points are not given in counter-clockwise order. - * @param a point 1 - * @param b point 2 - * @param c point 3 - * @return the area of a triangle spanned by the three given points - */ - function triangleArea(a, b, c) { - return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); - } - function isLeft(a, b, c) { - return triangleArea(a, b, c) > 0; - } - function isLeftOn(a, b, c) { - return triangleArea(a, b, c) >= 0; - } - function isRight(a, b, c) { - return triangleArea(a, b, c) < 0; - } - function isRightOn(a, b, c) { - return triangleArea(a, b, c) <= 0; - } + if (cycleReplacer == null) cycleReplacer = function(key, value) { + if (stack[0] === value) return "[Circular ~]" + return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]" + } - /** - * Check if three points are collinear - * @param a point 1 - * @param b point 2 - * @param c point 3 - * @param thresholdAngle angle to use when comparing the vectors. The function will return true if the angle between the resulting vectors is less than this value. Use zero for max precision. - * @return whether the points are collinear - */ - function collinear(a, b, c, thresholdAngle) { - if (thresholdAngle === void 0) { - thresholdAngle = 0; - } - if (!thresholdAngle) { - return triangleArea(a, b, c) === 0; - } else { - const ab = tmpPoint1; - const bc = tmpPoint2; - ab[0] = b[0] - a[0]; - ab[1] = b[1] - a[1]; - bc[0] = c[0] - b[0]; - bc[1] = c[1] - b[1]; - const dot = ab[0] * bc[0] + ab[1] * bc[1]; - const magA = Math.sqrt(ab[0] * ab[0] + ab[1] * ab[1]); - const magB = Math.sqrt(bc[0] * bc[0] + bc[1] * bc[1]); - const angle = Math.acos(dot / (magA * magB)); - return angle < thresholdAngle; - } - } - function sqdist(a, b) { - const dx = b[0] - a[0]; - const dy = b[1] - a[1]; - return dx * dx + dy * dy; - } + return function(key, value) { + if (stack.length > 0) { + var thisPos = stack.indexOf(this) + ~thisPos ? stack.splice(thisPos + 1) : stack.push(this) + ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key) + if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value) + } + else stack.push(value) - /** - * Get a vertex at position i. It does not matter if i is out of bounds, this function will just cycle. - * @param i vertex position - * @return vertex at position i - */ - function polygonAt(polygon, i) { - const s = polygon.length; - return polygon[i < 0 ? (i % s) + s : i % s]; - } + return replacer == null ? value : replacer.call(this, key, value) + } +} + + +/***/ }), + +/***/ "./node_modules/poly-decomp-es/dist/poly-decomp-es.js": +/*!************************************************************!*\ + !*** ./node_modules/poly-decomp-es/dist/poly-decomp-es.js ***! + \************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ decomp: () => (/* binding */ decomp), +/* harmony export */ isSimple: () => (/* binding */ isSimple), +/* harmony export */ makeCCW: () => (/* binding */ makeCCW), +/* harmony export */ quickDecomp: () => (/* binding */ quickDecomp), +/* harmony export */ removeCollinearPoints: () => (/* binding */ removeCollinearPoints), +/* harmony export */ removeDuplicatePoints: () => (/* binding */ removeDuplicatePoints) +/* harmony export */ }); +const tmpPoint1 = [0, 0]; +const tmpPoint2 = [0, 0]; +const tmpLine1 = [[0, 0], [0, 0]]; +const tmpLine2 = [[0, 0], [0, 0]]; + +/** + * Compute the intersection between two lines. + * @param l1 Line vector 1 + * @param l2 Line vector 2 + * @param precision Precision to use when checking if the lines are parallel + * @return The intersection point. + */ +function lineInt(l1, l2, precision) { + if (precision === void 0) { + precision = 0; + } + precision = precision || 0; + const i = [0, 0]; // point + const a1 = l1[1][1] - l1[0][1]; + const b1 = l1[0][0] - l1[1][0]; + const c1 = a1 * l1[0][0] + b1 * l1[0][1]; + const a2 = l2[1][1] - l2[0][1]; + const b2 = l2[0][0] - l2[1][0]; + const c2 = a2 * l2[0][0] + b2 * l2[0][1]; + const det = a1 * b2 - a2 * b1; + if (!scalarsEqual(det, 0, precision)) { + // lines are not parallel + i[0] = (b2 * c1 - b1 * c2) / det; + i[1] = (a1 * c2 - a2 * c1) / det; + } + return i; +} + +/** + * Checks if two line segments intersects. + * @param p1 The start vertex of the first line segment. + * @param p2 The end vertex of the first line segment. + * @param q1 The start vertex of the second line segment. + * @param q2 The end vertex of the second line segment. + * @return True if the two line segments intersect + */ +function lineSegmentsIntersect(p1, p2, q1, q2) { + const dx = p2[0] - p1[0]; + const dy = p2[1] - p1[1]; + const da = q2[0] - q1[0]; + const db = q2[1] - q1[1]; + + // segments are parallel + if (da * dy - db * dx === 0) { + return false; + } + const s = (dx * (q1[1] - p1[1]) + dy * (p1[0] - q1[0])) / (da * dy - db * dx); + const t = (da * (p1[1] - q1[1]) + db * (q1[0] - p1[0])) / (db * dx - da * dy); + return s >= 0 && s <= 1 && t >= 0 && t <= 1; +} + +/** + * Get the area of a triangle spanned by the three given points. Note that the area will be negative if the points are not given in counter-clockwise order. + * @param a point 1 + * @param b point 2 + * @param c point 3 + * @return the area of a triangle spanned by the three given points + */ +function triangleArea(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); +} +function isLeft(a, b, c) { + return triangleArea(a, b, c) > 0; +} +function isLeftOn(a, b, c) { + return triangleArea(a, b, c) >= 0; +} +function isRight(a, b, c) { + return triangleArea(a, b, c) < 0; +} +function isRightOn(a, b, c) { + return triangleArea(a, b, c) <= 0; +} + +/** + * Check if three points are collinear + * @param a point 1 + * @param b point 2 + * @param c point 3 + * @param thresholdAngle angle to use when comparing the vectors. The function will return true if the angle between the resulting vectors is less than this value. Use zero for max precision. + * @return whether the points are collinear + */ +function collinear(a, b, c, thresholdAngle) { + if (thresholdAngle === void 0) { + thresholdAngle = 0; + } + if (!thresholdAngle) { + return triangleArea(a, b, c) === 0; + } else { + const ab = tmpPoint1; + const bc = tmpPoint2; + ab[0] = b[0] - a[0]; + ab[1] = b[1] - a[1]; + bc[0] = c[0] - b[0]; + bc[1] = c[1] - b[1]; + const dot = ab[0] * bc[0] + ab[1] * bc[1]; + const magA = Math.sqrt(ab[0] * ab[0] + ab[1] * ab[1]); + const magB = Math.sqrt(bc[0] * bc[0] + bc[1] * bc[1]); + const angle = Math.acos(dot / (magA * magB)); + return angle < thresholdAngle; + } +} +function sqdist(a, b) { + const dx = b[0] - a[0]; + const dy = b[1] - a[1]; + return dx * dx + dy * dy; +} + +/** + * Get a vertex at position i. It does not matter if i is out of bounds, this function will just cycle. + * @param i vertex position + * @return vertex at position i + */ +function polygonAt(polygon, i) { + const s = polygon.length; + return polygon[i < 0 ? i % s + s : i % s]; +} + +/** + * Clear the polygon data + */ +function polygonClear(polygon) { + polygon.length = 0; +} + +/** + * Append points "from" to "to" -1 from an other polygon "poly" onto this one. + * @param polygon the polygon to append to + * @param poly The polygon to get points from. + * @param from The vertex index in "poly". + * @param to The end vertex index in "poly". Note that this vertex is NOT included when appending. + */ +function polygonAppend(polygon, poly, from, to) { + for (let i = from; i < to; i++) { + polygon.push(poly[i]); + } +} + +/** + * Make sure that the polygon vertices are ordered counter-clockwise. + */ +function makeCCW(polygon) { + let br = 0; + const v = polygon; + + // find bottom right point + for (let i = 1; i < polygon.length; ++i) { + if (v[i][1] < v[br][1] || v[i][1] === v[br][1] && v[i][0] > v[br][0]) { + br = i; + } + } - /** - * Clear the polygon data - */ - function polygonClear(polygon) { - polygon.length = 0; - } + // reverse poly if clockwise + if (!isLeft(polygonAt(polygon, br - 1), polygonAt(polygon, br), polygonAt(polygon, br + 1))) { + polygonReverse(polygon); + return true; + } else { + return false; + } +} + +/** + * Reverse the vertices in the polygon + */ +function polygonReverse(polygon) { + const tmp = []; + const N = polygon.length; + for (let i = 0; i !== N; i++) { + tmp.push(polygon.pop()); + } + for (let i = 0; i !== N; i++) { + polygon[i] = tmp[i]; + } +} + +/** + * Check if a point in the polygon is a reflex point + * @param i the point in the polygon to check + * @return whether the given point in the polygon is a reflex point + */ +function polygonIsReflex(polygon, i) { + return isRight(polygonAt(polygon, i - 1), polygonAt(polygon, i), polygonAt(polygon, i + 1)); +} + +/** + * Check if two vertices in the polygon can see each other + * @param a vertex index 1 + * @param b vertex index 2 + * @return whether two vertices in the polygon can see each other + */ +function polygonCanSee(polygon, a, b) { + const l1 = tmpLine1; + const l2 = tmpLine2; + if (isLeftOn(polygonAt(polygon, a + 1), polygonAt(polygon, a), polygonAt(polygon, b)) && isRightOn(polygonAt(polygon, a - 1), polygonAt(polygon, a), polygonAt(polygon, b))) { + return false; + } + const dist = sqdist(polygonAt(polygon, a), polygonAt(polygon, b)); + for (let i = 0; i !== polygon.length; ++i) { + // for each edge + if ((i + 1) % polygon.length === a || i === a) { + // ignore incident edges + continue; + } + if (isLeftOn(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i + 1)) && isRightOn(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i))) { + // if diag intersects an edge + l1[0] = polygonAt(polygon, a); + l1[1] = polygonAt(polygon, b); + l2[0] = polygonAt(polygon, i); + l2[1] = polygonAt(polygon, i + 1); + const p = lineInt(l1, l2); + if (sqdist(polygonAt(polygon, a), p) < dist) { + // if edge is blocking visibility to b + return false; + } + } + } + return true; +} + +/** + * Check if two vertices in the polygon can see each other + * @param a vertex index 1 + * @param b vertex index 2 + * @return if two vertices in the polygon can see each other + */ +function polygonCanSee2(polygon, a, b) { + // for each edge + for (let i = 0; i !== polygon.length; ++i) { + // ignore incident edges + if (i === a || i === b || (i + 1) % polygon.length === a || (i + 1) % polygon.length === b) { + continue; + } + if (lineSegmentsIntersect(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i), polygonAt(polygon, i + 1))) { + return false; + } + } + return true; +} + +/** + * Copy the polygon from vertex i to vertex j. + * @param i the start vertex to copy from + * @param j the end vertex to copy from + * @param targetPoly optional target polygon to save in. + * @return the resulting copy. + */ +function polygonCopy(polygon, i, j, targetPoly) { + if (targetPoly === void 0) { + targetPoly = []; + } + polygonClear(targetPoly); + if (i < j) { + // Insert all vertices from i to j + for (let k = i; k <= j; k++) { + targetPoly.push(polygon[k]); + } + } else { + // Insert vertices 0 to j + for (let k = 0; k <= j; k++) { + targetPoly.push(polygon[k]); + } - /** - * Append points "from" to "to" -1 from an other polygon "poly" onto this one. - * @param polygon the polygon to append to - * @param poly The polygon to get points from. - * @param from The vertex index in "poly". - * @param to The end vertex index in "poly". Note that this vertex is NOT included when appending. - */ - function polygonAppend(polygon, poly, from, to) { - for (let i = from; i < to; i++) { - polygon.push(poly[i]); + // Insert vertices i to end + for (let k = i; k < polygon.length; k++) { + targetPoly.push(polygon[k]); + } + } + return targetPoly; +} + +/** + * Decomposes the polygon into convex pieces. Returns a list of edges [[p1,p2],[p2,p3],...] that cuts the polygon. + * Note that this algorithm has complexity O(N^4) and will be very slow for polygons with many vertices. + * @return a list of edges that cuts the polygon + */ +function getCutEdges(polygon) { + let min = []; + let tmp1; + let tmp2; + const tmpPoly = []; + let nDiags = Number.MAX_VALUE; + for (let i = 0; i < polygon.length; ++i) { + if (polygonIsReflex(polygon, i)) { + for (let j = 0; j < polygon.length; ++j) { + if (polygonCanSee(polygon, i, j)) { + tmp1 = getCutEdges(polygonCopy(polygon, i, j, tmpPoly)); + tmp2 = getCutEdges(polygonCopy(polygon, j, i, tmpPoly)); + for (let k = 0; k < tmp2.length; k++) { + tmp1.push(tmp2[k]); + } + if (tmp1.length < nDiags) { + min = tmp1; + nDiags = tmp1.length; + min.push([polygonAt(polygon, i), polygonAt(polygon, j)]); } } + } + } + } + return min; +} + +/** + * Decomposes the polygon into one or more convex sub-Polygons. + * @return An array of Polygon objects, or false if decomposition fails + */ +function decomp(polygon) { + const edges = getCutEdges(polygon); + if (edges.length > 0) { + return slicePolygon(polygon, edges); + } else { + return [polygon]; + } +} + +/** + * Slices the polygon given one or more cut edges. If given one, this function will return two polygons (false on failure). If many, an array of polygons. + * @param cutEdges A list of edges, as returned by .getCutEdges() + * @return the sliced polygons, or false if the operation was unsuccessful + */ +function slicePolygon(polygon, cutEdges) { + if (cutEdges.length === 0) { + return [polygon]; + } - /** - * Make sure that the polygon vertices are ordered counter-clockwise. - */ - function makeCCW(polygon) { - let br = 0; - const v = polygon; - - // find bottom right point - for (let i = 1; i < polygon.length; ++i) { - if ( - v[i][1] < v[br][1] || - (v[i][1] === v[br][1] && v[i][0] > v[br][0]) - ) { - br = i; - } - } - - // reverse poly if clockwise - if ( - !isLeft( - polygonAt(polygon, br - 1), - polygonAt(polygon, br), - polygonAt(polygon, br + 1), - ) - ) { - polygonReverse(polygon); - return true; - } else { - return false; - } + // if given multiple edges + if (cutEdges instanceof Array && cutEdges.length && cutEdges[0] instanceof Array && cutEdges[0].length === 2 && cutEdges[0][0] instanceof Array) { + const polys = [polygon]; + for (let i = 0; i < cutEdges.length; i++) { + const cutEdge = cutEdges[i]; + // Cut all polys + for (let j = 0; j < polys.length; j++) { + const poly = polys[j]; + const result = slicePolygon(poly, cutEdge); + if (result) { + // Found poly! Cut and quit + polys.splice(j, 1); + polys.push(result[0], result[1]); + break; } + } + } + return polys; + } else { + // Was given one edge + const cutEdge = cutEdges; + const i = polygon.indexOf(cutEdge[0]); + const j = polygon.indexOf(cutEdge[1]); + if (i !== -1 && j !== -1) { + return [polygonCopy(polygon, i, j), polygonCopy(polygon, j, i)]; + } else { + return false; + } + } +} + +/** + * Checks that the line segments of this polygon do not intersect each other. + * @param polygon An array of vertices e.g. [[0,0],[0,1],...] + * @return whether line segments of this polygon do not intersect each other. + * @todo Should it check all segments with all others? + */ +function isSimple(polygon) { + const path = polygon; + let i; + + // Check + for (i = 0; i < path.length - 1; i++) { + for (let j = 0; j < i - 1; j++) { + if (lineSegmentsIntersect(path[i], path[i + 1], path[j], path[j + 1])) { + return false; + } + } + } - /** - * Reverse the vertices in the polygon - */ - function polygonReverse(polygon) { - const tmp = []; - const N = polygon.length; - for (let i = 0; i !== N; i++) { - tmp.push(polygon.pop()); - } - for (let i = 0; i !== N; i++) { - polygon[i] = tmp[i]; + // Check the segment between the last and the first point to all others + for (i = 1; i < path.length - 2; i++) { + if (lineSegmentsIntersect(path[0], path[path.length - 1], path[i], path[i + 1])) { + return false; + } + } + return true; +} +function getIntersectionPoint(p1, p2, q1, q2, delta) { + if (delta === void 0) { + delta = 0; + } + const a1 = p2[1] - p1[1]; + const b1 = p1[0] - p2[0]; + const c1 = a1 * p1[0] + b1 * p1[1]; + const a2 = q2[1] - q1[1]; + const b2 = q1[0] - q2[0]; + const c2 = a2 * q1[0] + b2 * q1[1]; + const det = a1 * b2 - a2 * b1; + if (!scalarsEqual(det, 0, delta)) { + return [(b2 * c1 - b1 * c2) / det, (a1 * c2 - a2 * c1) / det]; + } else { + return [0, 0]; + } +} + +/** + * Quickly decompose the Polygon into convex sub-polygons. + * @param polygon the polygon to decompose + * @param result + * @param reflexVertices + * @param steinerPoints + * @param delta + * @param maxlevel + * @param level + * @return the decomposed sub-polygons + */ +function quickDecomp(polygon, result, reflexVertices, steinerPoints, delta, maxlevel, level) { + if (result === void 0) { + result = []; + } + if (reflexVertices === void 0) { + reflexVertices = []; + } + if (steinerPoints === void 0) { + steinerPoints = []; + } + if (delta === void 0) { + delta = 25; + } + if (maxlevel === void 0) { + maxlevel = 100; + } + if (level === void 0) { + level = 0; + } + // Points + let upperInt = [0, 0]; + let lowerInt = [0, 0]; + let p = [0, 0]; + + // scalars + let upperDist = 0; + let lowerDist = 0; + let d = 0; + let closestDist = 0; + + // Integers + let upperIndex = 0; + let lowerIndex = 0; + let closestIndex = 0; + + // polygons + const lowerPoly = []; + const upperPoly = []; + const poly = polygon; + const v = polygon; + if (v.length < 3) { + return result; + } + level++; + if (level > maxlevel) { + console.warn('quickDecomp: max level (' + maxlevel + ') reached.'); + return result; + } + for (let i = 0; i < polygon.length; ++i) { + if (polygonIsReflex(poly, i)) { + reflexVertices.push(poly[i]); + upperDist = lowerDist = Number.MAX_VALUE; + for (let j = 0; j < polygon.length; ++j) { + if (isLeft(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) && isRightOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j - 1))) { + // if line intersects with an edge + p = getIntersectionPoint(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j), polygonAt(poly, j - 1)); // find the point of intersection + if (isRight(polygonAt(poly, i + 1), polygonAt(poly, i), p)) { + // make sure it's inside the poly + d = sqdist(poly[i], p); + if (d < lowerDist) { + // keep only the closest intersection + lowerDist = d; + lowerInt = p; + lowerIndex = j; + } } } - - /** - * Check if a point in the polygon is a reflex point - * @param i the point in the polygon to check - * @return whether the given point in the polygon is a reflex point - */ - function polygonIsReflex(polygon, i) { - return isRight( - polygonAt(polygon, i - 1), - polygonAt(polygon, i), - polygonAt(polygon, i + 1), - ); - } - - /** - * Check if two vertices in the polygon can see each other - * @param a vertex index 1 - * @param b vertex index 2 - * @return whether two vertices in the polygon can see each other - */ - function polygonCanSee(polygon, a, b) { - const l1 = tmpLine1; - const l2 = tmpLine2; - if ( - isLeftOn( - polygonAt(polygon, a + 1), - polygonAt(polygon, a), - polygonAt(polygon, b), - ) && - isRightOn( - polygonAt(polygon, a - 1), - polygonAt(polygon, a), - polygonAt(polygon, b), - ) - ) { - return false; - } - const dist = sqdist(polygonAt(polygon, a), polygonAt(polygon, b)); - for (let i = 0; i !== polygon.length; ++i) { - // for each edge - if ((i + 1) % polygon.length === a || i === a) { - // ignore incident edges - continue; - } - if ( - isLeftOn( - polygonAt(polygon, a), - polygonAt(polygon, b), - polygonAt(polygon, i + 1), - ) && - isRightOn( - polygonAt(polygon, a), - polygonAt(polygon, b), - polygonAt(polygon, i), - ) - ) { - // if diag intersects an edge - l1[0] = polygonAt(polygon, a); - l1[1] = polygonAt(polygon, b); - l2[0] = polygonAt(polygon, i); - l2[1] = polygonAt(polygon, i + 1); - const p = lineInt(l1, l2); - if (sqdist(polygonAt(polygon, a), p) < dist) { - // if edge is blocking visibility to b - return false; - } + if (isLeft(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j + 1)) && isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))) { + p = getIntersectionPoint(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j), polygonAt(poly, j + 1)); + if (isLeft(polygonAt(poly, i - 1), polygonAt(poly, i), p)) { + d = sqdist(poly[i], p); + if (d < upperDist) { + upperDist = d; + upperInt = p; + upperIndex = j; } } - return true; } + } - /** - * Check if two vertices in the polygon can see each other - * @param a vertex index 1 - * @param b vertex index 2 - * @return if two vertices in the polygon can see each other - */ - function polygonCanSee2(polygon, a, b) { - // for each edge - for (let i = 0; i !== polygon.length; ++i) { - // ignore incident edges - if ( - i === a || - i === b || - (i + 1) % polygon.length === a || - (i + 1) % polygon.length === b - ) { - continue; - } - if ( - lineSegmentsIntersect( - polygonAt(polygon, a), - polygonAt(polygon, b), - polygonAt(polygon, i), - polygonAt(polygon, i + 1), - ) - ) { - return false; + // if there are no vertices to connect to, choose a point in the middle + if (lowerIndex === (upperIndex + 1) % polygon.length) { + p[0] = (lowerInt[0] + upperInt[0]) / 2; + p[1] = (lowerInt[1] + upperInt[1]) / 2; + steinerPoints.push(p); + if (i < upperIndex) { + polygonAppend(lowerPoly, poly, i, upperIndex + 1); + lowerPoly.push(p); + upperPoly.push(p); + if (lowerIndex !== 0) { + polygonAppend(upperPoly, poly, lowerIndex, poly.length); + } + polygonAppend(upperPoly, poly, 0, i + 1); + } else { + if (i !== 0) { + polygonAppend(lowerPoly, poly, i, poly.length); + } + polygonAppend(lowerPoly, poly, 0, upperIndex + 1); + lowerPoly.push(p); + upperPoly.push(p); + polygonAppend(upperPoly, poly, lowerIndex, i + 1); + } + } else { + // connect to the closest point within the triangle + if (lowerIndex > upperIndex) { + upperIndex += polygon.length; + } + closestDist = Number.MAX_VALUE; + if (upperIndex < lowerIndex) { + return result; + } + for (let j = lowerIndex; j <= upperIndex; ++j) { + if (isLeftOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) && isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))) { + d = sqdist(polygonAt(poly, i), polygonAt(poly, j)); + if (d < closestDist && polygonCanSee2(poly, i, j)) { + closestDist = d; + closestIndex = j % polygon.length; } } - return true; } + if (i < closestIndex) { + polygonAppend(lowerPoly, poly, i, closestIndex + 1); + if (closestIndex !== 0) { + polygonAppend(upperPoly, poly, closestIndex, v.length); + } + polygonAppend(upperPoly, poly, 0, i + 1); + } else { + if (i !== 0) { + polygonAppend(lowerPoly, poly, i, v.length); + } + polygonAppend(lowerPoly, poly, 0, closestIndex + 1); + polygonAppend(upperPoly, poly, closestIndex, i + 1); + } + } - /** - * Copy the polygon from vertex i to vertex j. - * @param i the start vertex to copy from - * @param j the end vertex to copy from - * @param targetPoly optional target polygon to save in. - * @return the resulting copy. - */ - function polygonCopy(polygon, i, j, targetPoly) { - if (targetPoly === void 0) { - targetPoly = []; - } - polygonClear(targetPoly); - if (i < j) { - // Insert all vertices from i to j - for (let k = i; k <= j; k++) { - targetPoly.push(polygon[k]); - } - } else { - // Insert vertices 0 to j - for (let k = 0; k <= j; k++) { - targetPoly.push(polygon[k]); - } + // solve smallest poly first + if (lowerPoly.length < upperPoly.length) { + quickDecomp(lowerPoly, result, reflexVertices, steinerPoints, delta, maxlevel, level); + quickDecomp(upperPoly, result, reflexVertices, steinerPoints, delta, maxlevel, level); + } else { + quickDecomp(upperPoly, result, reflexVertices, steinerPoints, delta, maxlevel, level); + quickDecomp(lowerPoly, result, reflexVertices, steinerPoints, delta, maxlevel, level); + } + return result; + } + } + result.push(polygon); + return result; +} + +/** + * Remove collinear points in the polygon. + * @param thresholdAngle The threshold angle to use when determining whether two edges are collinear. Use zero for finest precision. + * @return The number of points removed + */ +function removeCollinearPoints(polygon, thresholdAngle) { + if (thresholdAngle === void 0) { + thresholdAngle = 0; + } + let num = 0; + for (let i = polygon.length - 1; polygon.length > 3 && i >= 0; --i) { + if (collinear(polygonAt(polygon, i - 1), polygonAt(polygon, i), polygonAt(polygon, i + 1), thresholdAngle)) { + // Remove the middle point + polygon.splice(i % polygon.length, 1); + num++; + } + } + return num; +} + +/** + * Check if two scalars are equal + * @param a scalar a + * @param b scalar b + * @param precision the precision for the equality check + * @return whether the two scalars are equal with the given precision + */ +function scalarsEqual(a, b, precision) { + if (precision === void 0) { + precision = 0; + } + precision = precision || 0; + return Math.abs(a - b) <= precision; +} + +/** + * Check if two points are equal + * @param a point a + * @param b point b + * @param precision the precision for the equality check + * @return if the two points are equal + */ +function pointsEqual(a, b, precision) { + if (precision === void 0) { + precision = 0; + } + return scalarsEqual(a[0], b[0], precision) && scalarsEqual(a[1], b[1], precision); +} + +/** + * Remove duplicate points in the polygon. + * @param precision The threshold to use when determining whether two points are the same. Use zero for best precision. + */ +function removeDuplicatePoints(polygon, precision) { + if (precision === void 0) { + precision = 0; + } + for (let i = polygon.length - 1; i >= 1; --i) { + const pi = polygon[i]; + for (let j = i - 1; j >= 0; --j) { + if (pointsEqual(pi, polygon[j], precision)) { + polygon.splice(i, 1); + continue; + } + } + } +} - // Insert vertices i to end - for (let k = i; k < polygon.length; k++) { - targetPoly.push(polygon[k]); - } - } - return targetPoly; - } - /** - * Decomposes the polygon into convex pieces. Returns a list of edges [[p1,p2],[p2,p3],...] that cuts the polygon. - * Note that this algorithm has complexity O(N^4) and will be very slow for polygons with many vertices. - * @return a list of edges that cuts the polygon - */ - function getCutEdges(polygon) { - let min = []; - let tmp1; - let tmp2; - const tmpPoly = []; - let nDiags = Number.MAX_VALUE; - for (let i = 0; i < polygon.length; ++i) { - if (polygonIsReflex(polygon, i)) { - for (let j = 0; j < polygon.length; ++j) { - if (polygonCanSee(polygon, i, j)) { - tmp1 = getCutEdges(polygonCopy(polygon, i, j, tmpPoly)); - tmp2 = getCutEdges(polygonCopy(polygon, j, i, tmpPoly)); - for (let k = 0; k < tmp2.length; k++) { - tmp1.push(tmp2[k]); - } - if (tmp1.length < nDiags) { - min = tmp1; - nDiags = tmp1.length; - min.push([polygonAt(polygon, i), polygonAt(polygon, j)]); - } - } - } - } - } - return min; - } - /** - * Decomposes the polygon into one or more convex sub-Polygons. - * @return An array of Polygon objects, or false if decomposition fails - */ - function decomp(polygon) { - const edges = getCutEdges(polygon); - if (edges.length > 0) { - return slicePolygon(polygon, edges); - } else { - return [polygon]; - } - } - /** - * Slices the polygon given one or more cut edges. If given one, this function will return two polygons (false on failure). If many, an array of polygons. - * @param cutEdges A list of edges, as returned by .getCutEdges() - * @return the sliced polygons, or false if the operation was unsuccessful - */ - function slicePolygon(polygon, cutEdges) { - if (cutEdges.length === 0) { - return [polygon]; - } +/***/ }), - // if given multiple edges - if ( - cutEdges instanceof Array && - cutEdges.length && - cutEdges[0] instanceof Array && - cutEdges[0].length === 2 && - cutEdges[0][0] instanceof Array - ) { - const polys = [polygon]; - for (let i = 0; i < cutEdges.length; i++) { - const cutEdge = cutEdges[i]; - // Cut all polys - for (let j = 0; j < polys.length; j++) { - const poly = polys[j]; - const result = slicePolygon(poly, cutEdge); - if (result) { - // Found poly! Cut and quit - polys.splice(j, 1); - polys.push(result[0], result[1]); - break; - } - } - } - return polys; - } else { - // Was given one edge - const cutEdge = cutEdges; - const i = polygon.indexOf(cutEdge[0]); - const j = polygon.indexOf(cutEdge[1]); - if (i !== -1 && j !== -1) { - return [polygonCopy(polygon, i, j), polygonCopy(polygon, j, i)]; - } else { - return false; - } - } - } +/***/ "./node_modules/quickselect/index.js": +/*!*******************************************!*\ + !*** ./node_modules/quickselect/index.js ***! + \*******************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - /** - * Checks that the line segments of this polygon do not intersect each other. - * @param polygon An array of vertices e.g. [[0,0],[0,1],...] - * @return whether line segments of this polygon do not intersect each other. - * @todo Should it check all segments with all others? - */ - function isSimple(polygon) { - const path = polygon; - let i; - - // Check - for (i = 0; i < path.length - 1; i++) { - for (let j = 0; j < i - 1; j++) { - if ( - lineSegmentsIntersect( - path[i], - path[i + 1], - path[j], - path[j + 1], - ) - ) { - return false; - } - } - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ quickselect) +/* harmony export */ }); - // Check the segment between the last and the first point to all others - for (i = 1; i < path.length - 2; i++) { - if ( - lineSegmentsIntersect( - path[0], - path[path.length - 1], - path[i], - path[i + 1], - ) - ) { - return false; - } - } - return true; - } - function getIntersectionPoint(p1, p2, q1, q2, delta) { - if (delta === void 0) { - delta = 0; - } - const a1 = p2[1] - p1[1]; - const b1 = p1[0] - p2[0]; - const c1 = a1 * p1[0] + b1 * p1[1]; - const a2 = q2[1] - q1[1]; - const b2 = q1[0] - q2[0]; - const c2 = a2 * q1[0] + b2 * q1[1]; - const det = a1 * b2 - a2 * b1; - if (!scalarsEqual(det, 0, delta)) { - return [(b2 * c1 - b1 * c2) / det, (a1 * c2 - a2 * c1) / det]; - } else { - return [0, 0]; - } - } +function quickselect(arr, k, left, right, compare) { + quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare); +} - /** - * Quickly decompose the Polygon into convex sub-polygons. - * @param polygon the polygon to decompose - * @param result - * @param reflexVertices - * @param steinerPoints - * @param delta - * @param maxlevel - * @param level - * @return the decomposed sub-polygons - */ - function quickDecomp( - polygon, - result, - reflexVertices, - steinerPoints, - delta, - maxlevel, - level, - ) { - if (result === void 0) { - result = []; - } - if (reflexVertices === void 0) { - reflexVertices = []; - } - if (steinerPoints === void 0) { - steinerPoints = []; - } - if (delta === void 0) { - delta = 25; - } - if (maxlevel === void 0) { - maxlevel = 100; - } - if (level === void 0) { - level = 0; - } - // Points - let upperInt = [0, 0]; - let lowerInt = [0, 0]; - let p = [0, 0]; - - // scalars - let upperDist = 0; - let lowerDist = 0; - let d = 0; - let closestDist = 0; - - // Integers - let upperIndex = 0; - let lowerIndex = 0; - let closestIndex = 0; - - // polygons - const lowerPoly = []; - const upperPoly = []; - const poly = polygon; - const v = polygon; - if (v.length < 3) { - return result; - } - level++; - if (level > maxlevel) { - console.warn("quickDecomp: max level (" + maxlevel + ") reached."); - return result; - } - for (let i = 0; i < polygon.length; ++i) { - if (polygonIsReflex(poly, i)) { - reflexVertices.push(poly[i]); - upperDist = lowerDist = Number.MAX_VALUE; - for (let j = 0; j < polygon.length; ++j) { - if ( - isLeft( - polygonAt(poly, i - 1), - polygonAt(poly, i), - polygonAt(poly, j), - ) && - isRightOn( - polygonAt(poly, i - 1), - polygonAt(poly, i), - polygonAt(poly, j - 1), - ) - ) { - // if line intersects with an edge - p = getIntersectionPoint( - polygonAt(poly, i - 1), - polygonAt(poly, i), - polygonAt(poly, j), - polygonAt(poly, j - 1), - ); // find the point of intersection - if (isRight(polygonAt(poly, i + 1), polygonAt(poly, i), p)) { - // make sure it's inside the poly - d = sqdist(poly[i], p); - if (d < lowerDist) { - // keep only the closest intersection - lowerDist = d; - lowerInt = p; - lowerIndex = j; - } - } - } - if ( - isLeft( - polygonAt(poly, i + 1), - polygonAt(poly, i), - polygonAt(poly, j + 1), - ) && - isRightOn( - polygonAt(poly, i + 1), - polygonAt(poly, i), - polygonAt(poly, j), - ) - ) { - p = getIntersectionPoint( - polygonAt(poly, i + 1), - polygonAt(poly, i), - polygonAt(poly, j), - polygonAt(poly, j + 1), - ); - if (isLeft(polygonAt(poly, i - 1), polygonAt(poly, i), p)) { - d = sqdist(poly[i], p); - if (d < upperDist) { - upperDist = d; - upperInt = p; - upperIndex = j; - } - } - } - } - - // if there are no vertices to connect to, choose a point in the middle - if (lowerIndex === (upperIndex + 1) % polygon.length) { - p[0] = (lowerInt[0] + upperInt[0]) / 2; - p[1] = (lowerInt[1] + upperInt[1]) / 2; - steinerPoints.push(p); - if (i < upperIndex) { - polygonAppend(lowerPoly, poly, i, upperIndex + 1); - lowerPoly.push(p); - upperPoly.push(p); - if (lowerIndex !== 0) { - polygonAppend(upperPoly, poly, lowerIndex, poly.length); - } - polygonAppend(upperPoly, poly, 0, i + 1); - } else { - if (i !== 0) { - polygonAppend(lowerPoly, poly, i, poly.length); - } - polygonAppend(lowerPoly, poly, 0, upperIndex + 1); - lowerPoly.push(p); - upperPoly.push(p); - polygonAppend(upperPoly, poly, lowerIndex, i + 1); - } - } else { - // connect to the closest point within the triangle - if (lowerIndex > upperIndex) { - upperIndex += polygon.length; - } - closestDist = Number.MAX_VALUE; - if (upperIndex < lowerIndex) { - return result; - } - for (let j = lowerIndex; j <= upperIndex; ++j) { - if ( - isLeftOn( - polygonAt(poly, i - 1), - polygonAt(poly, i), - polygonAt(poly, j), - ) && - isRightOn( - polygonAt(poly, i + 1), - polygonAt(poly, i), - polygonAt(poly, j), - ) - ) { - d = sqdist(polygonAt(poly, i), polygonAt(poly, j)); - if (d < closestDist && polygonCanSee2(poly, i, j)) { - closestDist = d; - closestIndex = j % polygon.length; - } - } - } - if (i < closestIndex) { - polygonAppend(lowerPoly, poly, i, closestIndex + 1); - if (closestIndex !== 0) { - polygonAppend(upperPoly, poly, closestIndex, v.length); - } - polygonAppend(upperPoly, poly, 0, i + 1); - } else { - if (i !== 0) { - polygonAppend(lowerPoly, poly, i, v.length); - } - polygonAppend(lowerPoly, poly, 0, closestIndex + 1); - polygonAppend(upperPoly, poly, closestIndex, i + 1); - } - } - - // solve smallest poly first - if (lowerPoly.length < upperPoly.length) { - quickDecomp( - lowerPoly, - result, - reflexVertices, - steinerPoints, - delta, - maxlevel, - level, - ); - quickDecomp( - upperPoly, - result, - reflexVertices, - steinerPoints, - delta, - maxlevel, - level, - ); - } else { - quickDecomp( - upperPoly, - result, - reflexVertices, - steinerPoints, - delta, - maxlevel, - level, - ); - quickDecomp( - lowerPoly, - result, - reflexVertices, - steinerPoints, - delta, - maxlevel, - level, - ); - } - return result; - } - } - result.push(polygon); - return result; - } +function quickselectStep(arr, k, left, right, compare) { - /** - * Remove collinear points in the polygon. - * @param thresholdAngle The threshold angle to use when determining whether two edges are collinear. Use zero for finest precision. - * @return The number of points removed - */ - function removeCollinearPoints(polygon, thresholdAngle) { - if (thresholdAngle === void 0) { - thresholdAngle = 0; - } - let num = 0; - for (let i = polygon.length - 1; polygon.length > 3 && i >= 0; --i) { - if ( - collinear( - polygonAt(polygon, i - 1), - polygonAt(polygon, i), - polygonAt(polygon, i + 1), - thresholdAngle, - ) - ) { - // Remove the middle point - polygon.splice(i % polygon.length, 1); - num++; - } - } - return num; + while (right > left) { + if (right - left > 600) { + var n = right - left + 1; + var m = k - left + 1; + var z = Math.log(n); + var s = 0.5 * Math.exp(2 * z / 3); + var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); + var newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); + var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); + quickselectStep(arr, k, newLeft, newRight, compare); } - /** - * Check if two scalars are equal - * @param a scalar a - * @param b scalar b - * @param precision the precision for the equality check - * @return whether the two scalars are equal with the given precision - */ - function scalarsEqual(a, b, precision) { - if (precision === void 0) { - precision = 0; - } - precision = precision || 0; - return Math.abs(a - b) <= precision; - } + var t = arr[k]; + var i = left; + var j = right; - /** - * Check if two points are equal - * @param a point a - * @param b point b - * @param precision the precision for the equality check - * @return if the two points are equal - */ - function pointsEqual(a, b, precision) { - if (precision === void 0) { - precision = 0; - } - return ( - scalarsEqual(a[0], b[0], precision) && - scalarsEqual(a[1], b[1], precision) - ); - } + swap(arr, left, k); + if (compare(arr[right], t) > 0) swap(arr, left, right); - /** - * Remove duplicate points in the polygon. - * @param precision The threshold to use when determining whether two points are the same. Use zero for best precision. - */ - function removeDuplicatePoints(polygon, precision) { - if (precision === void 0) { - precision = 0; - } - for (let i = polygon.length - 1; i >= 1; --i) { - const pi = polygon[i]; - for (let j = i - 1; j >= 0; --j) { - if (pointsEqual(pi, polygon[j], precision)) { - polygon.splice(i, 1); - continue; - } - } - } + while (i < j) { + swap(arr, i, j); + i++; + j--; + while (compare(arr[i], t) < 0) i++; + while (compare(arr[j], t) > 0) j--; } - /***/ - }, + if (compare(arr[left], t) === 0) swap(arr, left, j); + else { + j++; + swap(arr, j, right); + } - /***/ "./node_modules/.pnpm/random-seed@0.3.0/node_modules/random-seed/index.js": - /*!********************************************************************************!*\ - !*** ./node_modules/.pnpm/random-seed@0.3.0/node_modules/random-seed/index.js ***! - \********************************************************************************/ - /***/ (module, __unused_webpack_exports, __webpack_require__) => { - "use strict"; - /* - * random-seed - * https://github.com/skratchdot/random-seed - * - * This code was originally written by Steve Gibson and can be found here: - * - * https://www.grc.com/otg/uheprng.htm - * - * It was slightly modified for use in node, to pass jshint, and a few additional - * helper functions were added. - * - * Copyright (c) 2013 skratchdot - * Dual Licensed under the MIT license and the original GRC copyright/license - * included below. - */ - /* ============================================================================ + if (j <= k) left = j + 1; + if (k <= j) right = j - 1; + } +} + +function swap(arr, i, j) { + var tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} + + +/***/ }), + +/***/ "./node_modules/random-seed/index.js": +/*!*******************************************!*\ + !*** ./node_modules/random-seed/index.js ***! + \*******************************************/ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* + * random-seed + * https://github.com/skratchdot/random-seed + * + * This code was originally written by Steve Gibson and can be found here: + * + * https://www.grc.com/otg/uheprng.htm + * + * It was slightly modified for use in node, to pass jshint, and a few additional + * helper functions were added. + * + * Copyright (c) 2013 skratchdot + * Dual Licensed under the MIT license and the original GRC copyright/license + * included below. + */ +/* ============================================================================ Gibson Research Corporation UHEPRNG - Ultra High Entropy Pseudo-Random Number Generator ============================================================================ @@ -935,2246 +824,1723 @@ 1460910 and 1768863. (We use the largest one that's < 2^21) ============================================================================ */ - var stringify = __webpack_require__( - /*! json-stringify-safe */ "./node_modules/.pnpm/json-stringify-safe@5.0.1/node_modules/json-stringify-safe/stringify.js", - ); +var stringify = __webpack_require__(/*! json-stringify-safe */ "./node_modules/json-stringify-safe/stringify.js"); - /* ============================================================================ +/* ============================================================================ This is based upon Johannes Baagoe's carefully designed and efficient hash function for use with JavaScript. It has a proven "avalanche" effect such that every bit of the input affects every bit of the output 50% of the time, which is good. See: http://baagoe.com/en/RandomMusings/hash/avalanche.xhtml ============================================================================ */ - var Mash = function () { - var n = 0xefc8249d; - var mash = function (data) { - if (data) { - data = data.toString(); - for (var i = 0; i < data.length; i++) { - n += data.charCodeAt(i); - var h = 0.02519603282416938 * n; - n = h >>> 0; - h -= n; - h *= n; - n = h >>> 0; - h -= n; - n += h * 0x100000000; // 2^32 - } - return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 - } else { - n = 0xefc8249d; - } - }; - return mash; - }; +var Mash = function () { + var n = 0xefc8249d; + var mash = function (data) { + if (data) { + data = data.toString(); + for (var i = 0; i < data.length; i++) { + n += data.charCodeAt(i); + var h = 0.02519603282416938 * n; + n = h >>> 0; + h -= n; + h *= n; + n = h >>> 0; + h -= n; + n += h * 0x100000000; // 2^32 + } + return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 + } else { + n = 0xefc8249d; + } + }; + return mash; +}; + +var uheprng = function (seed) { + return (function () { + var o = 48; // set the 'order' number of ENTROPY-holding 32-bit values + var c = 1; // init the 'carry' used by the multiply-with-carry (MWC) algorithm + var p = o; // init the 'phase' (max-1) of the intermediate variable pointer + var s = new Array(o); // declare our intermediate variables array + var i; // general purpose local + var j; // general purpose local + var k = 0; // general purpose local + + // when our "uheprng" is initially invoked our PRNG state is initialized from the + // browser's own local PRNG. This is okay since although its generator might not + // be wonderful, it's useful for establishing large startup entropy for our usage. + var mash = new Mash(); // get a pointer to our high-performance "Mash" hash + + // fill the array with initial mash hash values + for (i = 0; i < o; i++) { + s[i] = mash(Math.random()); + } + + // this PRIVATE (internal access only) function is the heart of the multiply-with-carry + // (MWC) PRNG algorithm. When called it returns a pseudo-random number in the form of a + // 32-bit JavaScript fraction (0.0 to <1.0) it is a PRIVATE function used by the default + // [0-1] return function, and by the random 'string(n)' function which returns 'n' + // characters from 33 to 126. + var rawprng = function () { + if (++p >= o) { + p = 0; + } + var t = 1768863 * s[p] + c * 2.3283064365386963e-10; // 2^-32 + return s[p] = t - (c = t | 0); + }; + + // this EXPORTED function is the default function returned by this library. + // The values returned are integers in the range from 0 to range-1. We first + // obtain two 32-bit fractions (from rawprng) to synthesize a single high + // resolution 53-bit prng (0 to <1), then we multiply this by the caller's + // "range" param and take the "floor" to return a equally probable integer. + var random = function (range) { + return Math.floor(range * (rawprng() + (rawprng() * 0x200000 | 0) * 1.1102230246251565e-16)); // 2^-53 + }; + + // this EXPORTED function 'string(n)' returns a pseudo-random string of + // 'n' printable characters ranging from chr(33) to chr(126) inclusive. + random.string = function (count) { + var i; + var s = ''; + for (i = 0; i < count; i++) { + s += String.fromCharCode(33 + random(94)); + } + return s; + }; + + // this PRIVATE "hash" function is used to evolve the generator's internal + // entropy state. It is also called by the EXPORTED addEntropy() function + // which is used to pour entropy into the PRNG. + var hash = function () { + var args = Array.prototype.slice.call(arguments); + for (i = 0; i < args.length; i++) { + for (j = 0; j < o; j++) { + s[j] -= mash(args[i]); + if (s[j] < 0) { + s[j] += 1; + } + } + } + }; + + // this EXPORTED "clean string" function removes leading and trailing spaces and non-printing + // control characters, including any embedded carriage-return (CR) and line-feed (LF) characters, + // from any string it is handed. this is also used by the 'hashstring' function (below) to help + // users always obtain the same EFFECTIVE uheprng seeding key. + random.cleanString = function (inStr) { + inStr = inStr.replace(/(^\s*)|(\s*$)/gi, ''); // remove any/all leading spaces + inStr = inStr.replace(/[\x00-\x1F]/gi, ''); // remove any/all control characters + inStr = inStr.replace(/\n /, '\n'); // remove any/all trailing spaces + return inStr; // return the cleaned up result + }; + + // this EXPORTED "hash string" function hashes the provided character string after first removing + // any leading or trailing spaces and ignoring any embedded carriage returns (CR) or Line Feeds (LF) + random.hashString = function (inStr) { + inStr = random.cleanString(inStr); + mash(inStr); // use the string to evolve the 'mash' state + for (i = 0; i < inStr.length; i++) { // scan through the characters in our string + k = inStr.charCodeAt(i); // get the character code at the location + for (j = 0; j < o; j++) { // "mash" it into the UHEPRNG state + s[j] -= mash(k); + if (s[j] < 0) { + s[j] += 1; + } + } + } + }; + + // this EXPORTED function allows you to seed the random generator. + random.seed = function (seed) { + if (typeof seed === 'undefined' || seed === null) { + seed = Math.random(); + } + if (typeof seed !== 'string') { + seed = stringify(seed, function (key, value) { + if (typeof value === 'function') { + return (value).toString(); + } + return value; + }); + } + random.initState(); + random.hashString(seed); + }; + + // this handy exported function is used to add entropy to our uheprng at any time + random.addEntropy = function ( /* accept zero or more arguments */ ) { + var args = []; + for (i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + hash((k++) + (new Date().getTime()) + args.join('') + Math.random()); + }; + + // if we want to provide a deterministic startup context for our PRNG, + // but without directly setting the internal state variables, this allows + // us to initialize the mash hash and PRNG's internal state before providing + // some hashing input + random.initState = function () { + mash(); // pass a null arg to force mash hash to init + for (i = 0; i < o; i++) { + s[i] = mash(' '); // fill the array with initial mash hash values + } + c = 1; // init our multiply-with-carry carry + p = o; // init our phase + }; + + // we use this (optional) exported function to signal the JavaScript interpreter + // that we're finished using the "Mash" hash function so that it can free up the + // local "instance variables" is will have been maintaining. It's not strictly + // necessary, of course, but it's good JavaScript citizenship. + random.done = function () { + mash = null; + }; + + // if we called "uheprng" with a seed value, then execute random.seed() before returning + if (typeof seed !== 'undefined') { + random.seed(seed); + } + + // Returns a random integer between 0 (inclusive) and range (exclusive) + random.range = function (range) { + return random(range); + }; + + // Returns a random float between 0 (inclusive) and 1 (exclusive) + random.random = function () { + return random(Number.MAX_VALUE - 1) / Number.MAX_VALUE; + }; + + // Returns a random float between min (inclusive) and max (exclusive) + random.floatBetween = function (min, max) { + return random.random() * (max - min) + min; + }; + + // Returns a random integer between min (inclusive) and max (inclusive) + random.intBetween = function (min, max) { + return Math.floor(random.random() * (max - min + 1)) + min; + }; + + // when our main outer "uheprng" function is called, after setting up our + // initial variables and entropic state, we return an "instance pointer" + // to the internal anonymous function which can then be used to access + // the uheprng's various exported functions. As with the ".done" function + // above, we should set the returned value to 'null' once we're finished + // using any of these functions. + return random; + }()); +}; + +// Modification for use in node: +uheprng.create = function (seed) { + return new uheprng(seed); +}; +module.exports = uheprng; + + +/***/ }), + +/***/ "./node_modules/sat/SAT.js": +/*!*********************************!*\ + !*** ./node_modules/sat/SAT.js ***! + \*********************************/ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Version 0.9.0 - Copyright 2012 - 2021 - Jim Riecken +// +// Released under the MIT License - https://github.com/jriecken/sat-js +// +// A simple library for determining intersections of circles and +// polygons using the Separating Axis Theorem. +/** @preserve SAT.js - Version 0.9.0 - Copyright 2012 - 2021 - Jim Riecken - released under the MIT License. https://github.com/jriecken/sat-js */ + +/*global define: false, module: false*/ +/*jshint shadow:true, sub:true, forin:true, noarg:true, noempty:true, + eqeqeq:true, bitwise:true, strict:true, undef:true, + curly:true, browser:true */ - var uheprng = function (seed) { - return (function () { - var o = 48; // set the 'order' number of ENTROPY-holding 32-bit values - var c = 1; // init the 'carry' used by the multiply-with-carry (MWC) algorithm - var p = o; // init the 'phase' (max-1) of the intermediate variable pointer - var s = new Array(o); // declare our intermediate variables array - var i; // general purpose local - var j; // general purpose local - var k = 0; // general purpose local - - // when our "uheprng" is initially invoked our PRNG state is initialized from the - // browser's own local PRNG. This is okay since although its generator might not - // be wonderful, it's useful for establishing large startup entropy for our usage. - var mash = new Mash(); // get a pointer to our high-performance "Mash" hash - - // fill the array with initial mash hash values - for (i = 0; i < o; i++) { - s[i] = mash(Math.random()); - } +// Create a UMD wrapper for SAT. Works in: +// +// - Plain browser via global SAT variable +// - AMD loader (like require.js) +// - Node.js +// +// The quoted properties all over the place are used so that the Closure Compiler +// does not mangle the exposed API in advanced mode. +/** + * @param {*} root - The global scope + * @param {Function} factory - Factory that creates SAT module + */ +(function (root, factory) { + "use strict"; + if (true) { + !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : + __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else {} +}(this, function () { + "use strict"; + + var SAT = {}; + + // + // ## Vector + // + // Represents a vector in two dimensions with `x` and `y` properties. + + + // Create a new Vector, optionally passing in the `x` and `y` coordinates. If + // a coordinate is not specified, it will be set to `0` + /** + * @param {?number=} x The x position. + * @param {?number=} y The y position. + * @constructor + */ + function Vector(x, y) { + this['x'] = x || 0; + this['y'] = y || 0; + } + SAT['Vector'] = Vector; + // Alias `Vector` as `V` + SAT['V'] = Vector; + + + // Copy the values of another Vector into this one. + /** + * @param {Vector} other The other Vector. + * @return {Vector} This for chaining. + */ + Vector.prototype['copy'] = Vector.prototype.copy = function (other) { + this['x'] = other['x']; + this['y'] = other['y']; + return this; + }; - // this PRIVATE (internal access only) function is the heart of the multiply-with-carry - // (MWC) PRNG algorithm. When called it returns a pseudo-random number in the form of a - // 32-bit JavaScript fraction (0.0 to <1.0) it is a PRIVATE function used by the default - // [0-1] return function, and by the random 'string(n)' function which returns 'n' - // characters from 33 to 126. - var rawprng = function () { - if (++p >= o) { - p = 0; - } - var t = 1768863 * s[p] + c * 2.3283064365386963e-10; // 2^-32 - return (s[p] = t - (c = t | 0)); - }; - - // this EXPORTED function is the default function returned by this library. - // The values returned are integers in the range from 0 to range-1. We first - // obtain two 32-bit fractions (from rawprng) to synthesize a single high - // resolution 53-bit prng (0 to <1), then we multiply this by the caller's - // "range" param and take the "floor" to return a equally probable integer. - var random = function (range) { - return Math.floor( - range * - (rawprng() + - ((rawprng() * 0x200000) | 0) * 1.1102230246251565e-16), - ); // 2^-53 - }; - - // this EXPORTED function 'string(n)' returns a pseudo-random string of - // 'n' printable characters ranging from chr(33) to chr(126) inclusive. - random.string = function (count) { - var i; - var s = ""; - for (i = 0; i < count; i++) { - s += String.fromCharCode(33 + random(94)); - } - return s; - }; - - // this PRIVATE "hash" function is used to evolve the generator's internal - // entropy state. It is also called by the EXPORTED addEntropy() function - // which is used to pour entropy into the PRNG. - var hash = function () { - var args = Array.prototype.slice.call(arguments); - for (i = 0; i < args.length; i++) { - for (j = 0; j < o; j++) { - s[j] -= mash(args[i]); - if (s[j] < 0) { - s[j] += 1; - } - } - } - }; - - // this EXPORTED "clean string" function removes leading and trailing spaces and non-printing - // control characters, including any embedded carriage-return (CR) and line-feed (LF) characters, - // from any string it is handed. this is also used by the 'hashstring' function (below) to help - // users always obtain the same EFFECTIVE uheprng seeding key. - random.cleanString = function (inStr) { - inStr = inStr.replace(/(^\s*)|(\s*$)/gi, ""); // remove any/all leading spaces - inStr = inStr.replace(/[\x00-\x1F]/gi, ""); // remove any/all control characters - inStr = inStr.replace(/\n /, "\n"); // remove any/all trailing spaces - return inStr; // return the cleaned up result - }; - - // this EXPORTED "hash string" function hashes the provided character string after first removing - // any leading or trailing spaces and ignoring any embedded carriage returns (CR) or Line Feeds (LF) - random.hashString = function (inStr) { - inStr = random.cleanString(inStr); - mash(inStr); // use the string to evolve the 'mash' state - for (i = 0; i < inStr.length; i++) { - // scan through the characters in our string - k = inStr.charCodeAt(i); // get the character code at the location - for (j = 0; j < o; j++) { - // "mash" it into the UHEPRNG state - s[j] -= mash(k); - if (s[j] < 0) { - s[j] += 1; - } - } - } - }; - - // this EXPORTED function allows you to seed the random generator. - random.seed = function (seed) { - if (typeof seed === "undefined" || seed === null) { - seed = Math.random(); - } - if (typeof seed !== "string") { - seed = stringify(seed, function (key, value) { - if (typeof value === "function") { - return value.toString(); - } - return value; - }); - } - random.initState(); - random.hashString(seed); - }; - - // this handy exported function is used to add entropy to our uheprng at any time - random.addEntropy = function (/* accept zero or more arguments */) { - var args = []; - for (i = 0; i < arguments.length; i++) { - args.push(arguments[i]); - } - hash(k++ + new Date().getTime() + args.join("") + Math.random()); - }; - - // if we want to provide a deterministic startup context for our PRNG, - // but without directly setting the internal state variables, this allows - // us to initialize the mash hash and PRNG's internal state before providing - // some hashing input - random.initState = function () { - mash(); // pass a null arg to force mash hash to init - for (i = 0; i < o; i++) { - s[i] = mash(" "); // fill the array with initial mash hash values - } - c = 1; // init our multiply-with-carry carry - p = o; // init our phase - }; - - // we use this (optional) exported function to signal the JavaScript interpreter - // that we're finished using the "Mash" hash function so that it can free up the - // local "instance variables" is will have been maintaining. It's not strictly - // necessary, of course, but it's good JavaScript citizenship. - random.done = function () { - mash = null; - }; - - // if we called "uheprng" with a seed value, then execute random.seed() before returning - if (typeof seed !== "undefined") { - random.seed(seed); - } + // Create a new vector with the same coordinates as this on. + /** + * @return {Vector} The new cloned vector + */ + Vector.prototype['clone'] = Vector.prototype.clone = function () { + return new Vector(this['x'], this['y']); + }; - // Returns a random integer between 0 (inclusive) and range (exclusive) - random.range = function (range) { - return random(range); - }; - - // Returns a random float between 0 (inclusive) and 1 (exclusive) - random.random = function () { - return random(Number.MAX_VALUE - 1) / Number.MAX_VALUE; - }; - - // Returns a random float between min (inclusive) and max (exclusive) - random.floatBetween = function (min, max) { - return random.random() * (max - min) + min; - }; - - // Returns a random integer between min (inclusive) and max (inclusive) - random.intBetween = function (min, max) { - return Math.floor(random.random() * (max - min + 1)) + min; - }; - - // when our main outer "uheprng" function is called, after setting up our - // initial variables and entropic state, we return an "instance pointer" - // to the internal anonymous function which can then be used to access - // the uheprng's various exported functions. As with the ".done" function - // above, we should set the returned value to 'null' once we're finished - // using any of these functions. - return random; - })(); - }; + // Change this vector to be perpendicular to what it was before. (Effectively + // roatates it 90 degrees in a clockwise direction) + /** + * @return {Vector} This for chaining. + */ + Vector.prototype['perp'] = Vector.prototype.perp = function () { + var x = this['x']; + this['x'] = this['y']; + this['y'] = -x; + return this; + }; - // Modification for use in node: - uheprng.create = function (seed) { - return new uheprng(seed); - }; - module.exports = uheprng; - - /***/ - }, - - /***/ "./node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/rbush.min.js": - /*!************************************************************************!*\ - !*** ./node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/rbush.min.js ***! - \************************************************************************/ - /***/ function (module) { - !(function (t, i) { - true ? (module.exports = i()) : 0; - })(this, function () { - "use strict"; - function t(t, r, e, a, h) { - !(function t(n, r, e, a, h) { - for (; a > e; ) { - if (a - e > 600) { - var o = a - e + 1, - s = r - e + 1, - l = Math.log(o), - f = 0.5 * Math.exp((2 * l) / 3), - u = - 0.5 * - Math.sqrt((l * f * (o - f)) / o) * - (s - o / 2 < 0 ? -1 : 1), - m = Math.max(e, Math.floor(r - (s * f) / o + u)), - c = Math.min(a, Math.floor(r + ((o - s) * f) / o + u)); - t(n, r, m, c, h); - } - var p = n[r], - d = e, - x = a; - for (i(n, e, r), h(n[a], p) > 0 && i(n, e, a); d < x; ) { - for (i(n, d, x), d++, x--; h(n[d], p) < 0; ) d++; - for (; h(n[x], p) > 0; ) x--; - } - 0 === h(n[e], p) ? i(n, e, x) : i(n, ++x, a), - x <= r && (e = x + 1), - r <= x && (a = x - 1); - } - })(t, r, e || 0, a || t.length - 1, h || n); - } - function i(t, i, n) { - var r = t[i]; - (t[i] = t[n]), (t[n] = r); - } - function n(t, i) { - return t < i ? -1 : t > i ? 1 : 0; - } - var r = function (t) { - void 0 === t && (t = 9), - (this._maxEntries = Math.max(4, t)), - (this._minEntries = Math.max( - 2, - Math.ceil(0.4 * this._maxEntries), - )), - this.clear(); - }; - function e(t, i, n) { - if (!n) return i.indexOf(t); - for (var r = 0; r < i.length; r++) if (n(t, i[r])) return r; - return -1; - } - function a(t, i) { - h(t, 0, t.children.length, i, t); - } - function h(t, i, n, r, e) { - e || (e = p(null)), - (e.minX = 1 / 0), - (e.minY = 1 / 0), - (e.maxX = -1 / 0), - (e.maxY = -1 / 0); - for (var a = i; a < n; a++) { - var h = t.children[a]; - o(e, t.leaf ? r(h) : h); - } - return e; - } - function o(t, i) { - return ( - (t.minX = Math.min(t.minX, i.minX)), - (t.minY = Math.min(t.minY, i.minY)), - (t.maxX = Math.max(t.maxX, i.maxX)), - (t.maxY = Math.max(t.maxY, i.maxY)), - t - ); - } - function s(t, i) { - return t.minX - i.minX; - } - function l(t, i) { - return t.minY - i.minY; - } - function f(t) { - return (t.maxX - t.minX) * (t.maxY - t.minY); - } - function u(t) { - return t.maxX - t.minX + (t.maxY - t.minY); - } - function m(t, i) { - return ( - t.minX <= i.minX && - t.minY <= i.minY && - i.maxX <= t.maxX && - i.maxY <= t.maxY - ); - } - function c(t, i) { - return ( - i.minX <= t.maxX && - i.minY <= t.maxY && - i.maxX >= t.minX && - i.maxY >= t.minY - ); - } - function p(t) { - return { - children: t, - height: 1, - leaf: !0, - minX: 1 / 0, - minY: 1 / 0, - maxX: -1 / 0, - maxY: -1 / 0, - }; - } - function d(i, n, r, e, a) { - for (var h = [n, r]; h.length; ) - if (!((r = h.pop()) - (n = h.pop()) <= e)) { - var o = n + Math.ceil((r - n) / e / 2) * e; - t(i, o, n, r, a), h.push(n, o, o, r); - } - } - return ( - (r.prototype.all = function () { - return this._all(this.data, []); - }), - (r.prototype.search = function (t) { - var i = this.data, - n = []; - if (!c(t, i)) return n; - for (var r = this.toBBox, e = []; i; ) { - for (var a = 0; a < i.children.length; a++) { - var h = i.children[a], - o = i.leaf ? r(h) : h; - c(t, o) && - (i.leaf - ? n.push(h) - : m(t, o) - ? this._all(h, n) - : e.push(h)); - } - i = e.pop(); - } - return n; - }), - (r.prototype.collides = function (t) { - var i = this.data; - if (!c(t, i)) return !1; - for (var n = []; i; ) { - for (var r = 0; r < i.children.length; r++) { - var e = i.children[r], - a = i.leaf ? this.toBBox(e) : e; - if (c(t, a)) { - if (i.leaf || m(t, a)) return !0; - n.push(e); - } - } - i = n.pop(); - } - return !1; - }), - (r.prototype.load = function (t) { - if (!t || !t.length) return this; - if (t.length < this._minEntries) { - for (var i = 0; i < t.length; i++) this.insert(t[i]); - return this; - } - var n = this._build(t.slice(), 0, t.length - 1, 0); - if (this.data.children.length) - if (this.data.height === n.height) - this._splitRoot(this.data, n); - else { - if (this.data.height < n.height) { - var r = this.data; - (this.data = n), (n = r); - } - this._insert(n, this.data.height - n.height - 1, !0); - } - else this.data = n; - return this; - }), - (r.prototype.insert = function (t) { - return t && this._insert(t, this.data.height - 1), this; - }), - (r.prototype.clear = function () { - return (this.data = p([])), this; - }), - (r.prototype.remove = function (t, i) { - if (!t) return this; - for ( - var n, r, a, h = this.data, o = this.toBBox(t), s = [], l = []; - h || s.length; - - ) { - if ( - (h || - ((h = s.pop()), - (r = s[s.length - 1]), - (n = l.pop()), - (a = !0)), - h.leaf) - ) { - var f = e(t, h.children, i); - if (-1 !== f) - return ( - h.children.splice(f, 1), - s.push(h), - this._condense(s), - this - ); - } - a || h.leaf || !m(h, o) - ? r - ? (n++, (h = r.children[n]), (a = !1)) - : (h = null) - : (s.push(h), - l.push(n), - (n = 0), - (r = h), - (h = h.children[0])); - } - return this; - }), - (r.prototype.toBBox = function (t) { - return t; - }), - (r.prototype.compareMinX = function (t, i) { - return t.minX - i.minX; - }), - (r.prototype.compareMinY = function (t, i) { - return t.minY - i.minY; - }), - (r.prototype.toJSON = function () { - return this.data; - }), - (r.prototype.fromJSON = function (t) { - return (this.data = t), this; - }), - (r.prototype._all = function (t, i) { - for (var n = []; t; ) - t.leaf - ? i.push.apply(i, t.children) - : n.push.apply(n, t.children), - (t = n.pop()); - return i; - }), - (r.prototype._build = function (t, i, n, r) { - var e, - h = n - i + 1, - o = this._maxEntries; - if (h <= o) return a((e = p(t.slice(i, n + 1))), this.toBBox), e; - r || - ((r = Math.ceil(Math.log(h) / Math.log(o))), - (o = Math.ceil(h / Math.pow(o, r - 1)))), - ((e = p([])).leaf = !1), - (e.height = r); - var s = Math.ceil(h / o), - l = s * Math.ceil(Math.sqrt(o)); - d(t, i, n, l, this.compareMinX); - for (var f = i; f <= n; f += l) { - var u = Math.min(f + l - 1, n); - d(t, f, u, s, this.compareMinY); - for (var m = f; m <= u; m += s) { - var c = Math.min(m + s - 1, u); - e.children.push(this._build(t, m, c, r - 1)); - } - } - return a(e, this.toBBox), e; - }), - (r.prototype._chooseSubtree = function (t, i, n, r) { - for (; r.push(i), !i.leaf && r.length - 1 !== n; ) { - for ( - var e = 1 / 0, a = 1 / 0, h = void 0, o = 0; - o < i.children.length; - o++ - ) { - var s = i.children[o], - l = f(s), - u = - ((m = t), - (c = s), - (Math.max(c.maxX, m.maxX) - Math.min(c.minX, m.minX)) * - (Math.max(c.maxY, m.maxY) - Math.min(c.minY, m.minY)) - - l); - u < a - ? ((a = u), (e = l < e ? l : e), (h = s)) - : u === a && l < e && ((e = l), (h = s)); - } - i = h || i.children[0]; - } - var m, c; - return i; - }), - (r.prototype._insert = function (t, i, n) { - var r = n ? t : this.toBBox(t), - e = [], - a = this._chooseSubtree(r, this.data, i, e); - for ( - a.children.push(t), o(a, r); - i >= 0 && e[i].children.length > this._maxEntries; - - ) - this._split(e, i), i--; - this._adjustParentBBoxes(r, e, i); - }), - (r.prototype._split = function (t, i) { - var n = t[i], - r = n.children.length, - e = this._minEntries; - this._chooseSplitAxis(n, e, r); - var h = this._chooseSplitIndex(n, e, r), - o = p(n.children.splice(h, n.children.length - h)); - (o.height = n.height), - (o.leaf = n.leaf), - a(n, this.toBBox), - a(o, this.toBBox), - i ? t[i - 1].children.push(o) : this._splitRoot(n, o); - }), - (r.prototype._splitRoot = function (t, i) { - (this.data = p([t, i])), - (this.data.height = t.height + 1), - (this.data.leaf = !1), - a(this.data, this.toBBox); - }), - (r.prototype._chooseSplitIndex = function (t, i, n) { - for ( - var r, e, a, o, s, l, u, m = 1 / 0, c = 1 / 0, p = i; - p <= n - i; - p++ - ) { - var d = h(t, 0, p, this.toBBox), - x = h(t, p, n, this.toBBox), - v = - ((e = d), - (a = x), - (o = void 0), - (s = void 0), - (l = void 0), - (u = void 0), - (o = Math.max(e.minX, a.minX)), - (s = Math.max(e.minY, a.minY)), - (l = Math.min(e.maxX, a.maxX)), - (u = Math.min(e.maxY, a.maxY)), - Math.max(0, l - o) * Math.max(0, u - s)), - M = f(d) + f(x); - v < m - ? ((m = v), (r = p), (c = M < c ? M : c)) - : v === m && M < c && ((c = M), (r = p)); - } - return r || n - i; - }), - (r.prototype._chooseSplitAxis = function (t, i, n) { - var r = t.leaf ? this.compareMinX : s, - e = t.leaf ? this.compareMinY : l; - this._allDistMargin(t, i, n, r) < - this._allDistMargin(t, i, n, e) && t.children.sort(r); - }), - (r.prototype._allDistMargin = function (t, i, n, r) { - t.children.sort(r); - for ( - var e = this.toBBox, - a = h(t, 0, i, e), - s = h(t, n - i, n, e), - l = u(a) + u(s), - f = i; - f < n - i; - f++ - ) { - var m = t.children[f]; - o(a, t.leaf ? e(m) : m), (l += u(a)); - } - for (var c = n - i - 1; c >= i; c--) { - var p = t.children[c]; - o(s, t.leaf ? e(p) : p), (l += u(s)); - } - return l; - }), - (r.prototype._adjustParentBBoxes = function (t, i, n) { - for (var r = n; r >= 0; r--) o(i[r], t); - }), - (r.prototype._condense = function (t) { - for (var i = t.length - 1, n = void 0; i >= 0; i--) - 0 === t[i].children.length - ? i > 0 - ? (n = t[i - 1].children).splice(n.indexOf(t[i]), 1) - : this.clear() - : a(t[i], this.toBBox); - }), - r - ); - }); + // Rotate this vector (counter-clockwise) by the specified angle (in radians). + /** + * @param {number} angle The angle to rotate (in radians) + * @return {Vector} This for chaining. + */ + Vector.prototype['rotate'] = Vector.prototype.rotate = function (angle) { + var x = this['x']; + var y = this['y']; + this['x'] = x * Math.cos(angle) - y * Math.sin(angle); + this['y'] = x * Math.sin(angle) + y * Math.cos(angle); + return this; + }; - /***/ - }, - - /***/ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js": - /*!**************************************************************!*\ - !*** ./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js ***! - \**************************************************************/ - /***/ function (module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__; // Version 0.9.0 - Copyright 2012 - 2021 - Jim Riecken - // - // Released under the MIT License - https://github.com/jriecken/sat-js - // - // A simple library for determining intersections of circles and - // polygons using the Separating Axis Theorem. - /** @preserve SAT.js - Version 0.9.0 - Copyright 2012 - 2021 - Jim Riecken - released under the MIT License. https://github.com/jriecken/sat-js */ - - /*global define: false, module: false*/ - /*jshint shadow:true, sub:true, forin:true, noarg:true, noempty:true, - eqeqeq:true, bitwise:true, strict:true, undef:true, - curly:true, browser:true */ + // Reverse this vector. + /** + * @return {Vector} This for chaining. + */ + Vector.prototype['reverse'] = Vector.prototype.reverse = function () { + this['x'] = -this['x']; + this['y'] = -this['y']; + return this; + }; - // Create a UMD wrapper for SAT. Works in: - // - // - Plain browser via global SAT variable - // - AMD loader (like require.js) - // - Node.js - // - // The quoted properties all over the place are used so that the Closure Compiler - // does not mangle the exposed API in advanced mode. - /** - * @param {*} root - The global scope - * @param {Function} factory - Factory that creates SAT module - */ - (function (root, factory) { - "use strict"; - if (true) { - !((__WEBPACK_AMD_DEFINE_FACTORY__ = factory), - (__WEBPACK_AMD_DEFINE_RESULT__ = - typeof __WEBPACK_AMD_DEFINE_FACTORY__ === "function" - ? __WEBPACK_AMD_DEFINE_FACTORY__.call( - exports, - __webpack_require__, - exports, - module, - ) - : __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && - (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else { - } - })(this, function () { - "use strict"; - - var SAT = {}; - - // - // ## Vector - // - // Represents a vector in two dimensions with `x` and `y` properties. - - // Create a new Vector, optionally passing in the `x` and `y` coordinates. If - // a coordinate is not specified, it will be set to `0` - /** - * @param {?number=} x The x position. - * @param {?number=} y The y position. - * @constructor - */ - function Vector(x, y) { - this["x"] = x || 0; - this["y"] = y || 0; - } - SAT["Vector"] = Vector; - // Alias `Vector` as `V` - SAT["V"] = Vector; - - // Copy the values of another Vector into this one. - /** - * @param {Vector} other The other Vector. - * @return {Vector} This for chaining. - */ - Vector.prototype["copy"] = Vector.prototype.copy = function (other) { - this["x"] = other["x"]; - this["y"] = other["y"]; - return this; - }; - - // Create a new vector with the same coordinates as this on. - /** - * @return {Vector} The new cloned vector - */ - Vector.prototype["clone"] = Vector.prototype.clone = function () { - return new Vector(this["x"], this["y"]); - }; - - // Change this vector to be perpendicular to what it was before. (Effectively - // roatates it 90 degrees in a clockwise direction) - /** - * @return {Vector} This for chaining. - */ - Vector.prototype["perp"] = Vector.prototype.perp = function () { - var x = this["x"]; - this["x"] = this["y"]; - this["y"] = -x; - return this; - }; - - // Rotate this vector (counter-clockwise) by the specified angle (in radians). - /** - * @param {number} angle The angle to rotate (in radians) - * @return {Vector} This for chaining. - */ - Vector.prototype["rotate"] = Vector.prototype.rotate = function ( - angle, - ) { - var x = this["x"]; - var y = this["y"]; - this["x"] = x * Math.cos(angle) - y * Math.sin(angle); - this["y"] = x * Math.sin(angle) + y * Math.cos(angle); - return this; - }; - - // Reverse this vector. - /** - * @return {Vector} This for chaining. - */ - Vector.prototype["reverse"] = Vector.prototype.reverse = function () { - this["x"] = -this["x"]; - this["y"] = -this["y"]; - return this; - }; - - // Normalize this vector. (make it have length of `1`) - /** - * @return {Vector} This for chaining. - */ - Vector.prototype["normalize"] = Vector.prototype.normalize = - function () { - var d = this.len(); - if (d > 0) { - this["x"] = this["x"] / d; - this["y"] = this["y"] / d; - } - return this; - }; - - // Add another vector to this one. - /** - * @param {Vector} other The other Vector. - * @return {Vector} This for chaining. - */ - Vector.prototype["add"] = Vector.prototype.add = function (other) { - this["x"] += other["x"]; - this["y"] += other["y"]; - return this; - }; - - // Subtract another vector from this one. - /** - * @param {Vector} other The other Vector. - * @return {Vector} This for chaiing. - */ - Vector.prototype["sub"] = Vector.prototype.sub = function (other) { - this["x"] -= other["x"]; - this["y"] -= other["y"]; - return this; - }; - - // Scale this vector. An independent scaling factor can be provided - // for each axis, or a single scaling factor that will scale both `x` and `y`. - /** - * @param {number} x The scaling factor in the x direction. - * @param {?number=} y The scaling factor in the y direction. If this - * is not specified, the x scaling factor will be used. - * @return {Vector} This for chaining. - */ - Vector.prototype["scale"] = Vector.prototype.scale = function (x, y) { - this["x"] *= x; - this["y"] *= typeof y != "undefined" ? y : x; - return this; - }; - - // Project this vector on to another vector. - /** - * @param {Vector} other The vector to project onto. - * @return {Vector} This for chaining. - */ - Vector.prototype["project"] = Vector.prototype.project = function ( - other, - ) { - var amt = this.dot(other) / other.len2(); - this["x"] = amt * other["x"]; - this["y"] = amt * other["y"]; - return this; - }; - - // Project this vector onto a vector of unit length. This is slightly more efficient - // than `project` when dealing with unit vectors. - /** - * @param {Vector} other The unit vector to project onto. - * @return {Vector} This for chaining. - */ - Vector.prototype["projectN"] = Vector.prototype.projectN = function ( - other, - ) { - var amt = this.dot(other); - this["x"] = amt * other["x"]; - this["y"] = amt * other["y"]; - return this; - }; - - // Reflect this vector on an arbitrary axis. - /** - * @param {Vector} axis The vector representing the axis. - * @return {Vector} This for chaining. - */ - Vector.prototype["reflect"] = Vector.prototype.reflect = function ( - axis, - ) { - var x = this["x"]; - var y = this["y"]; - this.project(axis).scale(2); - this["x"] -= x; - this["y"] -= y; - return this; - }; - - // Reflect this vector on an arbitrary axis (represented by a unit vector). This is - // slightly more efficient than `reflect` when dealing with an axis that is a unit vector. - /** - * @param {Vector} axis The unit vector representing the axis. - * @return {Vector} This for chaining. - */ - Vector.prototype["reflectN"] = Vector.prototype.reflectN = function ( - axis, - ) { - var x = this["x"]; - var y = this["y"]; - this.projectN(axis).scale(2); - this["x"] -= x; - this["y"] -= y; - return this; - }; - - // Get the dot product of this vector and another. - /** - * @param {Vector} other The vector to dot this one against. - * @return {number} The dot product. - */ - Vector.prototype["dot"] = Vector.prototype.dot = function (other) { - return this["x"] * other["x"] + this["y"] * other["y"]; - }; - - // Get the squared length of this vector. - /** - * @return {number} The length^2 of this vector. - */ - Vector.prototype["len2"] = Vector.prototype.len2 = function () { - return this.dot(this); - }; - - // Get the length of this vector. - /** - * @return {number} The length of this vector. - */ - Vector.prototype["len"] = Vector.prototype.len = function () { - return Math.sqrt(this.len2()); - }; - - // ## Circle - // - // Represents a circle with a position and a radius. - - // Create a new circle, optionally passing in a position and/or radius. If no position - // is given, the circle will be at `(0,0)`. If no radius is provided, the circle will - // have a radius of `0`. - /** - * @param {Vector=} pos A vector representing the position of the center of the circle - * @param {?number=} r The radius of the circle - * @constructor - */ - function Circle(pos, r) { - this["pos"] = pos || new Vector(); - this["r"] = r || 0; - this["offset"] = new Vector(); - } - SAT["Circle"] = Circle; - - // Compute the axis-aligned bounding box (AABB) of this Circle. - // - // Note: Returns a _new_ `Box` each time you call this. - /** - * @return {Polygon} The AABB - */ - Circle.prototype["getAABBAsBox"] = Circle.prototype.getAABBAsBox = - function () { - var r = this["r"]; - var corner = this["pos"] - .clone() - .add(this["offset"]) - .sub(new Vector(r, r)); - return new Box(corner, r * 2, r * 2); - }; - - // Compute the axis-aligned bounding box (AABB) of this Circle. - // - // Note: Returns a _new_ `Polygon` each time you call this. - /** - * @return {Polygon} The AABB - */ - Circle.prototype["getAABB"] = Circle.prototype.getAABB = function () { - return this.getAABBAsBox().toPolygon(); - }; - - // Set the current offset to apply to the radius. - /** - * @param {Vector} offset The new offset vector. - * @return {Circle} This for chaining. - */ - Circle.prototype["setOffset"] = Circle.prototype.setOffset = - function (offset) { - this["offset"] = offset; - return this; - }; - - // ## Polygon - // - // Represents a *convex* polygon with any number of points (specified in counter-clockwise order) - // - // Note: Do _not_ manually change the `points`, `angle`, or `offset` properties. Use the - // provided setters. Otherwise the calculated properties will not be updated correctly. - // - // `pos` can be changed directly. - - // Create a new polygon, passing in a position vector, and an array of points (represented - // by vectors relative to the position vector). If no position is passed in, the position - // of the polygon will be `(0,0)`. - /** - * @param {Vector=} pos A vector representing the origin of the polygon. (all other - * points are relative to this one) - * @param {Array=} points An array of vectors representing the points in the polygon, - * in counter-clockwise order. - * @constructor - */ - function Polygon(pos, points) { - this["pos"] = pos || new Vector(); - this["angle"] = 0; - this["offset"] = new Vector(); - this.setPoints(points || []); - } - SAT["Polygon"] = Polygon; - - // Set the points of the polygon. Any consecutive duplicate points will be combined. - // - // Note: The points are counter-clockwise *with respect to the coordinate system*. - // If you directly draw the points on a screen that has the origin at the top-left corner - // it will _appear_ visually that the points are being specified clockwise. This is just - // because of the inversion of the Y-axis when being displayed. - /** - * @param {Array=} points An array of vectors representing the points in the polygon, - * in counter-clockwise order. - * @return {Polygon} This for chaining. - */ - Polygon.prototype["setPoints"] = Polygon.prototype.setPoints = - function (points) { - // Only re-allocate if this is a new polygon or the number of points has changed. - var lengthChanged = - !this["points"] || this["points"].length !== points.length; - if (lengthChanged) { - var i; - var calcPoints = (this["calcPoints"] = []); - var edges = (this["edges"] = []); - var normals = (this["normals"] = []); - // Allocate the vector arrays for the calculated properties - for (i = 0; i < points.length; i++) { - // Remove consecutive duplicate points - var p1 = points[i]; - var p2 = i < points.length - 1 ? points[i + 1] : points[0]; - if (p1 !== p2 && p1.x === p2.x && p1.y === p2.y) { - points.splice(i, 1); - i -= 1; - continue; - } - calcPoints.push(new Vector()); - edges.push(new Vector()); - normals.push(new Vector()); - } - } - this["points"] = points; - this._recalc(); - return this; - }; - - // Set the current rotation angle of the polygon. - /** - * @param {number} angle The current rotation angle (in radians). - * @return {Polygon} This for chaining. - */ - Polygon.prototype["setAngle"] = Polygon.prototype.setAngle = - function (angle) { - this["angle"] = angle; - this._recalc(); - return this; - }; - - // Set the current offset to apply to the `points` before applying the `angle` rotation. - /** - * @param {Vector} offset The new offset vector. - * @return {Polygon} This for chaining. - */ - Polygon.prototype["setOffset"] = Polygon.prototype.setOffset = - function (offset) { - this["offset"] = offset; - this._recalc(); - return this; - }; - - // Rotates this polygon counter-clockwise around the origin of *its local coordinate system* (i.e. `pos`). - // - // Note: This changes the **original** points (so any `angle` will be applied on top of this rotation). - /** - * @param {number} angle The angle to rotate (in radians) - * @return {Polygon} This for chaining. - */ - Polygon.prototype["rotate"] = Polygon.prototype.rotate = function ( - angle, - ) { - var points = this["points"]; - var len = points.length; - for (var i = 0; i < len; i++) { - points[i].rotate(angle); - } - this._recalc(); - return this; - }; - - // Translates the points of this polygon by a specified amount relative to the origin of *its own coordinate - // system* (i.e. `pos`). - // - // This is most useful to change the "center point" of a polygon. If you just want to move the whole polygon, change - // the coordinates of `pos`. - // - // Note: This changes the **original** points (so any `offset` will be applied on top of this translation) - /** - * @param {number} x The horizontal amount to translate. - * @param {number} y The vertical amount to translate. - * @return {Polygon} This for chaining. - */ - Polygon.prototype["translate"] = Polygon.prototype.translate = - function (x, y) { - var points = this["points"]; - var len = points.length; - for (var i = 0; i < len; i++) { - points[i]["x"] += x; - points[i]["y"] += y; - } - this._recalc(); - return this; - }; - - // Computes the calculated collision polygon. Applies the `angle` and `offset` to the original points then recalculates the - // edges and normals of the collision polygon. - /** - * @return {Polygon} This for chaining. - */ - Polygon.prototype._recalc = function () { - // Calculated points - this is what is used for underlying collisions and takes into account - // the angle/offset set on the polygon. - var calcPoints = this["calcPoints"]; - // The edges here are the direction of the `n`th edge of the polygon, relative to - // the `n`th point. If you want to draw a given edge from the edge value, you must - // first translate to the position of the starting point. - var edges = this["edges"]; - // The normals here are the direction of the normal for the `n`th edge of the polygon, relative - // to the position of the `n`th point. If you want to draw an edge normal, you must first - // translate to the position of the starting point. - var normals = this["normals"]; - // Copy the original points array and apply the offset/angle - var points = this["points"]; - var offset = this["offset"]; - var angle = this["angle"]; - var len = points.length; - var i; - for (i = 0; i < len; i++) { - var calcPoint = calcPoints[i].copy(points[i]); - calcPoint["x"] += offset["x"]; - calcPoint["y"] += offset["y"]; - if (angle !== 0) { - calcPoint.rotate(angle); - } - } - // Calculate the edges/normals - for (i = 0; i < len; i++) { - var p1 = calcPoints[i]; - var p2 = i < len - 1 ? calcPoints[i + 1] : calcPoints[0]; - var e = edges[i].copy(p2).sub(p1); - normals[i].copy(e).perp().normalize(); - } - return this; - }; - - // Compute the axis-aligned bounding box. Any current state - // (translations/rotations) will be applied before constructing the AABB. - // - // Note: Returns a _new_ `Box` each time you call this. - /** - * @return {Polygon} The AABB - */ - Polygon.prototype["getAABBAsBox"] = Polygon.prototype.getAABBAsBox = - function () { - var points = this["calcPoints"]; - var len = points.length; - var xMin = points[0]["x"]; - var yMin = points[0]["y"]; - var xMax = points[0]["x"]; - var yMax = points[0]["y"]; - for (var i = 1; i < len; i++) { - var point = points[i]; - if (point["x"] < xMin) { - xMin = point["x"]; - } else if (point["x"] > xMax) { - xMax = point["x"]; - } - if (point["y"] < yMin) { - yMin = point["y"]; - } else if (point["y"] > yMax) { - yMax = point["y"]; - } - } - return new Box( - this["pos"].clone().add(new Vector(xMin, yMin)), - xMax - xMin, - yMax - yMin, - ); - }; - - // Compute the axis-aligned bounding box. Any current state - // (translations/rotations) will be applied before constructing the AABB. - // - // Note: Returns a _new_ `Polygon` each time you call this. - /** - * @return {Polygon} The AABB - */ - Polygon.prototype["getAABB"] = Polygon.prototype.getAABB = - function () { - return this.getAABBAsBox().toPolygon(); - }; - - // Compute the centroid (geometric center) of the polygon. Any current state - // (translations/rotations) will be applied before computing the centroid. - // - // See https://en.wikipedia.org/wiki/Centroid#Centroid_of_a_polygon - // - // Note: Returns a _new_ `Vector` each time you call this. - /** - * @return {Vector} A Vector that contains the coordinates of the Centroid. - */ - Polygon.prototype["getCentroid"] = Polygon.prototype.getCentroid = - function () { - var points = this["calcPoints"]; - var len = points.length; - var cx = 0; - var cy = 0; - var ar = 0; - for (var i = 0; i < len; i++) { - var p1 = points[i]; - var p2 = i === len - 1 ? points[0] : points[i + 1]; // Loop around if last point - var a = p1["x"] * p2["y"] - p2["x"] * p1["y"]; - cx += (p1["x"] + p2["x"]) * a; - cy += (p1["y"] + p2["y"]) * a; - ar += a; - } - ar = ar * 3; // we want 1 / 6 the area and we currently have 2*area - cx = cx / ar; - cy = cy / ar; - return new Vector(cx, cy); - }; - - // ## Box - // - // Represents an axis-aligned box, with a width and height. - - // Create a new box, with the specified position, width, and height. If no position - // is given, the position will be `(0,0)`. If no width or height are given, they will - // be set to `0`. - /** - * @param {Vector=} pos A vector representing the bottom-left of the box (i.e. the smallest x and smallest y value). - * @param {?number=} w The width of the box. - * @param {?number=} h The height of the box. - * @constructor - */ - function Box(pos, w, h) { - this["pos"] = pos || new Vector(); - this["w"] = w || 0; - this["h"] = h || 0; - } - SAT["Box"] = Box; - - // Returns a polygon whose edges are the same as this box. - /** - * @return {Polygon} A new Polygon that represents this box. - */ - Box.prototype["toPolygon"] = Box.prototype.toPolygon = function () { - var pos = this["pos"]; - var w = this["w"]; - var h = this["h"]; - return new Polygon(new Vector(pos["x"], pos["y"]), [ - new Vector(), - new Vector(w, 0), - new Vector(w, h), - new Vector(0, h), - ]); - }; - - // ## Response - // - // An object representing the result of an intersection. Contains: - // - The two objects participating in the intersection - // - The vector representing the minimum change necessary to extract the first object - // from the second one (as well as a unit vector in that direction and the magnitude - // of the overlap) - // - Whether the first object is entirely inside the second, and vice versa. - /** - * @constructor - */ - function Response() { - this["a"] = null; - this["b"] = null; - this["overlapN"] = new Vector(); - this["overlapV"] = new Vector(); - this.clear(); - } - SAT["Response"] = Response; - - // Set some values of the response back to their defaults. Call this between tests if - // you are going to reuse a single Response object for multiple intersection tests (recommented - // as it will avoid allcating extra memory) - /** - * @return {Response} This for chaining - */ - Response.prototype["clear"] = Response.prototype.clear = function () { - this["aInB"] = true; - this["bInA"] = true; - this["overlap"] = Number.MAX_VALUE; - return this; - }; - - // ## Object Pools - - // A pool of `Vector` objects that are used in calculations to avoid - // allocating memory. - /** - * @type {Array} - */ - var T_VECTORS = []; - for (var i = 0; i < 10; i++) { - T_VECTORS.push(new Vector()); - } - // A pool of arrays of numbers used in calculations to avoid allocating - // memory. - /** - * @type {Array>} - */ - var T_ARRAYS = []; - for (var i = 0; i < 5; i++) { - T_ARRAYS.push([]); - } + // Normalize this vector. (make it have length of `1`) + /** + * @return {Vector} This for chaining. + */ + Vector.prototype['normalize'] = Vector.prototype.normalize = function () { + var d = this.len(); + if (d > 0) { + this['x'] = this['x'] / d; + this['y'] = this['y'] / d; + } + return this; + }; - // Temporary response used for polygon hit detection. - /** - * @type {Response} - */ - var T_RESPONSE = new Response(); - - // Tiny "point" polygon used for polygon hit detection. - /** - * @type {Polygon} - */ - var TEST_POINT = new Box( - new Vector(), - 0.000001, - 0.000001, - ).toPolygon(); - - // ## Helper Functions - - // Flattens the specified array of points onto a unit vector axis, - // resulting in a one dimensional range of the minimum and - // maximum value on that axis. - /** - * @param {Array} points The points to flatten. - * @param {Vector} normal The unit vector axis to flatten on. - * @param {Array} result An array. After calling this function, - * result[0] will be the minimum value, - * result[1] will be the maximum value. - */ - function flattenPointsOn(points, normal, result) { - var min = Number.MAX_VALUE; - var max = -Number.MAX_VALUE; - var len = points.length; - for (var i = 0; i < len; i++) { - // The magnitude of the projection of the point onto the normal - var dot = points[i].dot(normal); - if (dot < min) { - min = dot; - } - if (dot > max) { - max = dot; - } - } - result[0] = min; - result[1] = max; - } + // Add another vector to this one. + /** + * @param {Vector} other The other Vector. + * @return {Vector} This for chaining. + */ + Vector.prototype['add'] = Vector.prototype.add = function (other) { + this['x'] += other['x']; + this['y'] += other['y']; + return this; + }; - // Check whether two convex polygons are separated by the specified - // axis (must be a unit vector). - /** - * @param {Vector} aPos The position of the first polygon. - * @param {Vector} bPos The position of the second polygon. - * @param {Array} aPoints The points in the first polygon. - * @param {Array} bPoints The points in the second polygon. - * @param {Vector} axis The axis (unit sized) to test against. The points of both polygons - * will be projected onto this axis. - * @param {Response=} response A Response object (optional) which will be populated - * if the axis is not a separating axis. - * @return {boolean} true if it is a separating axis, false otherwise. If false, - * and a response is passed in, information about how much overlap and - * the direction of the overlap will be populated. - */ - function isSeparatingAxis( - aPos, - bPos, - aPoints, - bPoints, - axis, - response, - ) { - var rangeA = T_ARRAYS.pop(); - var rangeB = T_ARRAYS.pop(); - // The magnitude of the offset between the two polygons - var offsetV = T_VECTORS.pop().copy(bPos).sub(aPos); - var projectedOffset = offsetV.dot(axis); - // Project the polygons onto the axis. - flattenPointsOn(aPoints, axis, rangeA); - flattenPointsOn(bPoints, axis, rangeB); - // Move B's range to its position relative to A. - rangeB[0] += projectedOffset; - rangeB[1] += projectedOffset; - // Check if there is a gap. If there is, this is a separating axis and we can stop - if (rangeA[0] > rangeB[1] || rangeB[0] > rangeA[1]) { - T_VECTORS.push(offsetV); - T_ARRAYS.push(rangeA); - T_ARRAYS.push(rangeB); - return true; - } - // This is not a separating axis. If we're calculating a response, calculate the overlap. - if (response) { - var overlap = 0; - // A starts further left than B - if (rangeA[0] < rangeB[0]) { - response["aInB"] = false; - // A ends before B does. We have to pull A out of B - if (rangeA[1] < rangeB[1]) { - overlap = rangeA[1] - rangeB[0]; - response["bInA"] = false; - // B is fully inside A. Pick the shortest way out. - } else { - var option1 = rangeA[1] - rangeB[0]; - var option2 = rangeB[1] - rangeA[0]; - overlap = option1 < option2 ? option1 : -option2; - } - // B starts further left than A - } else { - response["bInA"] = false; - // B ends before A ends. We have to push A out of B - if (rangeA[1] > rangeB[1]) { - overlap = rangeA[0] - rangeB[1]; - response["aInB"] = false; - // A is fully inside B. Pick the shortest way out. - } else { - var option1 = rangeA[1] - rangeB[0]; - var option2 = rangeB[1] - rangeA[0]; - overlap = option1 < option2 ? option1 : -option2; - } - } - // If this is the smallest amount of overlap we've seen so far, set it as the minimum overlap. - var absOverlap = Math.abs(overlap); - if (absOverlap < response["overlap"]) { - response["overlap"] = absOverlap; - response["overlapN"].copy(axis); - if (overlap < 0) { - response["overlapN"].reverse(); - } - } - } - T_VECTORS.push(offsetV); - T_ARRAYS.push(rangeA); - T_ARRAYS.push(rangeB); - return false; - } - SAT["isSeparatingAxis"] = isSeparatingAxis; - - // Calculates which Voronoi region a point is on a line segment. - // It is assumed that both the line and the point are relative to `(0,0)` - // - // | (0) | - // (-1) [S]--------------[E] (1) - // | (0) | - /** - * @param {Vector} line The line segment. - * @param {Vector} point The point. - * @return {number} LEFT_VORONOI_REGION (-1) if it is the left region, - * MIDDLE_VORONOI_REGION (0) if it is the middle region, - * RIGHT_VORONOI_REGION (1) if it is the right region. - */ - function voronoiRegion(line, point) { - var len2 = line.len2(); - var dp = point.dot(line); - // If the point is beyond the start of the line, it is in the - // left voronoi region. - if (dp < 0) { - return LEFT_VORONOI_REGION; - } - // If the point is beyond the end of the line, it is in the - // right voronoi region. - else if (dp > len2) { - return RIGHT_VORONOI_REGION; - } - // Otherwise, it's in the middle one. - else { - return MIDDLE_VORONOI_REGION; - } - } - // Constants for Voronoi regions - /** - * @const - */ - var LEFT_VORONOI_REGION = -1; - /** - * @const - */ - var MIDDLE_VORONOI_REGION = 0; - /** - * @const - */ - var RIGHT_VORONOI_REGION = 1; - - // ## Collision Tests - - // Check if a point is inside a circle. - /** - * @param {Vector} p The point to test. - * @param {Circle} c The circle to test. - * @return {boolean} true if the point is inside the circle, false if it is not. - */ - function pointInCircle(p, c) { - var differenceV = T_VECTORS.pop() - .copy(p) - .sub(c["pos"]) - .sub(c["offset"]); - var radiusSq = c["r"] * c["r"]; - var distanceSq = differenceV.len2(); - T_VECTORS.push(differenceV); - // If the distance between is smaller than the radius then the point is inside the circle. - return distanceSq <= radiusSq; - } - SAT["pointInCircle"] = pointInCircle; - - // Check if a point is inside a convex polygon. - /** - * @param {Vector} p The point to test. - * @param {Polygon} poly The polygon to test. - * @return {boolean} true if the point is inside the polygon, false if it is not. - */ - function pointInPolygon(p, poly) { - TEST_POINT["pos"].copy(p); - T_RESPONSE.clear(); - var result = testPolygonPolygon(TEST_POINT, poly, T_RESPONSE); - if (result) { - result = T_RESPONSE["aInB"]; - } - return result; - } - SAT["pointInPolygon"] = pointInPolygon; - - // Check if two circles collide. - /** - * @param {Circle} a The first circle. - * @param {Circle} b The second circle. - * @param {Response=} response Response object (optional) that will be populated if - * the circles intersect. - * @return {boolean} true if the circles intersect, false if they don't. - */ - function testCircleCircle(a, b, response) { - // Check if the distance between the centers of the two - // circles is greater than their combined radius. - var differenceV = T_VECTORS.pop() - .copy(b["pos"]) - .add(b["offset"]) - .sub(a["pos"]) - .sub(a["offset"]); - var totalRadius = a["r"] + b["r"]; - var totalRadiusSq = totalRadius * totalRadius; - var distanceSq = differenceV.len2(); - // If the distance is bigger than the combined radius, they don't intersect. - if (distanceSq > totalRadiusSq) { - T_VECTORS.push(differenceV); - return false; - } - // They intersect. If we're calculating a response, calculate the overlap. - if (response) { - var dist = Math.sqrt(distanceSq); - response["a"] = a; - response["b"] = b; - response["overlap"] = totalRadius - dist; - response["overlapN"].copy(differenceV.normalize()); - response["overlapV"].copy(differenceV).scale(response["overlap"]); - response["aInB"] = a["r"] <= b["r"] && dist <= b["r"] - a["r"]; - response["bInA"] = b["r"] <= a["r"] && dist <= a["r"] - b["r"]; - } - T_VECTORS.push(differenceV); - return true; - } - SAT["testCircleCircle"] = testCircleCircle; - - // Check if a polygon and a circle collide. - /** - * @param {Polygon} polygon The polygon. - * @param {Circle} circle The circle. - * @param {Response=} response Response object (optional) that will be populated if - * they interset. - * @return {boolean} true if they intersect, false if they don't. - */ - function testPolygonCircle(polygon, circle, response) { - // Get the position of the circle relative to the polygon. - var circlePos = T_VECTORS.pop() - .copy(circle["pos"]) - .add(circle["offset"]) - .sub(polygon["pos"]); - var radius = circle["r"]; - var radius2 = radius * radius; - var points = polygon["calcPoints"]; - var len = points.length; - var edge = T_VECTORS.pop(); - var point = T_VECTORS.pop(); - - // For each edge in the polygon: - for (var i = 0; i < len; i++) { - var next = i === len - 1 ? 0 : i + 1; - var prev = i === 0 ? len - 1 : i - 1; - var overlap = 0; - var overlapN = null; - - // Get the edge. - edge.copy(polygon["edges"][i]); - // Calculate the center of the circle relative to the starting point of the edge. - point.copy(circlePos).sub(points[i]); - - // If the distance between the center of the circle and the point - // is bigger than the radius, the polygon is definitely not fully in - // the circle. - if (response && point.len2() > radius2) { - response["aInB"] = false; - } - - // Calculate which Voronoi region the center of the circle is in. - var region = voronoiRegion(edge, point); - // If it's the left region: - if (region === LEFT_VORONOI_REGION) { - // We need to make sure we're in the RIGHT_VORONOI_REGION of the previous edge. - edge.copy(polygon["edges"][prev]); - // Calculate the center of the circle relative the starting point of the previous edge - var point2 = T_VECTORS.pop().copy(circlePos).sub(points[prev]); - region = voronoiRegion(edge, point2); - if (region === RIGHT_VORONOI_REGION) { - // It's in the region we want. Check if the circle intersects the point. - var dist = point.len(); - if (dist > radius) { - // No intersection - T_VECTORS.push(circlePos); - T_VECTORS.push(edge); - T_VECTORS.push(point); - T_VECTORS.push(point2); - return false; - } else if (response) { - // It intersects, calculate the overlap. - response["bInA"] = false; - overlapN = point.normalize(); - overlap = radius - dist; - } - } - T_VECTORS.push(point2); - // If it's the right region: - } else if (region === RIGHT_VORONOI_REGION) { - // We need to make sure we're in the left region on the next edge - edge.copy(polygon["edges"][next]); - // Calculate the center of the circle relative to the starting point of the next edge. - point.copy(circlePos).sub(points[next]); - region = voronoiRegion(edge, point); - if (region === LEFT_VORONOI_REGION) { - // It's in the region we want. Check if the circle intersects the point. - var dist = point.len(); - if (dist > radius) { - // No intersection - T_VECTORS.push(circlePos); - T_VECTORS.push(edge); - T_VECTORS.push(point); - return false; - } else if (response) { - // It intersects, calculate the overlap. - response["bInA"] = false; - overlapN = point.normalize(); - overlap = radius - dist; - } - } - // Otherwise, it's the middle region: - } else { - // Need to check if the circle is intersecting the edge, - // Change the edge into its "edge normal". - var normal = edge.perp().normalize(); - // Find the perpendicular distance between the center of the - // circle and the edge. - var dist = point.dot(normal); - var distAbs = Math.abs(dist); - // If the circle is on the outside of the edge, there is no intersection. - if (dist > 0 && distAbs > radius) { - // No intersection - T_VECTORS.push(circlePos); - T_VECTORS.push(normal); - T_VECTORS.push(point); - return false; - } else if (response) { - // It intersects, calculate the overlap. - overlapN = normal; - overlap = radius - dist; - // If the center of the circle is on the outside of the edge, or part of the - // circle is on the outside, the circle is not fully inside the polygon. - if (dist >= 0 || overlap < 2 * radius) { - response["bInA"] = false; - } - } - } - - // If this is the smallest overlap we've seen, keep it. - // (overlapN may be null if the circle was in the wrong Voronoi region). - if ( - overlapN && - response && - Math.abs(overlap) < Math.abs(response["overlap"]) - ) { - response["overlap"] = overlap; - response["overlapN"].copy(overlapN); - } - } + // Subtract another vector from this one. + /** + * @param {Vector} other The other Vector. + * @return {Vector} This for chaiing. + */ + Vector.prototype['sub'] = Vector.prototype.sub = function (other) { + this['x'] -= other['x']; + this['y'] -= other['y']; + return this; + }; - // Calculate the final overlap vector - based on the smallest overlap. - if (response) { - response["a"] = polygon; - response["b"] = circle; - response["overlapV"] - .copy(response["overlapN"]) - .scale(response["overlap"]); - } + // Scale this vector. An independent scaling factor can be provided + // for each axis, or a single scaling factor that will scale both `x` and `y`. + /** + * @param {number} x The scaling factor in the x direction. + * @param {?number=} y The scaling factor in the y direction. If this + * is not specified, the x scaling factor will be used. + * @return {Vector} This for chaining. + */ + Vector.prototype['scale'] = Vector.prototype.scale = function (x, y) { + this['x'] *= x; + this['y'] *= typeof y != 'undefined' ? y : x; + return this; + }; + + // Project this vector on to another vector. + /** + * @param {Vector} other The vector to project onto. + * @return {Vector} This for chaining. + */ + Vector.prototype['project'] = Vector.prototype.project = function (other) { + var amt = this.dot(other) / other.len2(); + this['x'] = amt * other['x']; + this['y'] = amt * other['y']; + return this; + }; + + // Project this vector onto a vector of unit length. This is slightly more efficient + // than `project` when dealing with unit vectors. + /** + * @param {Vector} other The unit vector to project onto. + * @return {Vector} This for chaining. + */ + Vector.prototype['projectN'] = Vector.prototype.projectN = function (other) { + var amt = this.dot(other); + this['x'] = amt * other['x']; + this['y'] = amt * other['y']; + return this; + }; + + // Reflect this vector on an arbitrary axis. + /** + * @param {Vector} axis The vector representing the axis. + * @return {Vector} This for chaining. + */ + Vector.prototype['reflect'] = Vector.prototype.reflect = function (axis) { + var x = this['x']; + var y = this['y']; + this.project(axis).scale(2); + this['x'] -= x; + this['y'] -= y; + return this; + }; + + // Reflect this vector on an arbitrary axis (represented by a unit vector). This is + // slightly more efficient than `reflect` when dealing with an axis that is a unit vector. + /** + * @param {Vector} axis The unit vector representing the axis. + * @return {Vector} This for chaining. + */ + Vector.prototype['reflectN'] = Vector.prototype.reflectN = function (axis) { + var x = this['x']; + var y = this['y']; + this.projectN(axis).scale(2); + this['x'] -= x; + this['y'] -= y; + return this; + }; + + // Get the dot product of this vector and another. + /** + * @param {Vector} other The vector to dot this one against. + * @return {number} The dot product. + */ + Vector.prototype['dot'] = Vector.prototype.dot = function (other) { + return this['x'] * other['x'] + this['y'] * other['y']; + }; + + // Get the squared length of this vector. + /** + * @return {number} The length^2 of this vector. + */ + Vector.prototype['len2'] = Vector.prototype.len2 = function () { + return this.dot(this); + }; + + // Get the length of this vector. + /** + * @return {number} The length of this vector. + */ + Vector.prototype['len'] = Vector.prototype.len = function () { + return Math.sqrt(this.len2()); + }; + + // ## Circle + // + // Represents a circle with a position and a radius. + + // Create a new circle, optionally passing in a position and/or radius. If no position + // is given, the circle will be at `(0,0)`. If no radius is provided, the circle will + // have a radius of `0`. + /** + * @param {Vector=} pos A vector representing the position of the center of the circle + * @param {?number=} r The radius of the circle + * @constructor + */ + function Circle(pos, r) { + this['pos'] = pos || new Vector(); + this['r'] = r || 0; + this['offset'] = new Vector(); + } + SAT['Circle'] = Circle; + + // Compute the axis-aligned bounding box (AABB) of this Circle. + // + // Note: Returns a _new_ `Box` each time you call this. + /** + * @return {Polygon} The AABB + */ + Circle.prototype['getAABBAsBox'] = Circle.prototype.getAABBAsBox = function () { + var r = this['r']; + var corner = this['pos'].clone().add(this['offset']).sub(new Vector(r, r)); + return new Box(corner, r * 2, r * 2); + }; + + // Compute the axis-aligned bounding box (AABB) of this Circle. + // + // Note: Returns a _new_ `Polygon` each time you call this. + /** + * @return {Polygon} The AABB + */ + Circle.prototype['getAABB'] = Circle.prototype.getAABB = function () { + return this.getAABBAsBox().toPolygon(); + }; + + // Set the current offset to apply to the radius. + /** + * @param {Vector} offset The new offset vector. + * @return {Circle} This for chaining. + */ + Circle.prototype['setOffset'] = Circle.prototype.setOffset = function (offset) { + this['offset'] = offset; + return this; + }; + + // ## Polygon + // + // Represents a *convex* polygon with any number of points (specified in counter-clockwise order) + // + // Note: Do _not_ manually change the `points`, `angle`, or `offset` properties. Use the + // provided setters. Otherwise the calculated properties will not be updated correctly. + // + // `pos` can be changed directly. + + // Create a new polygon, passing in a position vector, and an array of points (represented + // by vectors relative to the position vector). If no position is passed in, the position + // of the polygon will be `(0,0)`. + /** + * @param {Vector=} pos A vector representing the origin of the polygon. (all other + * points are relative to this one) + * @param {Array=} points An array of vectors representing the points in the polygon, + * in counter-clockwise order. + * @constructor + */ + function Polygon(pos, points) { + this['pos'] = pos || new Vector(); + this['angle'] = 0; + this['offset'] = new Vector(); + this.setPoints(points || []); + } + SAT['Polygon'] = Polygon; + + // Set the points of the polygon. Any consecutive duplicate points will be combined. + // + // Note: The points are counter-clockwise *with respect to the coordinate system*. + // If you directly draw the points on a screen that has the origin at the top-left corner + // it will _appear_ visually that the points are being specified clockwise. This is just + // because of the inversion of the Y-axis when being displayed. + /** + * @param {Array=} points An array of vectors representing the points in the polygon, + * in counter-clockwise order. + * @return {Polygon} This for chaining. + */ + Polygon.prototype['setPoints'] = Polygon.prototype.setPoints = function (points) { + // Only re-allocate if this is a new polygon or the number of points has changed. + var lengthChanged = !this['points'] || this['points'].length !== points.length; + if (lengthChanged) { + var i; + var calcPoints = this['calcPoints'] = []; + var edges = this['edges'] = []; + var normals = this['normals'] = []; + // Allocate the vector arrays for the calculated properties + for (i = 0; i < points.length; i++) { + // Remove consecutive duplicate points + var p1 = points[i]; + var p2 = i < points.length - 1 ? points[i + 1] : points[0]; + if (p1 !== p2 && p1.x === p2.x && p1.y === p2.y) { + points.splice(i, 1); + i -= 1; + continue; + } + calcPoints.push(new Vector()); + edges.push(new Vector()); + normals.push(new Vector()); + } + } + this['points'] = points; + this._recalc(); + return this; + }; + + // Set the current rotation angle of the polygon. + /** + * @param {number} angle The current rotation angle (in radians). + * @return {Polygon} This for chaining. + */ + Polygon.prototype['setAngle'] = Polygon.prototype.setAngle = function (angle) { + this['angle'] = angle; + this._recalc(); + return this; + }; + + // Set the current offset to apply to the `points` before applying the `angle` rotation. + /** + * @param {Vector} offset The new offset vector. + * @return {Polygon} This for chaining. + */ + Polygon.prototype['setOffset'] = Polygon.prototype.setOffset = function (offset) { + this['offset'] = offset; + this._recalc(); + return this; + }; + + // Rotates this polygon counter-clockwise around the origin of *its local coordinate system* (i.e. `pos`). + // + // Note: This changes the **original** points (so any `angle` will be applied on top of this rotation). + /** + * @param {number} angle The angle to rotate (in radians) + * @return {Polygon} This for chaining. + */ + Polygon.prototype['rotate'] = Polygon.prototype.rotate = function (angle) { + var points = this['points']; + var len = points.length; + for (var i = 0; i < len; i++) { + points[i].rotate(angle); + } + this._recalc(); + return this; + }; + + // Translates the points of this polygon by a specified amount relative to the origin of *its own coordinate + // system* (i.e. `pos`). + // + // This is most useful to change the "center point" of a polygon. If you just want to move the whole polygon, change + // the coordinates of `pos`. + // + // Note: This changes the **original** points (so any `offset` will be applied on top of this translation) + /** + * @param {number} x The horizontal amount to translate. + * @param {number} y The vertical amount to translate. + * @return {Polygon} This for chaining. + */ + Polygon.prototype['translate'] = Polygon.prototype.translate = function (x, y) { + var points = this['points']; + var len = points.length; + for (var i = 0; i < len; i++) { + points[i]['x'] += x; + points[i]['y'] += y; + } + this._recalc(); + return this; + }; + + + // Computes the calculated collision polygon. Applies the `angle` and `offset` to the original points then recalculates the + // edges and normals of the collision polygon. + /** + * @return {Polygon} This for chaining. + */ + Polygon.prototype._recalc = function () { + // Calculated points - this is what is used for underlying collisions and takes into account + // the angle/offset set on the polygon. + var calcPoints = this['calcPoints']; + // The edges here are the direction of the `n`th edge of the polygon, relative to + // the `n`th point. If you want to draw a given edge from the edge value, you must + // first translate to the position of the starting point. + var edges = this['edges']; + // The normals here are the direction of the normal for the `n`th edge of the polygon, relative + // to the position of the `n`th point. If you want to draw an edge normal, you must first + // translate to the position of the starting point. + var normals = this['normals']; + // Copy the original points array and apply the offset/angle + var points = this['points']; + var offset = this['offset']; + var angle = this['angle']; + var len = points.length; + var i; + for (i = 0; i < len; i++) { + var calcPoint = calcPoints[i].copy(points[i]); + calcPoint['x'] += offset['x']; + calcPoint['y'] += offset['y']; + if (angle !== 0) { + calcPoint.rotate(angle); + } + } + // Calculate the edges/normals + for (i = 0; i < len; i++) { + var p1 = calcPoints[i]; + var p2 = i < len - 1 ? calcPoints[i + 1] : calcPoints[0]; + var e = edges[i].copy(p2).sub(p1); + normals[i].copy(e).perp().normalize(); + } + return this; + }; + + + // Compute the axis-aligned bounding box. Any current state + // (translations/rotations) will be applied before constructing the AABB. + // + // Note: Returns a _new_ `Box` each time you call this. + /** + * @return {Polygon} The AABB + */ + Polygon.prototype['getAABBAsBox'] = Polygon.prototype.getAABBAsBox = function () { + var points = this['calcPoints']; + var len = points.length; + var xMin = points[0]['x']; + var yMin = points[0]['y']; + var xMax = points[0]['x']; + var yMax = points[0]['y']; + for (var i = 1; i < len; i++) { + var point = points[i]; + if (point['x'] < xMin) { + xMin = point['x']; + } + else if (point['x'] > xMax) { + xMax = point['x']; + } + if (point['y'] < yMin) { + yMin = point['y']; + } + else if (point['y'] > yMax) { + yMax = point['y']; + } + } + return new Box(this['pos'].clone().add(new Vector(xMin, yMin)), xMax - xMin, yMax - yMin); + }; + + + // Compute the axis-aligned bounding box. Any current state + // (translations/rotations) will be applied before constructing the AABB. + // + // Note: Returns a _new_ `Polygon` each time you call this. + /** + * @return {Polygon} The AABB + */ + Polygon.prototype['getAABB'] = Polygon.prototype.getAABB = function () { + return this.getAABBAsBox().toPolygon(); + }; + + // Compute the centroid (geometric center) of the polygon. Any current state + // (translations/rotations) will be applied before computing the centroid. + // + // See https://en.wikipedia.org/wiki/Centroid#Centroid_of_a_polygon + // + // Note: Returns a _new_ `Vector` each time you call this. + /** + * @return {Vector} A Vector that contains the coordinates of the Centroid. + */ + Polygon.prototype['getCentroid'] = Polygon.prototype.getCentroid = function () { + var points = this['calcPoints']; + var len = points.length; + var cx = 0; + var cy = 0; + var ar = 0; + for (var i = 0; i < len; i++) { + var p1 = points[i]; + var p2 = i === len - 1 ? points[0] : points[i + 1]; // Loop around if last point + var a = p1['x'] * p2['y'] - p2['x'] * p1['y']; + cx += (p1['x'] + p2['x']) * a; + cy += (p1['y'] + p2['y']) * a; + ar += a; + } + ar = ar * 3; // we want 1 / 6 the area and we currently have 2*area + cx = cx / ar; + cy = cy / ar; + return new Vector(cx, cy); + }; + + + // ## Box + // + // Represents an axis-aligned box, with a width and height. + + + // Create a new box, with the specified position, width, and height. If no position + // is given, the position will be `(0,0)`. If no width or height are given, they will + // be set to `0`. + /** + * @param {Vector=} pos A vector representing the bottom-left of the box (i.e. the smallest x and smallest y value). + * @param {?number=} w The width of the box. + * @param {?number=} h The height of the box. + * @constructor + */ + function Box(pos, w, h) { + this['pos'] = pos || new Vector(); + this['w'] = w || 0; + this['h'] = h || 0; + } + SAT['Box'] = Box; + + // Returns a polygon whose edges are the same as this box. + /** + * @return {Polygon} A new Polygon that represents this box. + */ + Box.prototype['toPolygon'] = Box.prototype.toPolygon = function () { + var pos = this['pos']; + var w = this['w']; + var h = this['h']; + return new Polygon(new Vector(pos['x'], pos['y']), [ + new Vector(), new Vector(w, 0), + new Vector(w, h), new Vector(0, h) + ]); + }; + + // ## Response + // + // An object representing the result of an intersection. Contains: + // - The two objects participating in the intersection + // - The vector representing the minimum change necessary to extract the first object + // from the second one (as well as a unit vector in that direction and the magnitude + // of the overlap) + // - Whether the first object is entirely inside the second, and vice versa. + /** + * @constructor + */ + function Response() { + this['a'] = null; + this['b'] = null; + this['overlapN'] = new Vector(); + this['overlapV'] = new Vector(); + this.clear(); + } + SAT['Response'] = Response; + + // Set some values of the response back to their defaults. Call this between tests if + // you are going to reuse a single Response object for multiple intersection tests (recommented + // as it will avoid allcating extra memory) + /** + * @return {Response} This for chaining + */ + Response.prototype['clear'] = Response.prototype.clear = function () { + this['aInB'] = true; + this['bInA'] = true; + this['overlap'] = Number.MAX_VALUE; + return this; + }; + + // ## Object Pools + + // A pool of `Vector` objects that are used in calculations to avoid + // allocating memory. + /** + * @type {Array} + */ + var T_VECTORS = []; + for (var i = 0; i < 10; i++) { T_VECTORS.push(new Vector()); } + + // A pool of arrays of numbers used in calculations to avoid allocating + // memory. + /** + * @type {Array>} + */ + var T_ARRAYS = []; + for (var i = 0; i < 5; i++) { T_ARRAYS.push([]); } + + // Temporary response used for polygon hit detection. + /** + * @type {Response} + */ + var T_RESPONSE = new Response(); + + // Tiny "point" polygon used for polygon hit detection. + /** + * @type {Polygon} + */ + var TEST_POINT = new Box(new Vector(), 0.000001, 0.000001).toPolygon(); + + // ## Helper Functions + + // Flattens the specified array of points onto a unit vector axis, + // resulting in a one dimensional range of the minimum and + // maximum value on that axis. + /** + * @param {Array} points The points to flatten. + * @param {Vector} normal The unit vector axis to flatten on. + * @param {Array} result An array. After calling this function, + * result[0] will be the minimum value, + * result[1] will be the maximum value. + */ + function flattenPointsOn(points, normal, result) { + var min = Number.MAX_VALUE; + var max = -Number.MAX_VALUE; + var len = points.length; + for (var i = 0; i < len; i++) { + // The magnitude of the projection of the point onto the normal + var dot = points[i].dot(normal); + if (dot < min) { min = dot; } + if (dot > max) { max = dot; } + } + result[0] = min; result[1] = max; + } + + // Check whether two convex polygons are separated by the specified + // axis (must be a unit vector). + /** + * @param {Vector} aPos The position of the first polygon. + * @param {Vector} bPos The position of the second polygon. + * @param {Array} aPoints The points in the first polygon. + * @param {Array} bPoints The points in the second polygon. + * @param {Vector} axis The axis (unit sized) to test against. The points of both polygons + * will be projected onto this axis. + * @param {Response=} response A Response object (optional) which will be populated + * if the axis is not a separating axis. + * @return {boolean} true if it is a separating axis, false otherwise. If false, + * and a response is passed in, information about how much overlap and + * the direction of the overlap will be populated. + */ + function isSeparatingAxis(aPos, bPos, aPoints, bPoints, axis, response) { + var rangeA = T_ARRAYS.pop(); + var rangeB = T_ARRAYS.pop(); + // The magnitude of the offset between the two polygons + var offsetV = T_VECTORS.pop().copy(bPos).sub(aPos); + var projectedOffset = offsetV.dot(axis); + // Project the polygons onto the axis. + flattenPointsOn(aPoints, axis, rangeA); + flattenPointsOn(bPoints, axis, rangeB); + // Move B's range to its position relative to A. + rangeB[0] += projectedOffset; + rangeB[1] += projectedOffset; + // Check if there is a gap. If there is, this is a separating axis and we can stop + if (rangeA[0] > rangeB[1] || rangeB[0] > rangeA[1]) { + T_VECTORS.push(offsetV); + T_ARRAYS.push(rangeA); + T_ARRAYS.push(rangeB); + return true; + } + // This is not a separating axis. If we're calculating a response, calculate the overlap. + if (response) { + var overlap = 0; + // A starts further left than B + if (rangeA[0] < rangeB[0]) { + response['aInB'] = false; + // A ends before B does. We have to pull A out of B + if (rangeA[1] < rangeB[1]) { + overlap = rangeA[1] - rangeB[0]; + response['bInA'] = false; + // B is fully inside A. Pick the shortest way out. + } else { + var option1 = rangeA[1] - rangeB[0]; + var option2 = rangeB[1] - rangeA[0]; + overlap = option1 < option2 ? option1 : -option2; + } + // B starts further left than A + } else { + response['bInA'] = false; + // B ends before A ends. We have to push A out of B + if (rangeA[1] > rangeB[1]) { + overlap = rangeA[0] - rangeB[1]; + response['aInB'] = false; + // A is fully inside B. Pick the shortest way out. + } else { + var option1 = rangeA[1] - rangeB[0]; + var option2 = rangeB[1] - rangeA[0]; + overlap = option1 < option2 ? option1 : -option2; + } + } + // If this is the smallest amount of overlap we've seen so far, set it as the minimum overlap. + var absOverlap = Math.abs(overlap); + if (absOverlap < response['overlap']) { + response['overlap'] = absOverlap; + response['overlapN'].copy(axis); + if (overlap < 0) { + response['overlapN'].reverse(); + } + } + } + T_VECTORS.push(offsetV); + T_ARRAYS.push(rangeA); + T_ARRAYS.push(rangeB); + return false; + } + SAT['isSeparatingAxis'] = isSeparatingAxis; + + // Calculates which Voronoi region a point is on a line segment. + // It is assumed that both the line and the point are relative to `(0,0)` + // + // | (0) | + // (-1) [S]--------------[E] (1) + // | (0) | + /** + * @param {Vector} line The line segment. + * @param {Vector} point The point. + * @return {number} LEFT_VORONOI_REGION (-1) if it is the left region, + * MIDDLE_VORONOI_REGION (0) if it is the middle region, + * RIGHT_VORONOI_REGION (1) if it is the right region. + */ + function voronoiRegion(line, point) { + var len2 = line.len2(); + var dp = point.dot(line); + // If the point is beyond the start of the line, it is in the + // left voronoi region. + if (dp < 0) { return LEFT_VORONOI_REGION; } + // If the point is beyond the end of the line, it is in the + // right voronoi region. + else if (dp > len2) { return RIGHT_VORONOI_REGION; } + // Otherwise, it's in the middle one. + else { return MIDDLE_VORONOI_REGION; } + } + // Constants for Voronoi regions + /** + * @const + */ + var LEFT_VORONOI_REGION = -1; + /** + * @const + */ + var MIDDLE_VORONOI_REGION = 0; + /** + * @const + */ + var RIGHT_VORONOI_REGION = 1; + + // ## Collision Tests + + // Check if a point is inside a circle. + /** + * @param {Vector} p The point to test. + * @param {Circle} c The circle to test. + * @return {boolean} true if the point is inside the circle, false if it is not. + */ + function pointInCircle(p, c) { + var differenceV = T_VECTORS.pop().copy(p).sub(c['pos']).sub(c['offset']); + var radiusSq = c['r'] * c['r']; + var distanceSq = differenceV.len2(); + T_VECTORS.push(differenceV); + // If the distance between is smaller than the radius then the point is inside the circle. + return distanceSq <= radiusSq; + } + SAT['pointInCircle'] = pointInCircle; + + // Check if a point is inside a convex polygon. + /** + * @param {Vector} p The point to test. + * @param {Polygon} poly The polygon to test. + * @return {boolean} true if the point is inside the polygon, false if it is not. + */ + function pointInPolygon(p, poly) { + TEST_POINT['pos'].copy(p); + T_RESPONSE.clear(); + var result = testPolygonPolygon(TEST_POINT, poly, T_RESPONSE); + if (result) { + result = T_RESPONSE['aInB']; + } + return result; + } + SAT['pointInPolygon'] = pointInPolygon; + + // Check if two circles collide. + /** + * @param {Circle} a The first circle. + * @param {Circle} b The second circle. + * @param {Response=} response Response object (optional) that will be populated if + * the circles intersect. + * @return {boolean} true if the circles intersect, false if they don't. + */ + function testCircleCircle(a, b, response) { + // Check if the distance between the centers of the two + // circles is greater than their combined radius. + var differenceV = T_VECTORS.pop().copy(b['pos']).add(b['offset']).sub(a['pos']).sub(a['offset']); + var totalRadius = a['r'] + b['r']; + var totalRadiusSq = totalRadius * totalRadius; + var distanceSq = differenceV.len2(); + // If the distance is bigger than the combined radius, they don't intersect. + if (distanceSq > totalRadiusSq) { + T_VECTORS.push(differenceV); + return false; + } + // They intersect. If we're calculating a response, calculate the overlap. + if (response) { + var dist = Math.sqrt(distanceSq); + response['a'] = a; + response['b'] = b; + response['overlap'] = totalRadius - dist; + response['overlapN'].copy(differenceV.normalize()); + response['overlapV'].copy(differenceV).scale(response['overlap']); + response['aInB'] = a['r'] <= b['r'] && dist <= b['r'] - a['r']; + response['bInA'] = b['r'] <= a['r'] && dist <= a['r'] - b['r']; + } + T_VECTORS.push(differenceV); + return true; + } + SAT['testCircleCircle'] = testCircleCircle; + + // Check if a polygon and a circle collide. + /** + * @param {Polygon} polygon The polygon. + * @param {Circle} circle The circle. + * @param {Response=} response Response object (optional) that will be populated if + * they interset. + * @return {boolean} true if they intersect, false if they don't. + */ + function testPolygonCircle(polygon, circle, response) { + // Get the position of the circle relative to the polygon. + var circlePos = T_VECTORS.pop().copy(circle['pos']).add(circle['offset']).sub(polygon['pos']); + var radius = circle['r']; + var radius2 = radius * radius; + var points = polygon['calcPoints']; + var len = points.length; + var edge = T_VECTORS.pop(); + var point = T_VECTORS.pop(); + + // For each edge in the polygon: + for (var i = 0; i < len; i++) { + var next = i === len - 1 ? 0 : i + 1; + var prev = i === 0 ? len - 1 : i - 1; + var overlap = 0; + var overlapN = null; + + // Get the edge. + edge.copy(polygon['edges'][i]); + // Calculate the center of the circle relative to the starting point of the edge. + point.copy(circlePos).sub(points[i]); + + // If the distance between the center of the circle and the point + // is bigger than the radius, the polygon is definitely not fully in + // the circle. + if (response && point.len2() > radius2) { + response['aInB'] = false; + } + + // Calculate which Voronoi region the center of the circle is in. + var region = voronoiRegion(edge, point); + // If it's the left region: + if (region === LEFT_VORONOI_REGION) { + // We need to make sure we're in the RIGHT_VORONOI_REGION of the previous edge. + edge.copy(polygon['edges'][prev]); + // Calculate the center of the circle relative the starting point of the previous edge + var point2 = T_VECTORS.pop().copy(circlePos).sub(points[prev]); + region = voronoiRegion(edge, point2); + if (region === RIGHT_VORONOI_REGION) { + // It's in the region we want. Check if the circle intersects the point. + var dist = point.len(); + if (dist > radius) { + // No intersection T_VECTORS.push(circlePos); T_VECTORS.push(edge); T_VECTORS.push(point); - return true; + T_VECTORS.push(point2); + return false; + } else if (response) { + // It intersects, calculate the overlap. + response['bInA'] = false; + overlapN = point.normalize(); + overlap = radius - dist; } - SAT["testPolygonCircle"] = testPolygonCircle; - - // Check if a circle and a polygon collide. - // - // **NOTE:** This is slightly less efficient than polygonCircle as it just - // runs polygonCircle and reverses everything at the end. - /** - * @param {Circle} circle The circle. - * @param {Polygon} polygon The polygon. - * @param {Response=} response Response object (optional) that will be populated if - * they interset. - * @return {boolean} true if they intersect, false if they don't. - */ - function testCirclePolygon(circle, polygon, response) { - // Test the polygon against the circle. - var result = testPolygonCircle(polygon, circle, response); - if (result && response) { - // Swap A and B in the response. - var a = response["a"]; - var aInB = response["aInB"]; - response["overlapN"].reverse(); - response["overlapV"].reverse(); - response["a"] = response["b"]; - response["b"] = a; - response["aInB"] = response["bInA"]; - response["bInA"] = aInB; - } - return result; + } + T_VECTORS.push(point2); + // If it's the right region: + } else if (region === RIGHT_VORONOI_REGION) { + // We need to make sure we're in the left region on the next edge + edge.copy(polygon['edges'][next]); + // Calculate the center of the circle relative to the starting point of the next edge. + point.copy(circlePos).sub(points[next]); + region = voronoiRegion(edge, point); + if (region === LEFT_VORONOI_REGION) { + // It's in the region we want. Check if the circle intersects the point. + var dist = point.len(); + if (dist > radius) { + // No intersection + T_VECTORS.push(circlePos); + T_VECTORS.push(edge); + T_VECTORS.push(point); + return false; + } else if (response) { + // It intersects, calculate the overlap. + response['bInA'] = false; + overlapN = point.normalize(); + overlap = radius - dist; } - SAT["testCirclePolygon"] = testCirclePolygon; - - // Checks whether polygons collide. - /** - * @param {Polygon} a The first polygon. - * @param {Polygon} b The second polygon. - * @param {Response=} response Response object (optional) that will be populated if - * they interset. - * @return {boolean} true if they intersect, false if they don't. - */ - function testPolygonPolygon(a, b, response) { - var aPoints = a["calcPoints"]; - var aLen = aPoints.length; - var bPoints = b["calcPoints"]; - var bLen = bPoints.length; - // If any of the edge normals of A is a separating axis, no intersection. - for (var i = 0; i < aLen; i++) { - if ( - isSeparatingAxis( - a["pos"], - b["pos"], - aPoints, - bPoints, - a["normals"][i], - response, - ) - ) { - return false; - } - } - // If any of the edge normals of B is a separating axis, no intersection. - for (var i = 0; i < bLen; i++) { - if ( - isSeparatingAxis( - a["pos"], - b["pos"], - aPoints, - bPoints, - b["normals"][i], - response, - ) - ) { - return false; - } - } - // Since none of the edge normals of A or B are a separating axis, there is an intersection - // and we've already calculated the smallest overlap (in isSeparatingAxis). Calculate the - // final overlap vector. - if (response) { - response["a"] = a; - response["b"] = b; - response["overlapV"] - .copy(response["overlapN"]) - .scale(response["overlap"]); - } - return true; + } + // Otherwise, it's the middle region: + } else { + // Need to check if the circle is intersecting the edge, + // Change the edge into its "edge normal". + var normal = edge.perp().normalize(); + // Find the perpendicular distance between the center of the + // circle and the edge. + var dist = point.dot(normal); + var distAbs = Math.abs(dist); + // If the circle is on the outside of the edge, there is no intersection. + if (dist > 0 && distAbs > radius) { + // No intersection + T_VECTORS.push(circlePos); + T_VECTORS.push(normal); + T_VECTORS.push(point); + return false; + } else if (response) { + // It intersects, calculate the overlap. + overlapN = normal; + overlap = radius - dist; + // If the center of the circle is on the outside of the edge, or part of the + // circle is on the outside, the circle is not fully inside the polygon. + if (dist >= 0 || overlap < 2 * radius) { + response['bInA'] = false; } - SAT["testPolygonPolygon"] = testPolygonPolygon; + } + } - return SAT; - }); + // If this is the smallest overlap we've seen, keep it. + // (overlapN may be null if the circle was in the wrong Voronoi region). + if (overlapN && response && Math.abs(overlap) < Math.abs(response['overlap'])) { + response['overlap'] = overlap; + response['overlapN'].copy(overlapN); + } + } + + // Calculate the final overlap vector - based on the smallest overlap. + if (response) { + response['a'] = polygon; + response['b'] = circle; + response['overlapV'].copy(response['overlapN']).scale(response['overlap']); + } + T_VECTORS.push(circlePos); + T_VECTORS.push(edge); + T_VECTORS.push(point); + return true; + } + SAT['testPolygonCircle'] = testPolygonCircle; + + // Check if a circle and a polygon collide. + // + // **NOTE:** This is slightly less efficient than polygonCircle as it just + // runs polygonCircle and reverses everything at the end. + /** + * @param {Circle} circle The circle. + * @param {Polygon} polygon The polygon. + * @param {Response=} response Response object (optional) that will be populated if + * they interset. + * @return {boolean} true if they intersect, false if they don't. + */ + function testCirclePolygon(circle, polygon, response) { + // Test the polygon against the circle. + var result = testPolygonCircle(polygon, circle, response); + if (result && response) { + // Swap A and B in the response. + var a = response['a']; + var aInB = response['aInB']; + response['overlapN'].reverse(); + response['overlapV'].reverse(); + response['a'] = response['b']; + response['b'] = a; + response['aInB'] = response['bInA']; + response['bInA'] = aInB; + } + return result; + } + SAT['testCirclePolygon'] = testCirclePolygon; + + // Checks whether polygons collide. + /** + * @param {Polygon} a The first polygon. + * @param {Polygon} b The second polygon. + * @param {Response=} response Response object (optional) that will be populated if + * they interset. + * @return {boolean} true if they intersect, false if they don't. + */ + function testPolygonPolygon(a, b, response) { + var aPoints = a['calcPoints']; + var aLen = aPoints.length; + var bPoints = b['calcPoints']; + var bLen = bPoints.length; + // If any of the edge normals of A is a separating axis, no intersection. + for (var i = 0; i < aLen; i++) { + if (isSeparatingAxis(a['pos'], b['pos'], aPoints, bPoints, a['normals'][i], response)) { + return false; + } + } + // If any of the edge normals of B is a separating axis, no intersection. + for (var i = 0; i < bLen; i++) { + if (isSeparatingAxis(a['pos'], b['pos'], aPoints, bPoints, b['normals'][i], response)) { + return false; + } + } + // Since none of the edge normals of A or B are a separating axis, there is an intersection + // and we've already calculated the smallest overlap (in isSeparatingAxis). Calculate the + // final overlap vector. + if (response) { + response['a'] = a; + response['b'] = b; + response['overlapV'].copy(response['overlapN']).scale(response['overlap']); + } + return true; + } + SAT['testPolygonPolygon'] = testPolygonPolygon; + + return SAT; +})); - /***/ - }, - /***/ "./src/base-system.ts": - /*!****************************!*\ +/***/ }), + +/***/ "./src/base-system.ts": +/*!****************************!*\ !*** ./src/base-system.ts ***! \****************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.BaseSystem = void 0; - const box_1 = __webpack_require__( - /*! ./bodies/box */ "./src/bodies/box.ts", - ); - const circle_1 = __webpack_require__( - /*! ./bodies/circle */ "./src/bodies/circle.ts", - ); - const ellipse_1 = __webpack_require__( - /*! ./bodies/ellipse */ "./src/bodies/ellipse.ts", - ); - const line_1 = __webpack_require__( - /*! ./bodies/line */ "./src/bodies/line.ts", - ); - const point_1 = __webpack_require__( - /*! ./bodies/point */ "./src/bodies/point.ts", - ); - const polygon_1 = __webpack_require__( - /*! ./bodies/polygon */ "./src/bodies/polygon.ts", - ); - const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); - const optimized_1 = __webpack_require__( - /*! ./optimized */ "./src/optimized.ts", - ); - const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); - /** - * very base collision system (create, insert, update, draw, remove) - */ - class BaseSystem extends model_1.RBush { - /** - * create point at position with options and add to system - */ - createPoint(position, options) { - const point = new point_1.Point(position, options); - this.insert(point); - return point; - } - /** - * create line at position with options and add to system - */ - createLine(start, end, options) { - const line = new line_1.Line(start, end, options); - this.insert(line); - return line; - } - /** - * create circle at position with options and add to system - */ - createCircle(position, radius, options) { - const circle = new circle_1.Circle(position, radius, options); - this.insert(circle); - return circle; - } - /** - * create box at position with options and add to system - */ - createBox(position, width, height, options) { - const box = new box_1.Box(position, width, height, options); - this.insert(box); - return box; - } - /** - * create ellipse at position with options and add to system - */ - createEllipse(position, radiusX, radiusY = radiusX, step, options) { - const ellipse = new ellipse_1.Ellipse( - position, - radiusX, - radiusY, - step, - options, - ); - this.insert(ellipse); - return ellipse; - } - /** - * create polygon at position with options and add to system - */ - createPolygon(position, points, options) { - const polygon = new polygon_1.Polygon(position, points, options); - this.insert(polygon); - return polygon; - } - /** - * re-insert body into collision tree and update its bbox - * every body can be part of only one system - */ - insert(body) { - body.bbox = body.getAABBAsBBox(); - if (body.system) { - // allow end if body inserted and not moved - if (!(0, utils_1.bodyMoved)(body)) { +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BaseSystem = void 0; +const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); +const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); +const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); +const box_1 = __webpack_require__(/*! ./bodies/box */ "./src/bodies/box.ts"); +const circle_1 = __webpack_require__(/*! ./bodies/circle */ "./src/bodies/circle.ts"); +const ellipse_1 = __webpack_require__(/*! ./bodies/ellipse */ "./src/bodies/ellipse.ts"); +const line_1 = __webpack_require__(/*! ./bodies/line */ "./src/bodies/line.ts"); +const point_1 = __webpack_require__(/*! ./bodies/point */ "./src/bodies/point.ts"); +const polygon_1 = __webpack_require__(/*! ./bodies/polygon */ "./src/bodies/polygon.ts"); +/** + * very base collision system (create, insert, update, draw, remove) + */ +class BaseSystem extends model_1.RBush { + /** + * create point at position with options and add to system + */ + createPoint(position, options) { + const point = new point_1.Point(position, options); + this.insert(point); + return point; + } + /** + * create line at position with options and add to system + */ + createLine(start, end, options) { + const line = new line_1.Line(start, end, options); + this.insert(line); + return line; + } + /** + * create circle at position with options and add to system + */ + createCircle(position, radius, options) { + const circle = new circle_1.Circle(position, radius, options); + this.insert(circle); + return circle; + } + /** + * create box at position with options and add to system + */ + createBox(position, width, height, options) { + const box = new box_1.Box(position, width, height, options); + this.insert(box); + return box; + } + /** + * create ellipse at position with options and add to system + */ + createEllipse(position, radiusX, radiusY = radiusX, step, options) { + const ellipse = new ellipse_1.Ellipse(position, radiusX, radiusY, step, options); + this.insert(ellipse); + return ellipse; + } + /** + * create polygon at position with options and add to system + */ + createPolygon(position, points, options) { + const polygon = new polygon_1.Polygon(position, points, options); + this.insert(polygon); + return polygon; + } + /** + * re-insert body into collision tree and update its bbox + * every body can be part of only one system + */ + insert(body) { + body.bbox = body.getAABBAsBBox(); + if (body.system) { + // allow end if body inserted and not moved + if (!(0, utils_1.bodyMoved)(body)) { return this; - } - // old bounding box *needs* to be removed - body.system.remove(body); } - // only then we update min, max - body.minX = body.bbox.minX - body.padding; - body.minY = body.bbox.minY - body.padding; - body.maxX = body.bbox.maxX + body.padding; - body.maxY = body.bbox.maxY + body.padding; - // reinsert bounding box to collision tree - return super.insert(body); - } - /** - * updates body in collision tree - */ - updateBody(body) { - body.updateBody(); - } - /** - * update all bodies aabb - */ - update() { - (0, optimized_1.forEach)(this.all(), (body) => { - this.updateBody(body); - }); - } - /** - * draw exact bodies colliders outline - */ - draw(context) { - (0, optimized_1.forEach)(this.all(), (body) => { - body.draw(context); - }); - } - /** - * draw bounding boxes hierarchy outline - */ - drawBVH(context) { - const drawChildren = (body) => { - (0, utils_1.drawBVH)(context, body); - if (body.children) { - (0, optimized_1.forEach)(body.children, drawChildren); - } - }; - (0, optimized_1.forEach)(this.data.children, drawChildren); - } - /** - * remove body aabb from collision tree - */ - remove(body, equals) { - body.system = undefined; - return super.remove(body, equals); - } - /** - * get object potential colliders - * @deprecated because it's slower to use than checkOne() or checkAll() - */ - getPotentials(body) { - // filter here is required as collides with self - return (0, optimized_1.filter)( - this.search(body), - (candidate) => candidate !== body, - ); - } - /** - * used to find body deep inside data with finder function returning boolean found or not - */ - traverse(traverseFunction, { children } = this.data) { - return children === null || children === void 0 - ? void 0 - : children.find((body, index) => { - if (!body) { - return false; - } - if ( - body.typeGroup && - traverseFunction(body, children, index) - ) { - return true; - } - // if callback returns true, ends forEach - if (body.children) { - this.traverse(traverseFunction, body); - } - }); - } + // old bounding box *needs* to be removed + body.system.remove(body); } - exports.BaseSystem = BaseSystem; + // only then we update min, max + body.minX = body.bbox.minX - body.padding; + body.minY = body.bbox.minY - body.padding; + body.maxX = body.bbox.maxX + body.padding; + body.maxY = body.bbox.maxY + body.padding; + // reinsert bounding box to collision tree + return super.insert(body); + } + /** + * updates body in collision tree + */ + updateBody(body) { + body.updateBody(); + } + /** + * update all bodies aabb + */ + update() { + (0, optimized_1.forEach)(this.all(), (body) => { + this.updateBody(body); + }); + } + /** + * draw exact bodies colliders outline + */ + draw(context) { + (0, optimized_1.forEach)(this.all(), (body) => { + body.draw(context); + }); + } + /** + * draw bounding boxes hierarchy outline + */ + drawBVH(context) { + const drawChildren = (body) => { + (0, utils_1.drawBVH)(context, body); + if (body.children) { + (0, optimized_1.forEach)(body.children, drawChildren); + } + }; + (0, optimized_1.forEach)(this.data.children, drawChildren); + } + /** + * remove body aabb from collision tree + */ + remove(body, equals) { + body.system = undefined; + return super.remove(body, equals); + } + /** + * get object potential colliders + * @deprecated because it's slower to use than checkOne() or checkAll() + */ + getPotentials(body) { + // filter here is required as collides with self + return (0, optimized_1.filter)(this.search(body), (candidate) => candidate !== body); + } + /** + * used to find body deep inside data with finder function returning boolean found or not + */ + traverse(traverseFunction, { children } = this.data) { + return children === null || children === void 0 ? void 0 : children.find((body, index) => { + if (!body) { + return false; + } + if (body.typeGroup && traverseFunction(body, children, index)) { + return true; + } + // if callback returns true, ends forEach + if (body.children) { + this.traverse(traverseFunction, body); + } + }); + } +} +exports.BaseSystem = BaseSystem; + - /***/ - }, +/***/ }), - /***/ "./src/bodies/box.ts": - /*!***************************!*\ +/***/ "./src/bodies/box.ts": +/*!***************************!*\ !*** ./src/bodies/box.ts ***! \***************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Box = void 0; - const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); - const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); - const polygon_1 = __webpack_require__( - /*! ./polygon */ "./src/bodies/polygon.ts", - ); +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Box = void 0; +const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); +const polygon_1 = __webpack_require__(/*! ./polygon */ "./src/bodies/polygon.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +/** + * collider - box + */ +class Box extends polygon_1.Polygon { + /** + * collider - box + */ + constructor(position, width, height, options) { + super(position, (0, utils_1.createBox)(width, height), options); /** - * collider - box + * type of body */ - class Box extends polygon_1.Polygon { - /** - * collider - box - */ - constructor(position, width, height, options) { - super(position, (0, utils_1.createBox)(width, height), options); - /** - * type of body - */ - this.type = model_1.BodyType.Box; - /** - * faster than type - */ - this.typeGroup = model_1.BodyGroup.Box; - /** - * boxes are convex - */ - this.isConvex = true; - this._width = width; - this._height = height; - } - /** - * get box width - */ - get width() { - return this._width; - } - /** - * set box width, update points - */ - set width(width) { - this._width = width; - this.afterUpdateSize(); - } - /** - * get box height - */ - get height() { - return this._height; - } - /** - * set box height, update points - */ - set height(height) { - this._height = height; - this.afterUpdateSize(); - } - /** - * after setting width/height update translate - * see https://github.com/Prozi/detect-collisions/issues/70 - */ - afterUpdateSize() { - if (this.isCentered) { - this.retranslate(false); - } - this.setPoints((0, utils_1.createBox)(this._width, this._height)); - if (this.isCentered) { - this.retranslate(); - } - } - /** - * do not attempt to use Polygon.updateIsConvex() - */ - updateIsConvex() { - return; - } - } - exports.Box = Box; - - /***/ - }, - - /***/ "./src/bodies/circle.ts": - /*!******************************!*\ - !*** ./src/bodies/circle.ts ***! - \******************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Circle = void 0; - const sat_1 = __webpack_require__( - /*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js", - ); - const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); - const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); + this.type = model_1.BodyType.Box; /** - * collider - circle + * faster than type */ - class Circle extends sat_1.Circle { - /** - * collider - circle - */ - constructor(position, radius, options) { - super((0, utils_1.ensureVectorPoint)(position), radius); - /** - * offset copy without angle applied - */ - this.offsetCopy = { x: 0, y: 0 }; - /** - * was the polygon modified and needs update in the next checkCollision - */ - this.dirty = false; - /* - * circles are convex - */ - this.isConvex = true; - /** - * circle type - */ - this.type = model_1.BodyType.Circle; - /** - * faster than type - */ - this.typeGroup = model_1.BodyGroup.Circle; - /** - * always centered - */ - this.isCentered = true; - (0, utils_1.extendBody)(this, options); - this.unscaledRadius = radius; - } - /** - * get this.pos.x - */ - get x() { - return this.pos.x; - } - /** - * updating this.pos.x by this.x = x updates AABB - */ - set x(x) { - this.pos.x = x; - this.markAsDirty(); - } - /** - * get this.pos.y - */ - get y() { - return this.pos.y; - } - /** - * updating this.pos.y by this.y = y updates AABB - */ - set y(y) { - this.pos.y = y; - this.markAsDirty(); - } - /** - * allow get scale - */ - get scale() { - return this.r / this.unscaledRadius; - } - /** - * shorthand for setScale() - */ - set scale(scale) { - this.setScale(scale); - } - /** - * scaleX = scale in case of Circles - */ - get scaleX() { - return this.scale; - } - /** - * scaleY = scale in case of Circles - */ - get scaleY() { - return this.scale; - } - /** - * group for collision filtering - */ - get group() { - return this._group; - } - set group(group) { - this._group = (0, utils_1.getGroup)(group); - } - /** - * update position - */ - setPosition(x, y, update = true) { - this.pos.x = x; - this.pos.y = y; - this.markAsDirty(update); - return this; - } - /** - * update scale - */ - setScale(scaleX, _scaleY = scaleX, update = true) { - this.r = this.unscaledRadius * Math.abs(scaleX); - this.markAsDirty(update); - return this; - } - /** - * set rotation - */ - setAngle(angle, update = true) { - this.angle = angle; - const { x, y } = this.getOffsetWithAngle(); - this.offset.x = x; - this.offset.y = y; - this.markAsDirty(update); - return this; - } - /** - * set offset from center - */ - setOffset(offset, update = true) { - this.offsetCopy.x = offset.x; - this.offsetCopy.y = offset.y; - const { x, y } = this.getOffsetWithAngle(); - this.offset.x = x; - this.offset.y = y; - this.markAsDirty(update); - return this; - } - /** - * get body bounding box, without padding - */ - getAABBAsBBox() { - const x = this.pos.x + this.offset.x; - const y = this.pos.y + this.offset.y; - return { - minX: x - this.r, - maxX: x + this.r, - minY: y - this.r, - maxY: y + this.r, - }; - } - /** - * Draws collider on a CanvasRenderingContext2D's current path - */ - draw(context) { - const x = this.pos.x + this.offset.x; - const y = this.pos.y + this.offset.y; - const r = Math.abs(this.r); - if (this.isTrigger) { - const max = Math.max(8, this.r); - for (let i = 0; i < max; i++) { + this.typeGroup = model_1.BodyGroup.Box; + /** + * boxes are convex + */ + this.isConvex = true; + this._width = width; + this._height = height; + } + /** + * get box width + */ + get width() { + return this._width; + } + /** + * set box width, update points + */ + set width(width) { + this._width = width; + this.afterUpdateSize(); + } + /** + * get box height + */ + get height() { + return this._height; + } + /** + * set box height, update points + */ + set height(height) { + this._height = height; + this.afterUpdateSize(); + } + /** + * after setting width/height update translate + * see https://github.com/Prozi/detect-collisions/issues/70 + */ + afterUpdateSize() { + if (this.isCentered) { + this.retranslate(false); + } + this.setPoints((0, utils_1.createBox)(this._width, this._height)); + if (this.isCentered) { + this.retranslate(); + } + } + /** + * do not attempt to use Polygon.updateIsConvex() + */ + updateIsConvex() { + return; + } +} +exports.Box = Box; + + +/***/ }), + +/***/ "./src/bodies/circle.ts": +/*!******************************!*\ + !*** ./src/bodies/circle.ts ***! + \******************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Circle = void 0; +const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); +/** + * collider - circle + */ +class Circle extends sat_1.Circle { + /** + * collider - circle + */ + constructor(position, radius, options) { + super((0, utils_1.ensureVectorPoint)(position), radius); + /** + * offset copy without angle applied + */ + this.offsetCopy = { x: 0, y: 0 }; + /** + * was the polygon modified and needs update in the next checkCollision + */ + this.dirty = false; + /* + * circles are convex + */ + this.isConvex = true; + /** + * circle type + */ + this.type = model_1.BodyType.Circle; + /** + * faster than type + */ + this.typeGroup = model_1.BodyGroup.Circle; + /** + * always centered + */ + this.isCentered = true; + (0, utils_1.extendBody)(this, options); + this.unscaledRadius = radius; + } + /** + * get this.pos.x + */ + get x() { + return this.pos.x; + } + /** + * updating this.pos.x by this.x = x updates AABB + */ + set x(x) { + this.pos.x = x; + this.markAsDirty(); + } + /** + * get this.pos.y + */ + get y() { + return this.pos.y; + } + /** + * updating this.pos.y by this.y = y updates AABB + */ + set y(y) { + this.pos.y = y; + this.markAsDirty(); + } + /** + * allow get scale + */ + get scale() { + return this.r / this.unscaledRadius; + } + /** + * shorthand for setScale() + */ + set scale(scale) { + this.setScale(scale); + } + /** + * scaleX = scale in case of Circles + */ + get scaleX() { + return this.scale; + } + /** + * scaleY = scale in case of Circles + */ + get scaleY() { + return this.scale; + } + /** + * group for collision filtering + */ + get group() { + return this._group; + } + set group(group) { + this._group = (0, utils_1.getGroup)(group); + } + /** + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true) { + (0, utils_1.move)(this, speed, updateNow); + return this; + } + /** + * update position BY TELEPORTING + */ + setPosition(x, y, updateNow = true) { + this.pos.x = x; + this.pos.y = y; + this.markAsDirty(updateNow); + return this; + } + /** + * update scale + */ + setScale(scaleX, _scaleY = scaleX, updateNow = true) { + this.r = this.unscaledRadius * Math.abs(scaleX); + this.markAsDirty(updateNow); + return this; + } + /** + * set rotation + */ + setAngle(angle, updateNow = true) { + this.angle = angle; + const { x, y } = this.getOffsetWithAngle(); + this.offset.x = x; + this.offset.y = y; + this.markAsDirty(updateNow); + return this; + } + /** + * set offset from center + */ + setOffset(offset, updateNow = true) { + this.offsetCopy.x = offset.x; + this.offsetCopy.y = offset.y; + const { x, y } = this.getOffsetWithAngle(); + this.offset.x = x; + this.offset.y = y; + this.markAsDirty(updateNow); + return this; + } + /** + * get body bounding box, without padding + */ + getAABBAsBBox() { + const x = this.pos.x + this.offset.x; + const y = this.pos.y + this.offset.y; + return { + minX: x - this.r, + maxX: x + this.r, + minY: y - this.r, + maxY: y + this.r + }; + } + /** + * Draws collider on a CanvasRenderingContext2D's current path + */ + draw(context) { + const x = this.pos.x + this.offset.x; + const y = this.pos.y + this.offset.y; + const r = Math.abs(this.r); + if (this.isTrigger) { + const max = Math.max(8, this.r); + for (let i = 0; i < max; i++) { const arc = (i / max) * 2 * Math.PI; const arcPrev = ((i - 1) / max) * 2 * Math.PI; const fromX = x + Math.cos(arcPrev) * this.r; @@ -3182,2676 +2548,2868 @@ which is good. See: http://baagoe.com/en/RandomMusings/hash/avalanche.xhtml const toX = x + Math.cos(arc) * this.r; const toY = y + Math.sin(arc) * this.r; (0, utils_1.dashLineTo)(context, fromX, fromY, toX, toY); - } - } else { - context.moveTo(x + r, y); - context.arc(x, y, r, 0, Math.PI * 2); - } - } - /** - * Draws Bounding Box on canvas context - */ - drawBVH(context) { - (0, utils_1.drawBVH)(context, this); - } - /** - * inner function for after position change update aabb in system - */ - updateBody(update = this.dirty) { - var _a; - if (update) { - (_a = this.system) === null || _a === void 0 - ? void 0 - : _a.insert(this); - this.dirty = false; - } - } - /** - * update instantly or mark as dirty - */ - markAsDirty(update = false) { - if (update) { - this.updateBody(true); - } else { - this.dirty = true; } - } - /** - * internal for getting offset with applied angle - */ - getOffsetWithAngle() { - if ((!this.offsetCopy.x && !this.offsetCopy.y) || !this.angle) { - return this.offsetCopy; - } - const sin = Math.sin(this.angle); - const cos = Math.cos(this.angle); - const x = this.offsetCopy.x * cos - this.offsetCopy.y * sin; - const y = this.offsetCopy.x * sin + this.offsetCopy.y * cos; - return { x, y }; - } } - exports.Circle = Circle; + else { + context.moveTo(x + r, y); + context.arc(x, y, r, 0, Math.PI * 2); + } + } + /** + * Draws Bounding Box on canvas context + */ + drawBVH(context) { + (0, utils_1.drawBVH)(context, this); + } + /** + * inner function for after position change update aabb in system + */ + updateBody(updateNow = this.dirty) { + var _a; + if (updateNow) { + (_a = this.system) === null || _a === void 0 ? void 0 : _a.insert(this); + this.dirty = false; + } + } + /** + * update instantly or mark as dirty + */ + markAsDirty(updateNow = false) { + if (updateNow) { + this.updateBody(true); + } + else { + this.dirty = true; + } + } + /** + * internal for getting offset with applied angle + */ + getOffsetWithAngle() { + if ((!this.offsetCopy.x && !this.offsetCopy.y) || !this.angle) { + return this.offsetCopy; + } + const sin = Math.sin(this.angle); + const cos = Math.cos(this.angle); + const x = this.offsetCopy.x * cos - this.offsetCopy.y * sin; + const y = this.offsetCopy.x * sin + this.offsetCopy.y * cos; + return { x, y }; + } +} +exports.Circle = Circle; - /***/ - }, - /***/ "./src/bodies/ellipse.ts": - /*!*******************************!*\ +/***/ }), + +/***/ "./src/bodies/ellipse.ts": +/*!*******************************!*\ !*** ./src/bodies/ellipse.ts ***! \*******************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Ellipse = void 0; - const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); - const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); - const polygon_1 = __webpack_require__( - /*! ./polygon */ "./src/bodies/polygon.ts", - ); +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Ellipse = void 0; +const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); +const polygon_1 = __webpack_require__(/*! ./polygon */ "./src/bodies/polygon.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +/** + * collider - ellipse + */ +class Ellipse extends polygon_1.Polygon { + /** + * collider - ellipse + */ + constructor(position, radiusX, radiusY = radiusX, step = (radiusX + radiusY) / Math.PI, options) { + super(position, (0, utils_1.createEllipse)(radiusX, radiusY, step), options); /** - * collider - ellipse + * ellipse type */ - class Ellipse extends polygon_1.Polygon { - /** - * collider - ellipse - */ - constructor( - position, - radiusX, - radiusY = radiusX, - step = (radiusX + radiusY) / Math.PI, - options, - ) { - super( - position, - (0, utils_1.createEllipse)(radiusX, radiusY, step), - options, - ); - /** - * ellipse type - */ - this.type = model_1.BodyType.Ellipse; - /** - * faster than type - */ - this.typeGroup = model_1.BodyGroup.Ellipse; - /** - * ellipses are convex - */ - this.isConvex = true; - this._radiusX = radiusX; - this._radiusY = radiusY; - this._step = step; - } - /** - * flag to set is body centered - */ - set isCentered(_isCentered) {} - /** - * is body centered? - */ - get isCentered() { - return true; - } - /** - * get ellipse step number - */ - get step() { - return this._step; - } - /** - * set ellipse step number - */ - set step(step) { - this._step = step; - this.setPoints( - (0, utils_1.createEllipse)( - this._radiusX, - this._radiusY, - this._step, - ), - ); - } - /** - * get ellipse radiusX - */ - get radiusX() { - return this._radiusX; - } - /** - * set ellipse radiusX, update points - */ - set radiusX(radiusX) { - this._radiusX = radiusX; - this.setPoints( - (0, utils_1.createEllipse)( - this._radiusX, - this._radiusY, - this._step, - ), - ); - } - /** - * get ellipse radiusY - */ - get radiusY() { - return this._radiusY; - } - /** - * set ellipse radiusY, update points - */ - set radiusY(radiusY) { - this._radiusY = radiusY; - this.setPoints( - (0, utils_1.createEllipse)( - this._radiusX, - this._radiusY, - this._step, - ), - ); - } - /** - * do not attempt to use Polygon.center() - */ - center() { - return; - } - /** - * do not attempt to use Polygon.updateIsConvex() - */ - updateIsConvex() { - return; - } - } - exports.Ellipse = Ellipse; + this.type = model_1.BodyType.Ellipse; + /** + * faster than type + */ + this.typeGroup = model_1.BodyGroup.Ellipse; + /** + * ellipses are convex + */ + this.isConvex = true; + this._radiusX = radiusX; + this._radiusY = radiusY; + this._step = step; + } + /** + * flag to set is body centered + */ + set isCentered(_isCentered) { } + /** + * is body centered? + */ + get isCentered() { + return true; + } + /** + * get ellipse step number + */ + get step() { + return this._step; + } + /** + * set ellipse step number + */ + set step(step) { + this._step = step; + this.setPoints((0, utils_1.createEllipse)(this._radiusX, this._radiusY, this._step)); + } + /** + * get ellipse radiusX + */ + get radiusX() { + return this._radiusX; + } + /** + * set ellipse radiusX, update points + */ + set radiusX(radiusX) { + this._radiusX = radiusX; + this.setPoints((0, utils_1.createEllipse)(this._radiusX, this._radiusY, this._step)); + } + /** + * get ellipse radiusY + */ + get radiusY() { + return this._radiusY; + } + /** + * set ellipse radiusY, update points + */ + set radiusY(radiusY) { + this._radiusY = radiusY; + this.setPoints((0, utils_1.createEllipse)(this._radiusX, this._radiusY, this._step)); + } + /** + * do not attempt to use Polygon.center() + */ + center() { + return; + } + /** + * do not attempt to use Polygon.updateIsConvex() + */ + updateIsConvex() { + return; + } +} +exports.Ellipse = Ellipse; - /***/ - }, - /***/ "./src/bodies/line.ts": - /*!****************************!*\ +/***/ }), + +/***/ "./src/bodies/line.ts": +/*!****************************!*\ !*** ./src/bodies/line.ts ***! \****************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Line = void 0; - const sat_1 = __webpack_require__( - /*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js", - ); - const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); - const polygon_1 = __webpack_require__( - /*! ./polygon */ "./src/bodies/polygon.ts", - ); +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Line = void 0; +const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); +const polygon_1 = __webpack_require__(/*! ./polygon */ "./src/bodies/polygon.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); +/** + * collider - line + */ +class Line extends polygon_1.Polygon { + /** + * collider - line from start to end + */ + constructor(start, end, options) { + super(start, [ + { x: 0, y: 0 }, + { x: end.x - start.x, y: end.y - start.y } + ], options); /** - * collider - line + * line type */ - class Line extends polygon_1.Polygon { - /** - * collider - line from start to end - */ - constructor(start, end, options) { - super( - start, - [ - { x: 0, y: 0 }, - { x: end.x - start.x, y: end.y - start.y }, - ], - options, - ); - /** - * line type - */ - this.type = model_1.BodyType.Line; - /** - * faster than type - */ - this.typeGroup = model_1.BodyGroup.Line; - /** - * line is convex - */ - this.isConvex = true; - if (this.calcPoints.length === 1 || !end) { - console.error({ start, end }); - throw new Error("No end point for line provided"); - } - } - get start() { - return { - x: this.x + this.calcPoints[0].x, - y: this.y + this.calcPoints[0].y, - }; - } - set start({ x, y }) { - this.x = x; - this.y = y; - } - get end() { - return { - x: this.x + this.calcPoints[1].x, - y: this.y + this.calcPoints[1].y, - }; - } - set end({ x, y }) { - this.points[1].x = x - this.start.x; - this.points[1].y = y - this.start.y; - this.setPoints(this.points); - } - getCentroid() { - return new sat_1.Vector( - (this.end.x - this.start.x) / 2, - (this.end.y - this.start.y) / 2, - ); - } - /** - * do not attempt to use Polygon.updateIsConvex() - */ - updateIsConvex() { - return; - } + this.type = model_1.BodyType.Line; + /** + * faster than type + */ + this.typeGroup = model_1.BodyGroup.Line; + /** + * line is convex + */ + this.isConvex = true; + if (this.calcPoints.length === 1 || !end) { + console.error({ start, end }); + throw new Error("No end point for line provided"); } - exports.Line = Line; + } + get start() { + return { + x: this.x + this.calcPoints[0].x, + y: this.y + this.calcPoints[0].y + }; + } + set start({ x, y }) { + this.x = x; + this.y = y; + } + get end() { + return { + x: this.x + this.calcPoints[1].x, + y: this.y + this.calcPoints[1].y + }; + } + set end({ x, y }) { + this.points[1].x = x - this.start.x; + this.points[1].y = y - this.start.y; + this.setPoints(this.points); + } + getCentroid() { + return new sat_1.Vector((this.end.x - this.start.x) / 2, (this.end.y - this.start.y) / 2); + } + /** + * do not attempt to use Polygon.updateIsConvex() + */ + updateIsConvex() { + return; + } +} +exports.Line = Line; - /***/ - }, - /***/ "./src/bodies/point.ts": - /*!*****************************!*\ +/***/ }), + +/***/ "./src/bodies/point.ts": +/*!*****************************!*\ !*** ./src/bodies/point.ts ***! \*****************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Point = void 0; - const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); - const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); - const box_1 = __webpack_require__(/*! ./box */ "./src/bodies/box.ts"); +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Point = void 0; +const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); +const box_1 = __webpack_require__(/*! ./box */ "./src/bodies/box.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +/** + * collider - point (very tiny box) + */ +class Point extends box_1.Box { + /** + * collider - point (very tiny box) + */ + constructor(position, options) { + super((0, utils_1.ensureVectorPoint)(position), 0.001, 0.001, options); /** - * collider - point (very tiny box) + * point type */ - class Point extends box_1.Box { - /** - * collider - point (very tiny box) - */ - constructor(position, options) { - super( - (0, utils_1.ensureVectorPoint)(position), - 0.001, - 0.001, - options, - ); - /** - * point type - */ - this.type = model_1.BodyType.Point; - /** - * faster than type - */ - this.typeGroup = model_1.BodyGroup.Point; - } - } - exports.Point = Point; + this.type = model_1.BodyType.Point; + /** + * faster than type + */ + this.typeGroup = model_1.BodyGroup.Point; + } +} +exports.Point = Point; - /***/ - }, - /***/ "./src/bodies/polygon.ts": - /*!*******************************!*\ +/***/ }), + +/***/ "./src/bodies/polygon.ts": +/*!*******************************!*\ !*** ./src/bodies/polygon.ts ***! \*******************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Polygon = exports.isSimple = void 0; - const poly_decomp_es_1 = __webpack_require__( - /*! poly-decomp-es */ "./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js", - ); - Object.defineProperty(exports, "isSimple", { - enumerable: true, - get: function () { - return poly_decomp_es_1.isSimple; - }, - }); - const sat_1 = __webpack_require__( - /*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js", - ); - const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); - const optimized_1 = __webpack_require__( - /*! ../optimized */ "./src/optimized.ts", - ); - const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Polygon = exports.isSimple = void 0; +const model_1 = __webpack_require__(/*! ../model */ "./src/model.ts"); +const utils_1 = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +const optimized_1 = __webpack_require__(/*! ../optimized */ "./src/optimized.ts"); +const poly_decomp_es_1 = __webpack_require__(/*! poly-decomp-es */ "./node_modules/poly-decomp-es/dist/poly-decomp-es.js"); +Object.defineProperty(exports, "isSimple", ({ enumerable: true, get: function () { return poly_decomp_es_1.isSimple; } })); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); +/** + * collider - polygon + */ +class Polygon extends sat_1.Polygon { + /** + * collider - polygon + */ + constructor(position, points, options) { + super((0, utils_1.ensureVectorPoint)(position), (0, utils_1.ensurePolygonPoints)(points)); /** - * collider - polygon + * was the polygon modified and needs update in the next checkCollision */ - class Polygon extends sat_1.Polygon { - /** - * collider - polygon - */ - constructor(position, points, options) { - super( - (0, utils_1.ensureVectorPoint)(position), - (0, utils_1.ensurePolygonPoints)(points), - ); - /** - * was the polygon modified and needs update in the next checkCollision - */ - this.dirty = false; - /** - * type of body - */ - this.type = model_1.BodyType.Polygon; - /** - * faster than type - */ - this.typeGroup = model_1.BodyGroup.Polygon; - /** - * is body centered - */ - this.centered = false; - /** - * scale Vector of body - */ - this.scaleVector = { x: 1, y: 1 }; - if (!points.length) { - throw new Error("No points in polygon"); - } - (0, utils_1.extendBody)(this, options); - } - /** - * flag to set is polygon centered - */ - set isCentered(isCentered) { - if (this.centered === isCentered) { - return; - } - const centroid = this.getCentroidWithoutRotation(); - if (centroid.x || centroid.y) { - const x = centroid.x * (isCentered ? 1 : -1); - const y = centroid.y * (isCentered ? 1 : -1); - this.translate(-x, -y); - } - this.centered = isCentered; - } - /** - * is polygon centered? - */ - get isCentered() { - return this.centered; - } - get x() { - return this.pos.x; - } - /** - * updating this.pos.x by this.x = x updates AABB - */ - set x(x) { - this.pos.x = x; - this.markAsDirty(); - } - get y() { - return this.pos.y; - } - /** - * updating this.pos.y by this.y = y updates AABB - */ - set y(y) { - this.pos.y = y; - this.markAsDirty(); - } - /** - * allow exact getting of scale x - use setScale(x, y) to set - */ - get scaleX() { - return this.scaleVector.x; - } - /** - * allow exact getting of scale y - use setScale(x, y) to set - */ - get scaleY() { - return this.scaleVector.y; - } - /** - * allow approx getting of scale - */ - get scale() { - return (this.scaleVector.x + this.scaleVector.y) / 2; - } - /** - * allow easier setting of scale - */ - set scale(scale) { - this.setScale(scale); - } - /** - * group for collision filtering - */ - get group() { - return this._group; - } - set group(group) { - this._group = (0, utils_1.getGroup)(group); - } - /** - * update position - */ - setPosition(x, y, update = true) { - this.pos.x = x; - this.pos.y = y; - this.markAsDirty(update); - return this; - } - /** - * update scale - */ - setScale(x, y = x, update = true) { - this.scaleVector.x = Math.abs(x); - this.scaleVector.y = Math.abs(y); - super.setPoints( - (0, optimized_1.map)(this.points, (point, index) => { - point.x = this.pointsBackup[index].x * this.scaleVector.x; - point.y = this.pointsBackup[index].y * this.scaleVector.y; - return point; - }), - ); - this.markAsDirty(update); - return this; - } - setAngle(angle, update = true) { - super.setAngle(angle); - this.markAsDirty(update); - return this; - } - setOffset(offset, update = true) { - super.setOffset(offset); - this.markAsDirty(update); - return this; - } - /** - * get body bounding box, without padding - */ - getAABBAsBBox() { - const { pos, w, h } = this.getAABBAsBox(); - return { - minX: pos.x, - minY: pos.y, - maxX: pos.x + w, - maxY: pos.y + h, - }; - } - /** - * Draws exact collider on canvas context - */ - draw(context) { - (0, utils_1.drawPolygon)(context, this, this.isTrigger); - } - /** - * Draws Bounding Box on canvas context - */ - drawBVH(context) { - (0, utils_1.drawBVH)(context, this); - } - /** - * get body centroid without applied angle - */ - getCentroidWithoutRotation() { - // keep angle copy - const angle = this.angle; - if (angle) { - // reset angle for get centroid - this.setAngle(0); - // get centroid - const centroid = this.getCentroid(); - // revert angle change - this.setAngle(angle); - return centroid; - } - return this.getCentroid(); - } - /** - * sets polygon points to new array of vectors - */ - setPoints(points) { - super.setPoints(points); - this.updateIsConvex(); - this.pointsBackup = (0, utils_1.clonePointsArray)(points); - return this; - } - /** - * translates polygon points in x, y direction - */ - translate(x, y) { - super.translate(x, y); - this.pointsBackup = (0, utils_1.clonePointsArray)(this.points); - return this; - } - /** - * rotates polygon points by angle, in radians - */ - rotate(angle) { - super.rotate(angle); - this.pointsBackup = (0, utils_1.clonePointsArray)(this.points); - return this; - } - /** - * if true, polygon is not an invalid, self-crossing polygon - */ - isSimple() { - return (0, poly_decomp_es_1.isSimple)( - this.calcPoints.map(utils_1.mapVectorToArray), - ); - } - /** - * inner function for after position change update aabb in system and convex inner polygons - */ - updateBody(update = this.dirty) { - var _a; - if (update) { - this.updateConvexPolygonPositions(); - (_a = this.system) === null || _a === void 0 - ? void 0 - : _a.insert(this); - this.dirty = false; - } - } - retranslate(isCentered = this.isCentered) { - const centroid = this.getCentroidWithoutRotation(); - if (centroid.x || centroid.y) { - const x = centroid.x * (isCentered ? 1 : -1); - const y = centroid.y * (isCentered ? 1 : -1); - this.translate(-x, -y); - } - } - /** - * update instantly or mark as dirty - */ - markAsDirty(update = false) { - if (update) { - this.updateBody(true); - } else { - this.dirty = true; - } - } - /** - * update the position of the decomposed convex polygons (if any), called - * after the position of the body has changed - */ - updateConvexPolygonPositions() { - if (this.isConvex || !this.convexPolygons) { - return; - } - (0, optimized_1.forEach)(this.convexPolygons, (polygon) => { - polygon.pos.x = this.pos.x; - polygon.pos.y = this.pos.y; - if (polygon.angle !== this.angle) { - // Must use setAngle to recalculate the points of the Polygon - polygon.setAngle(this.angle); - } - }); - } - /** - * returns body split into convex polygons, or empty array for convex bodies - */ - getConvex() { - if ( - (this.typeGroup && - this.typeGroup !== model_1.BodyGroup.Polygon) || - this.points.length < 4 - ) { - return []; - } - const points = (0, optimized_1.map)( - this.calcPoints, - utils_1.mapVectorToArray, - ); - return (0, poly_decomp_es_1.quickDecomp)(points); - } - /** - * updates convex polygons cache in body - */ - updateConvexPolygons(convex = this.getConvex()) { - if (this.isConvex) { - return; - } - if (!this.convexPolygons) { - this.convexPolygons = []; - } - (0, optimized_1.forEach)(convex, (points, index) => { - // lazy create - if (!this.convexPolygons[index]) { - this.convexPolygons[index] = new sat_1.Polygon(); - } - this.convexPolygons[index].pos.x = this.pos.x; - this.convexPolygons[index].pos.y = this.pos.y; - this.convexPolygons[index].angle = this.angle; - this.convexPolygons[index].setPoints( - (0, utils_1.ensurePolygonPoints)( - (0, optimized_1.map)(points, utils_1.mapArrayToVector), - ), - ); - }); - // trim array length - this.convexPolygons.length = convex.length; - } - /** - * after points update set is convex - */ - updateIsConvex() { - // all other types other than polygon are always convex - const convex = this.getConvex(); - // everything with empty array or one element array - this.isConvex = convex.length <= 1; - this.updateConvexPolygons(convex); - } - } - exports.Polygon = Polygon; - - /***/ - }, - - /***/ "./src/intersect.ts": - /*!**************************!*\ - !*** ./src/intersect.ts ***! - \**************************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.intersectLinePolygon = - exports.intersectLineLine = - exports.intersectLineLineFast = - exports.intersectLineCircle = - exports.circleOutsidePolygon = - exports.circleInPolygon = - exports.circleInCircle = - exports.pointOnCircle = - exports.polygonInPolygon = - exports.pointInPolygon = - exports.polygonInCircle = - exports.ensureConvex = - void 0; - const sat_1 = __webpack_require__( - /*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js", - ); - const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); - const optimized_1 = __webpack_require__( - /*! ./optimized */ "./src/optimized.ts", - ); + this.dirty = false; /** - * replace body with array of related convex polygons + * type of body */ - function ensureConvex(body) { - if (body.isConvex || body.typeGroup !== model_1.BodyGroup.Polygon) { - return [body]; - } - return body.convexPolygons; - } - exports.ensureConvex = ensureConvex; - function polygonInCircle(polygon, circle) { - return (0, optimized_1.every)(polygon.calcPoints, (p) => - (0, sat_1.pointInCircle)( - { x: p.x + polygon.pos.x, y: p.y + polygon.pos.y }, - circle, - ), - ); - } - exports.polygonInCircle = polygonInCircle; - function pointInPolygon(point, polygon) { - return (0, optimized_1.some)(ensureConvex(polygon), (convex) => - (0, sat_1.pointInPolygon)(point, convex), - ); - } - exports.pointInPolygon = pointInPolygon; - function polygonInPolygon(polygonA, polygonB) { - return (0, optimized_1.every)(polygonA.calcPoints, (point) => - pointInPolygon( - { x: point.x + polygonA.pos.x, y: point.y + polygonA.pos.y }, - polygonB, - ), - ); - } - exports.polygonInPolygon = polygonInPolygon; + this.type = model_1.BodyType.Polygon; /** - * https://stackoverflow.com/a/68197894/1749528 + * faster than type */ - function pointOnCircle(point, circle) { - return ( - (point.x - circle.pos.x) * (point.x - circle.pos.x) + - (point.y - circle.pos.y) * (point.y - circle.pos.y) === - circle.r * circle.r - ); - } - exports.pointOnCircle = pointOnCircle; + this.typeGroup = model_1.BodyGroup.Polygon; /** - * https://stackoverflow.com/a/68197894/1749528 + * is body centered */ - function circleInCircle(bodyA, bodyB) { - const x1 = bodyA.pos.x; - const y1 = bodyA.pos.y; - const x2 = bodyB.pos.x; - const y2 = bodyB.pos.y; - const r1 = bodyA.r; - const r2 = bodyB.r; - const distSq = Math.sqrt( - (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2), - ); - return distSq + r2 === r1 || distSq + r2 < r1; - } - exports.circleInCircle = circleInCircle; + this.centered = false; /** - * https://stackoverflow.com/a/68197894/1749528 + * scale Vector of body */ - function circleInPolygon(circle, polygon) { - // Circle with radius 0 isn't a circle - if (circle.r === 0) { - return false; - } - // If the center of the circle is not within the polygon, - // then the circle may overlap, but it'll never be "contained" - // so return false - if (!pointInPolygon(circle.pos, polygon)) { - return false; - } - // Necessary add polygon pos to points - const points = (0, optimized_1.map)( - polygon.calcPoints, - ({ x, y }) => ({ - x: x + polygon.pos.x, - y: y + polygon.pos.y, - }), - ); - // If the center of the circle is within the polygon, - // the circle is not outside of the polygon completely. - // so return false. - if ( - (0, optimized_1.some)(points, (point) => - (0, sat_1.pointInCircle)(point, circle), - ) - ) { - return false; - } - // If any line-segment of the polygon intersects the circle, - // the circle is not "contained" - // so return false - if ( - (0, optimized_1.some)(points, (end, index) => { - const start = index - ? points[index - 1] - : points[points.length - 1]; - return intersectLineCircle({ start, end }, circle).length > 0; - }) - ) { - return false; - } - return true; + this.scaleVector = { x: 1, y: 1 }; + if (!points.length) { + throw new Error("No points in polygon"); } - exports.circleInPolygon = circleInPolygon; - /** - * https://stackoverflow.com/a/68197894/1749528 - */ - function circleOutsidePolygon(circle, polygon) { - // Circle with radius 0 isn't a circle - if (circle.r === 0) { - return false; - } - // If the center of the circle is within the polygon, - // the circle is not outside of the polygon completely. - // so return false. - if (pointInPolygon(circle.pos, polygon)) { - return false; - } - // Necessary add polygon pos to points - const points = (0, optimized_1.map)( - polygon.calcPoints, - ({ x, y }) => ({ - x: x + polygon.pos.x, - y: y + polygon.pos.y, - }), - ); - // If the center of the circle is within the polygon, - // the circle is not outside of the polygon completely. - // so return false. - if ( - (0, optimized_1.some)( - points, - (point) => - (0, sat_1.pointInCircle)(point, circle) || - pointOnCircle(point, circle), - ) - ) { - return false; - } - // If any line-segment of the polygon intersects the circle, - // the circle is not "contained" - // so return false - if ( - (0, optimized_1.some)(points, (end, index) => { - const start = index - ? points[index - 1] - : points[points.length - 1]; - return intersectLineCircle({ start, end }, circle).length > 0; - }) - ) { - return false; - } - return true; + (0, utils_1.extendBody)(this, options); + } + /** + * flag to set is polygon centered + */ + set isCentered(isCentered) { + if (this.centered === isCentered) { + return; } - exports.circleOutsidePolygon = circleOutsidePolygon; - /** - * https://stackoverflow.com/a/37225895/1749528 - */ - function intersectLineCircle(line, { pos, r }) { - const v1 = { - x: line.end.x - line.start.x, - y: line.end.y - line.start.y, - }; - const v2 = { x: line.start.x - pos.x, y: line.start.y - pos.y }; - const b = (v1.x * v2.x + v1.y * v2.y) * -2; - const c = (v1.x * v1.x + v1.y * v1.y) * 2; - const d = Math.sqrt( - b * b - (v2.x * v2.x + v2.y * v2.y - r * r) * c * 2, - ); - if (isNaN(d)) { - // no intercept - return []; - } - const u1 = (b - d) / c; // these represent the unit distance of point one and two on the line - const u2 = (b + d) / c; - const results = []; // return array - if (u1 <= 1 && u1 >= 0) { - // add point if on the line segment - results.push({ - x: line.start.x + v1.x * u1, - y: line.start.y + v1.y * u1, - }); - } - if (u2 <= 1 && u2 >= 0) { - // second add point if on the line segment - results.push({ - x: line.start.x + v1.x * u2, - y: line.start.y + v1.y * u2, - }); - } - return results; + const centroid = this.getCentroidWithoutRotation(); + if (centroid.x || centroid.y) { + const x = centroid.x * (isCentered ? 1 : -1); + const y = centroid.y * (isCentered ? 1 : -1); + this.translate(-x, -y); } - exports.intersectLineCircle = intersectLineCircle; - /** - * helper for intersectLineLineFast - */ - function isTurn(point1, point2, point3) { - const A = (point3.x - point1.x) * (point2.y - point1.y); - const B = (point2.x - point1.x) * (point3.y - point1.y); - return A > B + Number.EPSILON ? 1 : A + Number.EPSILON < B ? -1 : 0; + this.centered = isCentered; + } + /** + * is polygon centered? + */ + get isCentered() { + return this.centered; + } + get x() { + return this.pos.x; + } + /** + * updating this.pos.x by this.x = x updates AABB + */ + set x(x) { + this.pos.x = x; + this.markAsDirty(); + } + get y() { + return this.pos.y; + } + /** + * updating this.pos.y by this.y = y updates AABB + */ + set y(y) { + this.pos.y = y; + this.markAsDirty(); + } + /** + * allow exact getting of scale x - use setScale(x, y) to set + */ + get scaleX() { + return this.scaleVector.x; + } + /** + * allow exact getting of scale y - use setScale(x, y) to set + */ + get scaleY() { + return this.scaleVector.y; + } + /** + * allow approx getting of scale + */ + get scale() { + return (this.scaleVector.x + this.scaleVector.y) / 2; + } + /** + * allow easier setting of scale + */ + set scale(scale) { + this.setScale(scale); + } + /** + * group for collision filtering + */ + get group() { + return this._group; + } + set group(group) { + this._group = (0, utils_1.getGroup)(group); + } + /** + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true) { + (0, utils_1.move)(this, speed, updateNow); + return this; + } + /** + * update position BY TELEPORTING + */ + setPosition(x, y, updateNow = true) { + this.pos.x = x; + this.pos.y = y; + this.markAsDirty(updateNow); + return this; + } + /** + * update scale + */ + setScale(x, y = x, updateNow = true) { + this.scaleVector.x = Math.abs(x); + this.scaleVector.y = Math.abs(y); + super.setPoints((0, optimized_1.map)(this.points, (point, index) => { + point.x = this.pointsBackup[index].x * this.scaleVector.x; + point.y = this.pointsBackup[index].y * this.scaleVector.y; + return point; + })); + this.markAsDirty(updateNow); + return this; + } + setAngle(angle, updateNow = true) { + super.setAngle(angle); + this.markAsDirty(updateNow); + return this; + } + setOffset(offset, updateNow = true) { + super.setOffset(offset); + this.markAsDirty(updateNow); + return this; + } + /** + * get body bounding box, without padding + */ + getAABBAsBBox() { + const { pos, w, h } = this.getAABBAsBox(); + return { + minX: pos.x, + minY: pos.y, + maxX: pos.x + w, + maxY: pos.y + h + }; + } + /** + * Draws exact collider on canvas context + */ + draw(context) { + (0, utils_1.drawPolygon)(context, this, this.isTrigger); + } + /** + * Draws Bounding Box on canvas context + */ + drawBVH(context) { + (0, utils_1.drawBVH)(context, this); + } + /** + * get body centroid without applied angle + */ + getCentroidWithoutRotation() { + // keep angle copy + const angle = this.angle; + if (angle) { + // reset angle for get centroid + this.setAngle(0); + // get centroid + const centroid = this.getCentroid(); + // revert angle change + this.setAngle(angle); + return centroid; } - /** - * faster implementation of intersectLineLine - * https://stackoverflow.com/a/16725715/1749528 - */ - function intersectLineLineFast(line1, line2) { - return ( - isTurn(line1.start, line2.start, line2.end) !== - isTurn(line1.end, line2.start, line2.end) && - isTurn(line1.start, line1.end, line2.start) !== - isTurn(line1.start, line1.end, line2.end) - ); + return this.getCentroid(); + } + /** + * sets polygon points to new array of vectors + */ + setPoints(points) { + super.setPoints(points); + this.updateIsConvex(); + this.pointsBackup = (0, utils_1.clonePointsArray)(points); + return this; + } + /** + * translates polygon points in x, y direction + */ + translate(x, y) { + super.translate(x, y); + this.pointsBackup = (0, utils_1.clonePointsArray)(this.points); + return this; + } + /** + * rotates polygon points by angle, in radians + */ + rotate(angle) { + super.rotate(angle); + this.pointsBackup = (0, utils_1.clonePointsArray)(this.points); + return this; + } + /** + * if true, polygon is not an invalid, self-crossing polygon + */ + isSimple() { + return (0, poly_decomp_es_1.isSimple)(this.calcPoints.map(utils_1.mapVectorToArray)); + } + /** + * inner function for after position change update aabb in system and convex inner polygons + */ + updateBody(updateNow = this.dirty) { + var _a; + if (updateNow) { + this.updateConvexPolygonPositions(); + (_a = this.system) === null || _a === void 0 ? void 0 : _a.insert(this); + this.dirty = false; } - exports.intersectLineLineFast = intersectLineLineFast; - /** - * returns the point of intersection - * https://stackoverflow.com/a/24392281/1749528 - */ - function intersectLineLine(line1, line2) { - const dX = line1.end.x - line1.start.x; - const dY = line1.end.y - line1.start.y; - const determinant = - dX * (line2.end.y - line2.start.y) - - (line2.end.x - line2.start.x) * dY; - if (determinant === 0) { - return null; - } - const lambda = - ((line2.end.y - line2.start.y) * (line2.end.x - line1.start.x) + - (line2.start.x - line2.end.x) * (line2.end.y - line1.start.y)) / - determinant; - const gamma = - ((line1.start.y - line1.end.y) * (line2.end.x - line1.start.x) + - dX * (line2.end.y - line1.start.y)) / - determinant; - // check if there is an intersection - if (!(lambda >= 0 && lambda <= 1) || !(gamma >= 0 && gamma <= 1)) { - return null; - } - return { - x: line1.start.x + lambda * dX, - y: line1.start.y + lambda * dY, - }; + } + retranslate(isCentered = this.isCentered) { + const centroid = this.getCentroidWithoutRotation(); + if (centroid.x || centroid.y) { + const x = centroid.x * (isCentered ? 1 : -1); + const y = centroid.y * (isCentered ? 1 : -1); + this.translate(-x, -y); + } + } + /** + * update instantly or mark as dirty + */ + markAsDirty(updateNow = false) { + if (updateNow) { + this.updateBody(true); + } + else { + this.dirty = true; + } + } + /** + * update the position of the decomposed convex polygons (if any), called + * after the position of the body has changed + */ + updateConvexPolygonPositions() { + if (this.isConvex || !this.convexPolygons) { + return; + } + (0, optimized_1.forEach)(this.convexPolygons, (polygon) => { + polygon.pos.x = this.pos.x; + polygon.pos.y = this.pos.y; + if (polygon.angle !== this.angle) { + // Must use setAngle to recalculate the points of the Polygon + polygon.setAngle(this.angle); + } + }); + } + /** + * returns body split into convex polygons, or empty array for convex bodies + */ + getConvex() { + if ((this.typeGroup && this.typeGroup !== model_1.BodyGroup.Polygon) || + this.points.length < 4) { + return []; + } + const points = (0, optimized_1.map)(this.calcPoints, utils_1.mapVectorToArray); + return (0, poly_decomp_es_1.quickDecomp)(points); + } + /** + * updates convex polygons cache in body + */ + updateConvexPolygons(convex = this.getConvex()) { + if (this.isConvex) { + return; } - exports.intersectLineLine = intersectLineLine; - function intersectLinePolygon(line, polygon) { - const results = []; - (0, optimized_1.forEach)(polygon.calcPoints, (to, index) => { - const from = index - ? polygon.calcPoints[index - 1] - : polygon.calcPoints[polygon.calcPoints.length - 1]; - const side = { - start: { x: from.x + polygon.pos.x, y: from.y + polygon.pos.y }, - end: { x: to.x + polygon.pos.x, y: to.y + polygon.pos.y }, - }; - const hit = intersectLineLine(line, side); - if (hit) { - results.push(hit); + if (!this.convexPolygons) { + this.convexPolygons = []; + } + (0, optimized_1.forEach)(convex, (points, index) => { + // lazy create + if (!this.convexPolygons[index]) { + this.convexPolygons[index] = new sat_1.Polygon(); } - }); - return results; + this.convexPolygons[index].pos.x = this.pos.x; + this.convexPolygons[index].pos.y = this.pos.y; + this.convexPolygons[index].angle = this.angle; + this.convexPolygons[index].setPoints((0, utils_1.ensurePolygonPoints)((0, optimized_1.map)(points, utils_1.mapArrayToVector))); + }); + // trim array length + this.convexPolygons.length = convex.length; + } + /** + * after points update set is convex + */ + updateIsConvex() { + // all other types other than polygon are always convex + const convex = this.getConvex(); + // everything with empty array or one element array + this.isConvex = convex.length <= 1; + this.updateConvexPolygons(convex); + } +} +exports.Polygon = Polygon; + + +/***/ }), + +/***/ "./src/intersect.ts": +/*!**************************!*\ + !*** ./src/intersect.ts ***! + \**************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ensureConvex = ensureConvex; +exports.polygonInCircle = polygonInCircle; +exports.pointInPolygon = pointInPolygon; +exports.polygonInPolygon = polygonInPolygon; +exports.pointOnCircle = pointOnCircle; +exports.circleInCircle = circleInCircle; +exports.circleInPolygon = circleInPolygon; +exports.circleOutsidePolygon = circleOutsidePolygon; +exports.intersectLineCircle = intersectLineCircle; +exports.intersectLineLineFast = intersectLineLineFast; +exports.intersectLineLine = intersectLineLine; +exports.intersectLinePolygon = intersectLinePolygon; +const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); +const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); +/** + * replace body with array of related convex polygons + */ +function ensureConvex(body) { + if (body.isConvex || body.typeGroup !== model_1.BodyGroup.Polygon) { + return [body]; + } + return body.convexPolygons; +} +function polygonInCircle(polygon, circle) { + return (0, optimized_1.every)(polygon.calcPoints, p => (0, sat_1.pointInCircle)({ x: p.x + polygon.pos.x, y: p.y + polygon.pos.y }, circle)); +} +function pointInPolygon(point, polygon) { + return (0, optimized_1.some)(ensureConvex(polygon), convex => (0, sat_1.pointInPolygon)(point, convex)); +} +function polygonInPolygon(polygonA, polygonB) { + return (0, optimized_1.every)(polygonA.calcPoints, point => pointInPolygon({ x: point.x + polygonA.pos.x, y: point.y + polygonA.pos.y }, polygonB)); +} +/** + * https://stackoverflow.com/a/68197894/1749528 + */ +function pointOnCircle(point, circle) { + return ((point.x - circle.pos.x) * (point.x - circle.pos.x) + + (point.y - circle.pos.y) * (point.y - circle.pos.y) === + circle.r * circle.r); +} +/** + * https://stackoverflow.com/a/68197894/1749528 + */ +function circleInCircle(bodyA, bodyB) { + const x1 = bodyA.pos.x; + const y1 = bodyA.pos.y; + const x2 = bodyB.pos.x; + const y2 = bodyB.pos.y; + const r1 = bodyA.r; + const r2 = bodyB.r; + const distSq = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + return distSq + r2 === r1 || distSq + r2 < r1; +} +/** + * https://stackoverflow.com/a/68197894/1749528 + */ +function circleInPolygon(circle, polygon) { + // Circle with radius 0 isn't a circle + if (circle.r === 0) { + return false; + } + // If the center of the circle is not within the polygon, + // then the circle may overlap, but it'll never be "contained" + // so return false + if (!pointInPolygon(circle.pos, polygon)) { + return false; + } + // Necessary add polygon pos to points + const points = (0, optimized_1.map)(polygon.calcPoints, ({ x, y }) => ({ + x: x + polygon.pos.x, + y: y + polygon.pos.y + })); + // If the center of the circle is within the polygon, + // the circle is not outside of the polygon completely. + // so return false. + if ((0, optimized_1.some)(points, point => (0, sat_1.pointInCircle)(point, circle))) { + return false; + } + // If any line-segment of the polygon intersects the circle, + // the circle is not "contained" + // so return false + if ((0, optimized_1.some)(points, (end, index) => { + const start = index + ? points[index - 1] + : points[points.length - 1]; + return intersectLineCircle({ start, end }, circle).length > 0; + })) { + return false; + } + return true; +} +/** + * https://stackoverflow.com/a/68197894/1749528 + */ +function circleOutsidePolygon(circle, polygon) { + // Circle with radius 0 isn't a circle + if (circle.r === 0) { + return false; + } + // If the center of the circle is within the polygon, + // the circle is not outside of the polygon completely. + // so return false. + if (pointInPolygon(circle.pos, polygon)) { + return false; + } + // Necessary add polygon pos to points + const points = (0, optimized_1.map)(polygon.calcPoints, ({ x, y }) => ({ + x: x + polygon.pos.x, + y: y + polygon.pos.y + })); + // If the center of the circle is within the polygon, + // the circle is not outside of the polygon completely. + // so return false. + if ((0, optimized_1.some)(points, point => (0, sat_1.pointInCircle)(point, circle) || pointOnCircle(point, circle))) { + return false; + } + // If any line-segment of the polygon intersects the circle, + // the circle is not "contained" + // so return false + if ((0, optimized_1.some)(points, (end, index) => { + const start = index + ? points[index - 1] + : points[points.length - 1]; + return intersectLineCircle({ start, end }, circle).length > 0; + })) { + return false; + } + return true; +} +/** + * https://stackoverflow.com/a/37225895/1749528 + */ +function intersectLineCircle(line, { pos, r }) { + const v1 = { x: line.end.x - line.start.x, y: line.end.y - line.start.y }; + const v2 = { x: line.start.x - pos.x, y: line.start.y - pos.y }; + const b = (v1.x * v2.x + v1.y * v2.y) * -2; + const c = (v1.x * v1.x + v1.y * v1.y) * 2; + const d = Math.sqrt(b * b - (v2.x * v2.x + v2.y * v2.y - r * r) * c * 2); + if (isNaN(d)) { + // no intercept + return []; + } + const u1 = (b - d) / c; // these represent the unit distance of point one and two on the line + const u2 = (b + d) / c; + const results = []; // return array + if (u1 <= 1 && u1 >= 0) { + // add point if on the line segment + results.push({ x: line.start.x + v1.x * u1, y: line.start.y + v1.y * u1 }); + } + if (u2 <= 1 && u2 >= 0) { + // second add point if on the line segment + results.push({ x: line.start.x + v1.x * u2, y: line.start.y + v1.y * u2 }); + } + return results; +} +/** + * helper for intersectLineLineFast + */ +function isTurn(point1, point2, point3) { + const A = (point3.x - point1.x) * (point2.y - point1.y); + const B = (point2.x - point1.x) * (point3.y - point1.y); + return A > B + Number.EPSILON ? 1 : A + Number.EPSILON < B ? -1 : 0; +} +/** + * faster implementation of intersectLineLine + * https://stackoverflow.com/a/16725715/1749528 + */ +function intersectLineLineFast(line1, line2) { + return (isTurn(line1.start, line2.start, line2.end) !== + isTurn(line1.end, line2.start, line2.end) && + isTurn(line1.start, line1.end, line2.start) !== + isTurn(line1.start, line1.end, line2.end)); +} +/** + * returns the point of intersection + * https://stackoverflow.com/a/24392281/1749528 + */ +function intersectLineLine(line1, line2) { + const dX = line1.end.x - line1.start.x; + const dY = line1.end.y - line1.start.y; + const determinant = dX * (line2.end.y - line2.start.y) - (line2.end.x - line2.start.x) * dY; + if (determinant === 0) { + return null; + } + const lambda = ((line2.end.y - line2.start.y) * (line2.end.x - line1.start.x) + + (line2.start.x - line2.end.x) * (line2.end.y - line1.start.y)) / + determinant; + const gamma = ((line1.start.y - line1.end.y) * (line2.end.x - line1.start.x) + + dX * (line2.end.y - line1.start.y)) / + determinant; + // check if there is an intersection + if (!(lambda >= 0 && lambda <= 1) || !(gamma >= 0 && gamma <= 1)) { + return null; + } + return { x: line1.start.x + lambda * dX, y: line1.start.y + lambda * dY }; +} +function intersectLinePolygon(line, polygon) { + const results = []; + (0, optimized_1.forEach)(polygon.calcPoints, (to, index) => { + const from = index + ? polygon.calcPoints[index - 1] + : polygon.calcPoints[polygon.calcPoints.length - 1]; + const side = { + start: { x: from.x + polygon.pos.x, y: from.y + polygon.pos.y }, + end: { x: to.x + polygon.pos.x, y: to.y + polygon.pos.y } + }; + const hit = intersectLineLine(line, side); + if (hit) { + results.push(hit); } - exports.intersectLinePolygon = intersectLinePolygon; + }); + return results; +} - /***/ - }, - /***/ "./src/model.ts": - /*!**********************!*\ +/***/ }), + +/***/ "./src/model.ts": +/*!**********************!*\ !*** ./src/model.ts ***! \**********************/ - /***/ function (__unused_webpack_module, exports, __webpack_require__) { - "use strict"; - - var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.BodyGroup = - exports.BodyType = - exports.SATCircle = - exports.SATPolygon = - exports.SATVector = - exports.Response = - exports.RBush = - exports.isSimple = - void 0; - const rbush_1 = __importDefault( - __webpack_require__( - /*! rbush */ "./node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/rbush.min.js", - ), - ); - Object.defineProperty(exports, "RBush", { - enumerable: true, - get: function () { - return rbush_1.default; - }, - }); - const sat_1 = __webpack_require__( - /*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js", - ); - Object.defineProperty(exports, "SATCircle", { - enumerable: true, - get: function () { - return sat_1.Circle; - }, - }); - Object.defineProperty(exports, "SATPolygon", { - enumerable: true, - get: function () { - return sat_1.Polygon; - }, - }); - Object.defineProperty(exports, "Response", { - enumerable: true, - get: function () { - return sat_1.Response; - }, - }); - Object.defineProperty(exports, "SATVector", { - enumerable: true, - get: function () { - return sat_1.Vector; - }, - }); - var poly_decomp_es_1 = __webpack_require__( - /*! poly-decomp-es */ "./node_modules/.pnpm/poly-decomp-es@0.4.2/node_modules/poly-decomp-es/dist/poly-decomp-es.js", - ); - Object.defineProperty(exports, "isSimple", { - enumerable: true, - get: function () { - return poly_decomp_es_1.isSimple; - }, - }); - /** - * types - */ - var BodyType; - (function (BodyType) { - BodyType["Ellipse"] = "Ellipse"; - BodyType["Circle"] = "Circle"; - BodyType["Polygon"] = "Polygon"; - BodyType["Box"] = "Box"; - BodyType["Line"] = "Line"; - BodyType["Point"] = "Point"; - })((BodyType = exports.BodyType || (exports.BodyType = {}))); - /** - * for groups - */ - var BodyGroup; - (function (BodyGroup) { - BodyGroup[(BodyGroup["Ellipse"] = 32)] = "Ellipse"; - BodyGroup[(BodyGroup["Circle"] = 16)] = "Circle"; - BodyGroup[(BodyGroup["Polygon"] = 8)] = "Polygon"; - BodyGroup[(BodyGroup["Box"] = 4)] = "Box"; - BodyGroup[(BodyGroup["Line"] = 2)] = "Line"; - BodyGroup[(BodyGroup["Point"] = 1)] = "Point"; - })((BodyGroup = exports.BodyGroup || (exports.BodyGroup = {}))); - - /***/ - }, - - /***/ "./src/optimized.ts": - /*!**************************!*\ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BodyGroup = exports.BodyType = exports.SATCircle = exports.SATPolygon = exports.SATVector = exports.Response = exports.RBush = exports.isSimple = void 0; +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); +Object.defineProperty(exports, "SATCircle", ({ enumerable: true, get: function () { return sat_1.Circle; } })); +Object.defineProperty(exports, "SATPolygon", ({ enumerable: true, get: function () { return sat_1.Polygon; } })); +Object.defineProperty(exports, "Response", ({ enumerable: true, get: function () { return sat_1.Response; } })); +Object.defineProperty(exports, "SATVector", ({ enumerable: true, get: function () { return sat_1.Vector; } })); +// version 4.0.0 1=1 copy +const rbush_1 = __importDefault(__webpack_require__(/*! ./rbush */ "./src/rbush.js")); +exports.RBush = rbush_1.default; +var poly_decomp_es_1 = __webpack_require__(/*! poly-decomp-es */ "./node_modules/poly-decomp-es/dist/poly-decomp-es.js"); +Object.defineProperty(exports, "isSimple", ({ enumerable: true, get: function () { return poly_decomp_es_1.isSimple; } })); +/** + * types + */ +var BodyType; +(function (BodyType) { + BodyType["Ellipse"] = "Ellipse"; + BodyType["Circle"] = "Circle"; + BodyType["Polygon"] = "Polygon"; + BodyType["Box"] = "Box"; + BodyType["Line"] = "Line"; + BodyType["Point"] = "Point"; +})(BodyType || (exports.BodyType = BodyType = {})); +/** + * for groups + */ +var BodyGroup; +(function (BodyGroup) { + BodyGroup[BodyGroup["Ellipse"] = 32] = "Ellipse"; + BodyGroup[BodyGroup["Circle"] = 16] = "Circle"; + BodyGroup[BodyGroup["Polygon"] = 8] = "Polygon"; + BodyGroup[BodyGroup["Box"] = 4] = "Box"; + BodyGroup[BodyGroup["Line"] = 2] = "Line"; + BodyGroup[BodyGroup["Point"] = 1] = "Point"; +})(BodyGroup || (exports.BodyGroup = BodyGroup = {})); + + +/***/ }), + +/***/ "./src/optimized.ts": +/*!**************************!*\ !*** ./src/optimized.ts ***! \**************************/ - /***/ (__unused_webpack_module, exports) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.map = - exports.filter = - exports.every = - exports.some = - exports.forEach = - void 0; +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.map = exports.filter = exports.every = exports.some = exports.forEach = void 0; +/** + * 40-90% faster than built-in Array.forEach function. + * + * basic benchmark: https://jsbench.me/urle772xdn + */ +const forEach = (array, callback) => { + for (let i = 0, l = array.length; i < l; i++) { + callback(array[i], i); + } +}; +exports.forEach = forEach; +/** + * 20-90% faster than built-in Array.some function. + * + * basic benchmark: https://jsbench.me/l0le7bnnsq + */ +const some = (array, callback) => { + for (let i = 0, l = array.length; i < l; i++) { + if (callback(array[i], i)) { + return true; + } + } + return false; +}; +exports.some = some; +/** + * 20-40% faster than built-in Array.every function. + * + * basic benchmark: https://jsbench.me/unle7da29v + */ +const every = (array, callback) => { + for (let i = 0, l = array.length; i < l; i++) { + if (!callback(array[i], i)) { + return false; + } + } + return true; +}; +exports.every = every; +/** + * 20-60% faster than built-in Array.filter function. + * + * basic benchmark: https://jsbench.me/o1le77ev4l + */ +const filter = (array, callback) => { + const output = []; + for (let i = 0, l = array.length; i < l; i++) { + const item = array[i]; + if (callback(item, i)) { + output.push(item); + } + } + return output; +}; +exports.filter = filter; +/** + * 20-70% faster than built-in Array.map + * + * basic benchmark: https://jsbench.me/oyle77vbpc + */ +const map = (array, callback) => { + const l = array.length; + const output = new Array(l); + for (let i = 0; i < l; i++) { + output[i] = callback(array[i], i); + } + return output; +}; +exports.map = map; + + +/***/ }), + +/***/ "./src/system.ts": +/*!***********************!*\ + !*** ./src/system.ts ***! + \***********************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.System = void 0; +const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); +const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); +const intersect_1 = __webpack_require__(/*! ./intersect */ "./src/intersect.ts"); +const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); +const base_system_1 = __webpack_require__(/*! ./base-system */ "./src/base-system.ts"); +const line_1 = __webpack_require__(/*! ./bodies/line */ "./src/bodies/line.ts"); +/** + * collision system + */ +class System extends base_system_1.BaseSystem { + constructor() { + super(...arguments); /** - * 40-90% faster than built-in Array.forEach function. - * - * basic benchmark: https://jsbench.me/urle772xdn + * the last collision result */ - const forEach = (array, callback) => { - for (let i = 0, l = array.length; i < l; i++) { - callback(array[i], i); - } + this.response = new model_1.Response(); + } + /** + * re-insert body into collision tree and update its bbox + * every body can be part of only one system + */ + insert(body) { + const insertResult = super.insert(body); + // set system for later body.system.updateBody(body) + body.system = this; + return insertResult; + } + /** + * separate (move away) bodies + */ + separate() { + (0, optimized_1.forEach)(this.all(), (body) => { + this.separateBody(body); + }); + } + /** + * separate (move away) 1 body + */ + separateBody(body) { + if (body.isStatic || body.isTrigger) { + return; + } + const offsets = { x: 0, y: 0 }; + const addOffsets = ({ overlapV: { x, y } }) => { + offsets.x += x; + offsets.y += y; }; - exports.forEach = forEach; - /** - * 20-90% faster than built-in Array.some function. - * - * basic benchmark: https://jsbench.me/l0le7bnnsq - */ - const some = (array, callback) => { - for (let i = 0, l = array.length; i < l; i++) { - if (callback(array[i], i)) { - return true; + this.checkOne(body, addOffsets); + if (offsets.x || offsets.y) { + body.setPosition(body.x - offsets.x, body.y - offsets.y); + } + } + /** + * check one body collisions with callback + */ + checkOne(body, callback = utils_1.returnTrue, response = this.response) { + // no need to check static body collision + if (body.isStatic) { + return false; + } + const bodies = this.search(body); + const checkCollision = (candidate) => { + if (candidate !== body && + this.checkCollision(body, candidate, response)) { + return callback(response); } - } - return false; }; - exports.some = some; - /** - * 20-40% faster than built-in Array.every function. - * - * basic benchmark: https://jsbench.me/unle7da29v - */ - const every = (array, callback) => { - for (let i = 0, l = array.length; i < l; i++) { - if (!callback(array[i], i)) { - return false; - } - } - return true; + return (0, optimized_1.some)(bodies, checkCollision); + } + /** + * check all bodies collisions in area with callback + */ + checkArea(area, callback = utils_1.returnTrue, response = this.response) { + const checkOne = (body) => { + return this.checkOne(body, callback, response); }; - exports.every = every; - /** - * 20-60% faster than built-in Array.filter function. - * - * basic benchmark: https://jsbench.me/o1le77ev4l - */ - const filter = (array, callback) => { - const output = []; - for (let i = 0, l = array.length; i < l; i++) { - const item = array[i]; - if (callback(item, i)) { - output.push(item); - } - } - return output; + return (0, optimized_1.some)(this.search(area), checkOne); + } + /** + * check all bodies collisions with callback + */ + checkAll(callback = utils_1.returnTrue, response = this.response) { + const checkOne = (body) => { + return this.checkOne(body, callback, response); }; - exports.filter = filter; - /** - * 20-70% faster than built-in Array.map - * - * basic benchmark: https://jsbench.me/oyle77vbpc - */ - const map = (array, callback) => { - const l = array.length; - const output = new Array(l); - for (let i = 0; i < l; i++) { - output[i] = callback(array[i], i); + return (0, optimized_1.some)(this.all(), checkOne); + } + /** + * check do 2 objects collide + */ + checkCollision(bodyA, bodyB, response = this.response) { + const { bbox: bboxA } = bodyA; + const { bbox: bboxB } = bodyB; + // assess the bodies real aabb without padding + if (!(0, utils_1.canInteract)(bodyA, bodyB) || + !bboxA || + !bboxB || + (0, utils_1.notIntersectAABB)(bboxA, bboxB)) { + return false; + } + const sat = (0, utils_1.getSATTest)(bodyA, bodyB); + // 99% of cases + if (bodyA.isConvex && bodyB.isConvex) { + // always first clear response + response.clear(); + return sat(bodyA, bodyB, response); + } + // more complex (non convex) cases + const convexBodiesA = (0, intersect_1.ensureConvex)(bodyA); + const convexBodiesB = (0, intersect_1.ensureConvex)(bodyB); + let overlapX = 0; + let overlapY = 0; + let collided = false; + (0, optimized_1.forEach)(convexBodiesA, convexBodyA => { + (0, optimized_1.forEach)(convexBodiesB, convexBodyB => { + // always first clear response + response.clear(); + if (sat(convexBodyA, convexBodyB, response)) { + collided = true; + overlapX += response.overlapV.x; + overlapY += response.overlapV.y; + } + }); + }); + if (collided) { + const vector = new model_1.SATVector(overlapX, overlapY); + response.a = bodyA; + response.b = bodyB; + response.overlapV.x = overlapX; + response.overlapV.y = overlapY; + response.overlapN = vector.normalize(); + response.overlap = vector.len(); + response.aInB = (0, utils_1.checkAInB)(bodyA, bodyB); + response.bInA = (0, utils_1.checkAInB)(bodyB, bodyA); + } + return collided; + } + /** + * raycast to get collider of ray from start to end + */ + raycast(start, end, allow = utils_1.returnTrue) { + let minDistance = Infinity; + let result = null; + if (!this.ray) { + this.ray = new line_1.Line(start, end, { isTrigger: true }); + } + else { + this.ray.start = start; + this.ray.end = end; + } + this.insert(this.ray); + this.checkOne(this.ray, ({ b: body }) => { + if (!allow(body, this.ray)) { + return false; + } + const points = body.typeGroup === model_1.BodyGroup.Circle + ? (0, intersect_1.intersectLineCircle)(this.ray, body) + : (0, intersect_1.intersectLinePolygon)(this.ray, body); + (0, optimized_1.forEach)(points, (point) => { + const pointDistance = (0, utils_1.distance)(start, point); + if (pointDistance < minDistance) { + minDistance = pointDistance; + result = { point, body }; + } + }); + }); + this.remove(this.ray); + return result; + } +} +exports.System = System; + + +/***/ }), + +/***/ "./src/utils.ts": +/*!**********************!*\ + !*** ./src/utils.ts ***! + \**********************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.RAD2DEG = exports.DEG2RAD = void 0; +exports.deg2rad = deg2rad; +exports.rad2deg = rad2deg; +exports.createEllipse = createEllipse; +exports.createBox = createBox; +exports.ensureVectorPoint = ensureVectorPoint; +exports.ensurePolygonPoints = ensurePolygonPoints; +exports.distance = distance; +exports.clockwise = clockwise; +exports.extendBody = extendBody; +exports.bodyMoved = bodyMoved; +exports.notIntersectAABB = notIntersectAABB; +exports.intersectAABB = intersectAABB; +exports.canInteract = canInteract; +exports.checkAInB = checkAInB; +exports.clonePointsArray = clonePointsArray; +exports.mapVectorToArray = mapVectorToArray; +exports.mapArrayToVector = mapArrayToVector; +exports.getBounceDirection = getBounceDirection; +exports.getSATTest = getSATTest; +exports.dashLineTo = dashLineTo; +exports.drawPolygon = drawPolygon; +exports.drawBVH = drawBVH; +exports.cloneResponse = cloneResponse; +exports.returnTrue = returnTrue; +exports.getGroup = getGroup; +exports.bin2dec = bin2dec; +exports.ensureNumber = ensureNumber; +exports.groupBits = groupBits; +exports.move = move; +const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); +const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); +const intersect_1 = __webpack_require__(/*! ./intersect */ "./src/intersect.ts"); +const optimized_1 = __webpack_require__(/*! ./optimized */ "./src/optimized.ts"); +/* helpers for faster getSATTest() and checkAInB() */ +const testMap = { + satCircleCircle: sat_1.testCircleCircle, + satCirclePolygon: sat_1.testCirclePolygon, + satPolygonCircle: sat_1.testPolygonCircle, + satPolygonPolygon: sat_1.testPolygonPolygon, + inCircleCircle: intersect_1.circleInCircle, + inCirclePolygon: intersect_1.circleInPolygon, + inPolygonCircle: intersect_1.polygonInCircle, + inPolygonPolygon: intersect_1.polygonInPolygon +}; +function createMap(bodyType, testType) { + return Object.values(model_1.BodyType).reduce((result, type) => (Object.assign(Object.assign({}, result), { [type]: type === model_1.BodyType.Circle + ? testMap[`${testType}${bodyType}Circle`] + : testMap[`${testType}${bodyType}Polygon`] })), {}); +} +const circleSATFunctions = createMap(model_1.BodyType.Circle, "sat"); +const circleInFunctions = createMap(model_1.BodyType.Circle, "in"); +const polygonSATFunctions = createMap(model_1.BodyType.Polygon, "sat"); +const polygonInFunctions = createMap(model_1.BodyType.Polygon, "in"); +exports.DEG2RAD = Math.PI / 180; +exports.RAD2DEG = 180 / Math.PI; +/** + * convert from degrees to radians + */ +function deg2rad(degrees) { + return degrees * exports.DEG2RAD; +} +/** + * convert from radians to degrees + */ +function rad2deg(radians) { + return radians * exports.RAD2DEG; +} +/** + * creates ellipse-shaped polygon based on params + */ +function createEllipse(radiusX, radiusY = radiusX, step = 1) { + const steps = Math.PI * Math.hypot(radiusX, radiusY) * 2; + const length = Math.max(8, Math.ceil(steps / Math.max(1, step))); + const ellipse = []; + for (let index = 0; index < length; index++) { + const value = (index / length) * 2 * Math.PI; + const x = Math.cos(value) * radiusX; + const y = Math.sin(value) * radiusY; + ellipse.push(new sat_1.Vector(x, y)); + } + return ellipse; +} +/** + * creates box shaped polygon points + */ +function createBox(width, height) { + return [ + new sat_1.Vector(0, 0), + new sat_1.Vector(width, 0), + new sat_1.Vector(width, height), + new sat_1.Vector(0, height) + ]; +} +/** + * ensure SATVector type point result + */ +function ensureVectorPoint(point = {}) { + return point instanceof sat_1.Vector + ? point + : new sat_1.Vector(point.x || 0, point.y || 0); +} +/** + * ensure Vector points (for polygon) in counter-clockwise order + */ +function ensurePolygonPoints(points = []) { + const polygonPoints = (0, optimized_1.map)(points, ensureVectorPoint); + return clockwise(polygonPoints) ? polygonPoints.reverse() : polygonPoints; +} +/** + * get distance between two Vector points + */ +function distance(bodyA, bodyB) { + const xDiff = bodyA.x - bodyB.x; + const yDiff = bodyA.y - bodyB.y; + return Math.hypot(xDiff, yDiff); +} +/** + * check [is clockwise] direction of polygon + */ +function clockwise(points) { + const length = points.length; + let sum = 0; + (0, optimized_1.forEach)(points, (v1, index) => { + const v2 = points[(index + 1) % length]; + sum += (v2.x - v1.x) * (v2.y + v1.y); + }); + return sum > 0; +} +/** + * used for all types of bodies in constructor + */ +function extendBody(body, options = {}) { + body.isStatic = !!options.isStatic; + body.isTrigger = !!options.isTrigger; + body.padding = options.padding || 0; + body.group = typeof options.group === "number" ? options.group : 0x7FFFFFFF; + if (body.typeGroup !== model_1.BodyGroup.Circle) { + body.isCentered = options.isCentered || false; + } + body.setAngle(options.angle || 0); +} +/** + * check if body moved outside of its padding + */ +function bodyMoved(body) { + const { bbox, minX, minY, maxX, maxY } = body; + return (bbox.minX < minX || bbox.minY < minY || bbox.maxX > maxX || bbox.maxY > maxY); +} +/** + * returns true if two boxes not intersect + */ +function notIntersectAABB(bodyA, bodyB) { + return (bodyB.minX > bodyA.maxX || + bodyB.minY > bodyA.maxY || + bodyB.maxX < bodyA.minX || + bodyB.maxY < bodyA.minY); +} +/** + * checks if two boxes intersect + */ +function intersectAABB(bodyA, bodyB) { + return !notIntersectAABB(bodyA, bodyB); +} +/** + * checks if two bodies can interact (for collision filtering) + */ +function canInteract(bodyA, bodyB) { + return (((bodyA.group >> 16) & (bodyB.group & 0xFFFF) && + (bodyB.group >> 16) & (bodyA.group & 0xFFFF)) !== 0); +} +/** + * checks if body a is in body b + */ +function checkAInB(bodyA, bodyB) { + const check = bodyA.typeGroup === model_1.BodyGroup.Circle + ? circleInFunctions + : polygonInFunctions; + return check[bodyB.type](bodyA, bodyB); +} +/** + * clone sat vector points array into vector points array + */ +function clonePointsArray(points) { + return (0, optimized_1.map)(points, ({ x, y }) => ({ x, y })); +} +/** + * change format from SAT.js to poly-decomp + */ +function mapVectorToArray({ x, y } = { x: 0, y: 0 }) { + return [x, y]; +} +/** + * change format from poly-decomp to SAT.js + */ +function mapArrayToVector([x, y] = [0, 0]) { + return { x, y }; +} +/** + * given 2 bodies calculate vector of bounce assuming equal mass and they are circles + */ +function getBounceDirection(body, collider) { + const v2 = new sat_1.Vector(collider.x - body.x, collider.y - body.y); + const v1 = new sat_1.Vector(body.x - collider.x, body.y - collider.y); + const len = v1.dot(v2.normalize()) * 2; + return new sat_1.Vector(v2.x * len - v1.x, v2.y * len - v1.y).normalize(); +} +/** + * returns correct sat.js testing function based on body types + */ +function getSATTest(bodyA, bodyB) { + const check = bodyA.typeGroup === model_1.BodyGroup.Circle + ? circleSATFunctions + : polygonSATFunctions; + return check[bodyB.type]; +} +/** + * draws dashed line on canvas context + */ +function dashLineTo(context, fromX, fromY, toX, toY, dash = 2, gap = 4) { + const xDiff = toX - fromX; + const yDiff = toY - fromY; + const arc = Math.atan2(yDiff, xDiff); + const offsetX = Math.cos(arc); + const offsetY = Math.sin(arc); + let posX = fromX; + let posY = fromY; + let dist = Math.hypot(xDiff, yDiff); + while (dist > 0) { + const step = Math.min(dist, dash); + context.moveTo(posX, posY); + context.lineTo(posX + offsetX * step, posY + offsetY * step); + posX += offsetX * (dash + gap); + posY += offsetY * (dash + gap); + dist -= dash + gap; + } +} +/** + * draw polygon + */ +function drawPolygon(context, { pos, calcPoints }, isTrigger = false) { + const lastPoint = calcPoints[calcPoints.length - 1]; + const fromX = pos.x + lastPoint.x; + const fromY = pos.y + lastPoint.y; + if (calcPoints.length === 1) { + context.arc(fromX, fromY, 1, 0, Math.PI * 2); + } + else { + context.moveTo(fromX, fromY); + } + (0, optimized_1.forEach)(calcPoints, (point, index) => { + const toX = pos.x + point.x; + const toY = pos.y + point.y; + if (isTrigger) { + const prev = calcPoints[index - 1] || lastPoint; + dashLineTo(context, pos.x + prev.x, pos.y + prev.y, toX, toY); + } + else { + context.lineTo(toX, toY); + } + }); +} +/** + * draw body bounding body box + */ +function drawBVH(context, body) { + drawPolygon(context, { + pos: { x: body.minX, y: body.minY }, + calcPoints: createBox(body.maxX - body.minX, body.maxY - body.minY) + }); +} +/** + * clone response object returning new response with previous ones values + */ +function cloneResponse(response) { + const clone = new sat_1.Response(); + const { a, b, overlap, overlapN, overlapV, aInB, bInA } = response; + clone.a = a; + clone.b = b; + clone.overlap = overlap; + clone.overlapN = overlapN.clone(); + clone.overlapV = overlapV.clone(); + clone.aInB = aInB; + clone.bInA = bInA; + return clone; +} +/** + * dummy fn used as default, for optimization + */ +function returnTrue() { + return true; +} +/** + * for groups + */ +function getGroup(group) { + return Math.max(0, Math.min(group, 0x7FFFFFFF)); +} +/** + * binary string to decimal number + */ +function bin2dec(binary) { + return Number(`0b${binary}`.replace(/\s/g, "")); +} +/** + * helper for groupBits() + * + * @param input - number or binary string + */ +function ensureNumber(input) { + return typeof input === "number" ? input : bin2dec(input); +} +/** + * create group bits from category and mask + * + * @param category - category bits + * @param mask - mask bits (default: category) + */ +function groupBits(category, mask = category) { + return (ensureNumber(category) << 16) | ensureNumber(mask); +} +function move(body, speed = 1, updateNow = true) { + if (!speed) { + return; + } + const moveX = Math.cos(body.angle) * speed; + const moveY = Math.sin(body.angle) * speed; + body.setPosition(body.x + moveX, body.y + moveY, updateNow); +} + + +/***/ }), + +/***/ "./src/demo/canvas.js": +/*!****************************!*\ + !*** ./src/demo/canvas.js ***! + \****************************/ +/***/ ((module) => { + +const width = window.innerWidth || 1024; +const height = window.innerHeight || 768; + +class TestCanvas { + constructor(test) { + this.test = test; + + this.element = document.createElement("div"); + this.element.id = "debug"; + this.element.innerHTML = `${this.test.legend} +
+ +
`; + + this.canvas = document.createElement("canvas"); + this.canvas.width = width; + this.canvas.height = height; + + this.context = this.canvas.getContext("2d"); + this.context.font = "24px Arial"; + this.test.context = this.context; + + this.bvhCheckbox = this.element.querySelector("#bvh"); + + if (this.canvas instanceof Node) { + this.element.appendChild(this.canvas); + } + + this.fps = 0; + this.frame = 0; + this.started = Date.now(); + + loop(this.update.bind(this)); + } + + update() { + this.frame++; + + const timeDiff = Date.now() - this.started; + if (timeDiff >= 1000) { + this.fps = this.frame / (timeDiff / 1000); + this.frame = 0; + this.started = Date.now(); + } + + // Clear the canvas + this.context.fillStyle = "#000000"; + this.context.fillRect(0, 0, width, height); + + // Render the bodies + this.context.strokeStyle = "#FFFFFF"; + this.context.beginPath(); + this.test.physics.draw(this.context); + this.context.stroke(); + + // Render the BVH + if (this.bvhCheckbox.checked) { + this.context.strokeStyle = "#00FF00"; + this.context.beginPath(); + this.test.physics.drawBVH(this.context); + this.context.stroke(); + } + + // Render the FPS + this.context.fillStyle = "#FFCC00"; + this.context.fillText( + `FPS: ${this.fps ? this.fps.toFixed(0) : "?"}`, + 24, + 48, + ); + + if (this.test.drawCallback) { + this.test.drawCallback(); + } + } +} + +function loop(callback) { + // interval for fps instead of setTimeout + // and ms = 1 which is lowest nonzero value + // for responsiveness of user input + setInterval(callback, 1); +} + +module.exports.TestCanvas = TestCanvas; + +module.exports.loop = loop; + +module.exports.width = width; + +module.exports.height = height; + + +/***/ }), + +/***/ "./src/demo/stress.js": +/*!****************************!*\ + !*** ./src/demo/stress.js ***! + \****************************/ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +const { BodyGroup } = __webpack_require__(/*! ../model */ "./src/model.ts"); +const { System } = __webpack_require__(/*! ../system */ "./src/system.ts"); +const { getBounceDirection, groupBits } = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +const { width, height, loop } = __webpack_require__(/*! ./canvas */ "./src/demo/canvas.js"); +const seededRandom = (__webpack_require__(/*! random-seed */ "./node_modules/random-seed/index.js").create)("@Prozi").random; + +function random(min, max) { + return Math.floor(seededRandom() * max) + min; +} + +class Stress { + constructor(count = 2000) { + this.size = Math.sqrt((width * height) / (count * 50)); + + this.physics = new System(5); + this.bodies = []; + this.polygons = 0; + this.boxes = 0; + this.circles = 0; + this.ellipses = 0; + this.lines = 0; + this.lastVariant = 0; + this.count = count; + this.bounds = this.getBounds(); + this.enableFiltering = false; + + for (let i = 0; i < count; ++i) { + this.createShape(!random(0, 20)); + } + + this.legend = `
Total: ${count}
+
Polygons: ${this.polygons}
+
Boxes: ${this.boxes}
+
Circles: ${this.circles}
+
Ellipses: ${this.ellipses}
+
Lines: ${this.lines}
+
+ +
+ `; + + this.lastTime = Date.now(); + this.updateBody = this.updateBody.bind(this); + + // observer #debug & add filtering checkbox event + const observer = new window.MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((node) => { + if (node.id == "debug") { + document + .querySelector("#filtering") + .addEventListener("change", () => this.toggleFiltering()); + observer.disconnect(); } - return output; - }; - exports.map = map; + }); + }); + }); + observer.observe(document.querySelector("body"), { + subtree: false, + childList: true, + }); + + this.start = () => { + loop(this.update.bind(this)); + }; + } - /***/ - }, + getBounds() { + return [ + this.physics.createBox({ x: 0, y: 0 }, width, 10, { + isStatic: true, + }), + this.physics.createBox({ x: width - 10, y: 0 }, 10, height, { + isStatic: true, + }), + this.physics.createBox({ x: 0, y: height - 10 }, width, 10, { + isStatic: true, + }), + this.physics.createBox({ x: 0, y: 0 }, 10, height, { + isStatic: true, + }), + ]; + } - /***/ "./src/system.ts": - /*!***********************!*\ - !*** ./src/system.ts ***! - \***********************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; + toggleFiltering() { + this.enableFiltering = !this.enableFiltering; + this.physics.clear(); + this.bodies.length = 0; + this.polygons = 0; + this.boxes = 0; + this.circles = 0; + this.ellipses = 0; + this.lines = 0; + this.lastVariant = 0; + this.bounds = this.getBounds(); + for (let i = 0; i < this.count; ++i) { + this.createShape(!random(0, 20)); + } + } + + update() { + const now = Date.now(); + this.timeScale = Math.min(1000, now - this.lastTime) / 60; + this.lastTime = now; + this.bodies.forEach(this.updateBody); + } + + updateBody(body) { + body.setAngle(body.angle + body.rotationSpeed * this.timeScale, false); + + if (seededRandom() < 0.05 * this.timeScale) { + body.targetScale.x = 0.5 + seededRandom(); + } + + if (seededRandom() < 0.05 * this.timeScale) { + body.targetScale.y = 0.5 + seededRandom(); + } + + if (Math.abs(body.targetScale.x - body.scaleX) > 0.01) { + const scaleX = + body.scaleX + + Math.sign(body.targetScale.x - body.scaleX) * 0.02 * this.timeScale; + const scaleY = + body.scaleY + + Math.sign(body.targetScale.y - body.scaleY) * 0.02 * this.timeScale; + + body.setScale(scaleX, scaleY, false); + } + + // as last step update position, and bounding box + body.setPosition( + body.x + body.directionX * this.timeScale, + body.y + body.directionY * this.timeScale, + ); + + // separate + bounce + this.bounceBody(body); + } + + bounceBody(body) { + const bounces = { x: 0, y: 0 }; + const addBounces = ({ overlapV: { x, y } }) => { + bounces.x += x; + bounces.y += y; + }; + + this.physics.checkOne(body, addBounces); + + if (bounces.x || bounces.y) { + const size = 0.5 * (body.scaleX + body.scaleY); + const bounce = getBounceDirection(body, { + x: body.x + bounces.x, + y: body.y + bounces.y, + }); + + bounce.scale(body.size).add({ + x: body.directionX * size, + y: body.directionY * size, + }); - Object.defineProperty(exports, "__esModule", { value: true }); - exports.System = void 0; - const base_system_1 = __webpack_require__( - /*! ./base-system */ "./src/base-system.ts", + const { x, y } = bounce.normalize(); + + body.directionX = x; + body.directionY = y; + body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; + + body.setPosition(body.x - bounces.x, body.y - bounces.y); + } + } + + createShape(large) { + const minSize = this.size * 1.0 * (large ? seededRandom() + 1 : 1); + const maxSize = this.size * 1.25 * (large ? seededRandom() * 2 + 1 : 1); + const x = random(0, width); + const y = random(0, height); + const direction = (random(0, 360) * Math.PI) / 180; + const options = { + isCentered: true, + padding: (minSize + maxSize) * 0.2, + }; + + let body; + let variant = this.lastVariant++ % 5; + + switch (variant) { + case 0: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Circle); + } + body = this.physics.createCircle( + { x, y }, + random(minSize, maxSize) / 2, + options, ); - const line_1 = __webpack_require__( - /*! ./bodies/line */ "./src/bodies/line.ts", + + ++this.circles; + break; + + case 1: + const width = random(minSize, maxSize); + const height = random(minSize, maxSize); + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Ellipse); + console.log(); + } + body = this.physics.createEllipse({ x, y }, width, height, 2, options); + + ++this.ellipses; + break; + + case 2: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Box); + } + body = this.physics.createBox( + { x, y }, + random(minSize, maxSize), + random(minSize, maxSize), + options, ); - const intersect_1 = __webpack_require__( - /*! ./intersect */ "./src/intersect.ts", + + ++this.boxes; + break; + + case 3: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Line); + } + body = this.physics.createLine( + { x, y }, + { + x: x + random(minSize, maxSize), + y: y + random(minSize, maxSize), + }, + options, ); - const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); - const optimized_1 = __webpack_require__( - /*! ./optimized */ "./src/optimized.ts", + + ++this.lines; + break; + + default: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Polygon); + } + body = this.physics.createPolygon( + { x, y }, + [ + { x: -random(minSize, maxSize), y: random(minSize, maxSize) }, + { x: random(minSize, maxSize), y: random(minSize, maxSize) }, + { x: random(minSize, maxSize), y: -random(minSize, maxSize) }, + { x: -random(minSize, maxSize), y: -random(minSize, maxSize) }, + ], + options, ); - const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); - /** - * collision system - */ - class System extends base_system_1.BaseSystem { - constructor() { - super(...arguments); - /** - * the last collision result - */ - this.response = new model_1.Response(); - } - /** - * re-insert body into collision tree and update its bbox - * every body can be part of only one system - */ - insert(body) { - const insertResult = super.insert(body); - // set system for later body.system.updateBody(body) - body.system = this; - return insertResult; - } - /** - * separate (move away) bodies - */ - separate() { - (0, optimized_1.forEach)(this.all(), (body) => { - this.separateBody(body); - }); - } - /** - * separate (move away) 1 body - */ - separateBody(body) { - if (body.isStatic || body.isTrigger) { - return; - } - const offsets = { x: 0, y: 0 }; - const addOffsets = ({ overlapV: { x, y } }) => { - offsets.x += x; - offsets.y += y; - }; - this.checkOne(body, addOffsets); - if (offsets.x || offsets.y) { - body.setPosition(body.x - offsets.x, body.y - offsets.y); - } - } - /** - * check one body collisions with callback - */ - checkOne( - body, - callback = utils_1.returnTrue, - response = this.response, - ) { - // no need to check static body collision - if (body.isStatic) { - return false; - } - const bodies = this.search(body); - const checkCollision = (candidate) => { - if ( - candidate !== body && - this.checkCollision(body, candidate, response) - ) { - return callback(response); - } - }; - return (0, optimized_1.some)(bodies, checkCollision); - } - /** - * check all bodies collisions in area with callback - */ - checkArea( - area, - callback = utils_1.returnTrue, - response = this.response, - ) { - const checkOne = (body) => { - return this.checkOne(body, callback, response); - }; - return (0, optimized_1.some)(this.search(area), checkOne); - } - /** - * check all bodies collisions with callback - */ - checkAll(callback = utils_1.returnTrue, response = this.response) { - const checkOne = (body) => { - return this.checkOne(body, callback, response); - }; - return (0, optimized_1.some)(this.all(), checkOne); - } - /** - * check do 2 objects collide - */ - checkCollision(bodyA, bodyB, response = this.response) { - const { bbox: bboxA } = bodyA; - const { bbox: bboxB } = bodyA; - // assess the bodies real aabb without padding - if ( - !(0, utils_1.canInteract)(bodyA, bodyB) || - !bboxA || - !bboxB || - (0, utils_1.notIntersectAABB)(bboxA, bboxB) - ) { - return false; - } - const sat = (0, utils_1.getSATTest)(bodyA, bodyB); - // 99% of cases - if (bodyA.isConvex && bodyB.isConvex) { - // always first clear response - response.clear(); - return sat(bodyA, bodyB, response); - } - // more complex (non convex) cases - const convexBodiesA = (0, intersect_1.ensureConvex)(bodyA); - const convexBodiesB = (0, intersect_1.ensureConvex)(bodyB); - let overlapX = 0; - let overlapY = 0; - let collided = false; - (0, optimized_1.forEach)(convexBodiesA, (convexBodyA) => { - (0, optimized_1.forEach)(convexBodiesB, (convexBodyB) => { - // always first clear response - response.clear(); - if (sat(convexBodyA, convexBodyB, response)) { - collided = true; - overlapX += response.overlapV.x; - overlapY += response.overlapV.y; + + ++this.polygons; + break; + } + + // set initial rotation angle direction + body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; + body.setAngle((random(0, 360) * Math.PI) / 180); + + body.targetScale = { x: 1, y: 1 }; + body.size = (minSize + maxSize) / 2; + + body.directionX = Math.cos(direction); + body.directionY = Math.sin(direction); + + this.bodies.push(body); + } +} + +module.exports = Stress; + + +/***/ }), + +/***/ "./src/demo/tank.js": +/*!**************************!*\ + !*** ./src/demo/tank.js ***! + \**************************/ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +const { BodyGroup } = __webpack_require__(/*! ../model */ "./src/model.ts"); +const { System } = __webpack_require__(/*! ../system */ "./src/system.ts"); +const { mapVectorToArray } = __webpack_require__(/*! ../utils */ "./src/utils.ts"); +const { width, height, loop } = __webpack_require__(/*! ./canvas */ "./src/demo/canvas.js"); + +class Tank { + constructor() { + this.physics = new System(); + this.bodies = []; + this.player = this.createPlayer(400, 300); + + this.createPolygon( + 300, + 300, + [ + { x: -11.25, y: -6.76 }, + { x: -12.5, y: -6.76 }, + { x: -12.5, y: 6.75 }, + { x: -3.1, y: 6.75 }, + { x: -3.1, y: 0.41 }, + { x: -2.35, y: 0.41 }, + { x: -2.35, y: 6.75 }, + { x: 0.77, y: 6.75 }, + { x: 0.77, y: 7.5 }, + { x: -13.25, y: 7.5 }, + { x: -13.25, y: -7.51 }, + { x: -11.25, y: -7.51 }, + ] + .map(mapVectorToArray) + .map(([x, y]) => [x * 10, y * 10]), + ); + + this.up = false; + this.down = false; + this.left = false; + this.right = false; + + this.legend = `
W, S - Accelerate/Decelerate
+
A, D - Turn
`; + + const updateKeys = ({ type, key }) => { + const keyDown = type === "keydown"; + const keyLowerCase = key.toLowerCase(); + + keyLowerCase === "w" && (this.up = keyDown); + keyLowerCase === "s" && (this.down = keyDown); + keyLowerCase === "a" && (this.left = keyDown); + keyLowerCase === "d" && (this.right = keyDown); + }; + + document.addEventListener("keydown", updateKeys); + document.addEventListener("keyup", updateKeys); + + if (this.canvas instanceof Node) { + this.element.appendChild(this.canvas); + } + + this.createMap(); + this.lastTime = Date.now(); + + this.start = () => { + loop(this.update.bind(this)); + }; + } + + update() { + const now = Date.now(); + this.timeScale = Math.min(1000, now - this.lastTime) / 60; + this.lastTime = now; + this.handleInput(); + this.processGameLogic(); + this.handleCollisions(); + this.updateTurret(); + } + + handleInput() { + if (this.up) { + this.player.velocity += 0.2 * this.timeScale; + } + + if (this.down) { + this.player.velocity -= 0.2 * this.timeScale; + } + + if (this.left) { + this.player.setAngle(this.player.angle - 0.2 * this.timeScale); + } + + if (this.right) { + this.player.setAngle(this.player.angle + 0.2 * this.timeScale); + } + } + + processGameLogic() { + const x = Math.cos(this.player.angle); + const y = Math.sin(this.player.angle); + + if (this.player.velocity > 0) { + this.player.velocity = Math.max( + this.player.velocity - 0.1 * this.timeScale, + 0, + ); + + if (this.player.velocity > 2) { + this.player.velocity = 2; + } + } else if (this.player.velocity < 0) { + this.player.velocity = Math.min( + this.player.velocity + 0.1 * this.timeScale, + 0, + ); + + if (this.player.velocity < -2) { + this.player.velocity = -2; + } + } + + if (!Math.round(this.player.velocity * 100)) { + this.player.velocity = 0; + } + + if (this.player.velocity) { + this.player.setPosition( + this.player.x + x * this.player.velocity, + this.player.y + y * this.player.velocity, + ); + } + } + + handleCollisions() { + this.physics.checkAll(({ a, b, overlapV }) => { + if (a.isTrigger || b.isTrigger) { + return; + } + + if (a.typeGroup === BodyGroup.Polygon || a === this.player) { + a.setPosition(a.pos.x - overlapV.x, a.pos.y - overlapV.y); + } + + if (b.typeGroup === BodyGroup.Circle || b === this.player) { + b.setPosition(b.pos.x + overlapV.x, b.pos.y + overlapV.y); + } + + if (a === this.player) { + a.velocity *= 0.9; + } + }); + } + + updateTurret() { + this.playerTurret.setAngle(this.player.angle, false); + this.playerTurret.setPosition(this.player.x, this.player.y); + + const hit = this.physics.raycast( + this.playerTurret.start, + this.playerTurret.end, + (test) => test !== this.player, + ); + + this.drawCallback = () => { + if (hit) { + this.context.strokeStyle = "#FF0000"; + this.context.beginPath(); + this.context.arc(hit.point.x, hit.point.y, 5, 0, 2 * Math.PI); + this.context.stroke(); + } + }; + } + + createPlayer(x, y, size = 13) { + const player = + Math.random() < 0.5 + ? this.physics.createCircle( + { x: this.scaleX(x), y: this.scaleY(y) }, + this.scaleX(size / 2), + { isCentered: true }, + ) + : this.physics.createBox( + { x: this.scaleX(x - size / 2), y: this.scaleY(y - size / 2) }, + this.scaleX(size), + this.scaleX(size), + { isCentered: true }, + ); + + player.velocity = 0; + player.setOffset({ x: -this.scaleX(size / 2), y: 0 }); + player.setAngle(0.2); + + this.physics.updateBody(player); + this.playerTurret = this.physics.createLine( + player, + { x: player.x + this.scaleX(20) + this.scaleY(20), y: player.y }, + { angle: 0.2, isTrigger: true }, + ); + + return player; + } + + scaleX(x) { + return (x / 800) * width; + } + + scaleY(y) { + return (y / 600) * height; + } + + createCircle(x, y, radius) { + this.physics.createCircle( + { x: this.scaleX(x), y: this.scaleY(y) }, + this.scaleX(radius), + ); + } + + createEllipse(x, y, radiusX, radiusY, step, angle) { + this.physics.createEllipse( + { x: this.scaleX(x), y: this.scaleY(y) }, + this.scaleX(radiusX), + this.scaleY(radiusY), + step, + { angle }, + ); + } + + createPolygon(x, y, points, angle) { + const scaledPoints = points.map(([pointX, pointY]) => ({ + x: this.scaleX(pointX), + y: this.scaleY(pointY), + })); + + return this.physics.createPolygon( + { x: this.scaleX(x), y: this.scaleY(y) }, + scaledPoints, + { angle, isStatic: true }, + ); + } + + createMap(width = 800, height = 600) { + // World bounds + // World bounds + this.createPolygon(0, 0, [ + [0, 0], + [width, 0], + ]); + this.createPolygon(0, 0, [ + [width, 0], + [width, height], + ]); + this.createPolygon(0, 0, [ + [width, height], + [0, height], + ]); + this.createPolygon(0, 0, [ + [0, height], + [0, 0], + ]); + + // Factory + this.createPolygon( + 100, + 100, + [ + [-50, -50], + [50, -50], + [50, 50], + [-50, 50], + ], + 0.4, + ); + this.createPolygon( + 190, + 105, + [ + [-20, -20], + [20, -20], + [20, 20], + [-20, 20], + ], + 0.4, + ); + this.createCircle(170, 140, 6); + this.createCircle(185, 155, 6); + this.createCircle(165, 165, 6); + this.createCircle(145, 165, 6); + + // Airstrip + this.createPolygon( + 230, + 50, + [ + [-150, -30], + [150, -30], + [150, 30], + [-150, 30], + ], + 0.4, + ); + + // HQ + this.createPolygon( + 100, + 500, + [ + [-40, -50], + [40, -50], + [50, 50], + [-50, 50], + ], + 0.2, + ); + this.createCircle(180, 490, 12); + this.createCircle(175, 540, 12); + + // Barracks + this.createPolygon( + 400, + 500, + [ + [-60, -20], + [60, -20], + [60, 20], + [-60, 20], + ], + 1.7, + ); + this.createPolygon( + 350, + 494, + [ + [-60, -20], + [60, -20], + [60, 20], + [-60, 20], + ], + 1.7, + ); + + // Mountains + this.createPolygon(750, 0, [ + [0, 0], + [-20, 100], + ]); + this.createPolygon(750, 0, [ + [-20, 100], + [30, 250], + ]); + this.createPolygon(750, 0, [ + [30, 250], + [20, 300], + ]); + this.createPolygon(750, 0, [ + [20, 300], + [-50, 320], + ]); + this.createPolygon(750, 0, [ + [-50, 320], + [-90, 500], + ]); + this.createPolygon(750, 0, [ + [-90, 500], + [-200, 600], + ]); + + // Lake + this.createEllipse(530, 130, 80, 70, 10, -0.2); + } +} + +module.exports = Tank; + + +/***/ }), + +/***/ "./src/rbush.js": +/*!**********************!*\ + !*** ./src/rbush.js ***! + \**********************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ RBush) +/* harmony export */ }); +/* harmony import */ var quickselect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! quickselect */ "./node_modules/quickselect/index.js"); + + +class RBush { + constructor(maxEntries = 9) { + // max entries in a node is 9 by default; min node fill is 40% for best performance + this._maxEntries = Math.max(4, maxEntries); + this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); + this.clear(); + } + + all() { + return this._all(this.data, []); + } + + search(bbox) { + let node = this.data; + const result = []; + + if (!intersects(bbox, node)) return result; + + const toBBox = this.toBBox; + const nodesToSearch = []; + + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? toBBox(child) : child; + + if (intersects(bbox, childBBox)) { + if (node.leaf) result.push(child); + else if (contains(bbox, childBBox)) this._all(child, result); + else nodesToSearch.push(child); } - }); - }); - if (collided) { - const vector = new model_1.SATVector(overlapX, overlapY); - response.a = bodyA; - response.b = bodyB; - response.overlapV.x = overlapX; - response.overlapV.y = overlapY; - response.overlapN = vector.normalize(); - response.overlap = vector.len(); - response.aInB = (0, utils_1.checkAInB)(bodyA, bodyB); - response.bInA = (0, utils_1.checkAInB)(bodyB, bodyA); - } - return collided; - } - /** - * raycast to get collider of ray from start to end - */ - raycast(start, end, allow = utils_1.returnTrue) { - let minDistance = Infinity; - let result = null; - if (!this.ray) { - this.ray = new line_1.Line(start, end, { isTrigger: true }); - } else { - this.ray.start = start; - this.ray.end = end; } - this.insert(this.ray); - this.checkOne(this.ray, ({ b: body }) => { - if (!allow(body, this.ray)) { - return false; - } - const points = - body.typeGroup === model_1.BodyGroup.Circle - ? (0, intersect_1.intersectLineCircle)(this.ray, body) - : (0, intersect_1.intersectLinePolygon)(this.ray, body); - (0, optimized_1.forEach)(points, (point) => { - const pointDistance = (0, utils_1.distance)(start, point); - if (pointDistance < minDistance) { - minDistance = pointDistance; - result = { point, body }; - } - }); - }); - this.remove(this.ray); - return result; - } + node = nodesToSearch.pop(); } - exports.System = System; - /***/ - }, + return result; + } - /***/ "./src/utils.ts": - /*!**********************!*\ - !*** ./src/utils.ts ***! - \**********************/ - /***/ (__unused_webpack_module, exports, __webpack_require__) => { - "use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); - exports.groupBits = - exports.ensureNumber = - exports.bin2dec = - exports.getGroup = - exports.returnTrue = - exports.cloneResponse = - exports.drawBVH = - exports.drawPolygon = - exports.dashLineTo = - exports.getSATTest = - exports.getBounceDirection = - exports.mapArrayToVector = - exports.mapVectorToArray = - exports.clonePointsArray = - exports.checkAInB = - exports.canInteract = - exports.intersectAABB = - exports.notIntersectAABB = - exports.bodyMoved = - exports.extendBody = - exports.clockwise = - exports.distance = - exports.ensurePolygonPoints = - exports.ensureVectorPoint = - exports.createBox = - exports.createEllipse = - exports.rad2deg = - exports.deg2rad = - exports.RAD2DEG = - exports.DEG2RAD = - void 0; - const sat_1 = __webpack_require__( - /*! sat */ "./node_modules/.pnpm/sat@0.9.0/node_modules/sat/SAT.js", - ); - const intersect_1 = __webpack_require__( - /*! ./intersect */ "./src/intersect.ts", - ); - const model_1 = __webpack_require__(/*! ./model */ "./src/model.ts"); - const optimized_1 = __webpack_require__( - /*! ./optimized */ "./src/optimized.ts", - ); - /* helpers for faster getSATTest() and checkAInB() */ - const testMap = { - satCircleCircle: sat_1.testCircleCircle, - satCirclePolygon: sat_1.testCirclePolygon, - satPolygonCircle: sat_1.testPolygonCircle, - satPolygonPolygon: sat_1.testPolygonPolygon, - inCircleCircle: intersect_1.circleInCircle, - inCirclePolygon: intersect_1.circleInPolygon, - inPolygonCircle: intersect_1.polygonInCircle, - inPolygonPolygon: intersect_1.polygonInPolygon, - }; - function createMap(bodyType, testType) { - return Object.values(model_1.BodyType).reduce( - (result, type) => - Object.assign(Object.assign({}, result), { - [type]: - type === model_1.BodyType.Circle - ? testMap[`${testType}${bodyType}Circle`] - : testMap[`${testType}${bodyType}Polygon`], - }), - {}, - ); - } - const circleSATFunctions = createMap(model_1.BodyType.Circle, "sat"); - const circleInFunctions = createMap(model_1.BodyType.Circle, "in"); - const polygonSATFunctions = createMap(model_1.BodyType.Polygon, "sat"); - const polygonInFunctions = createMap(model_1.BodyType.Polygon, "in"); - exports.DEG2RAD = Math.PI / 180; - exports.RAD2DEG = 180 / Math.PI; - /** - * convert from degrees to radians - */ - function deg2rad(degrees) { - return degrees * exports.DEG2RAD; - } - exports.deg2rad = deg2rad; - /** - * convert from radians to degrees - */ - function rad2deg(radians) { - return radians * exports.RAD2DEG; - } - exports.rad2deg = rad2deg; - /** - * creates ellipse-shaped polygon based on params - */ - function createEllipse(radiusX, radiusY = radiusX, step = 1) { - const steps = Math.PI * Math.hypot(radiusX, radiusY) * 2; - const length = Math.max(8, Math.ceil(steps / Math.max(1, step))); - const ellipse = []; - for (let index = 0; index < length; index++) { - const value = (index / length) * 2 * Math.PI; - const x = Math.cos(value) * radiusX; - const y = Math.sin(value) * radiusY; - ellipse.push(new sat_1.Vector(x, y)); - } - return ellipse; - } - exports.createEllipse = createEllipse; - /** - * creates box shaped polygon points - */ - function createBox(width, height) { - return [ - new sat_1.Vector(0, 0), - new sat_1.Vector(width, 0), - new sat_1.Vector(width, height), - new sat_1.Vector(0, height), - ]; - } - exports.createBox = createBox; - /** - * ensure SATVector type point result - */ - function ensureVectorPoint(point = {}) { - return point instanceof sat_1.Vector - ? point - : new sat_1.Vector(point.x || 0, point.y || 0); - } - exports.ensureVectorPoint = ensureVectorPoint; - /** - * ensure Vector points (for polygon) in counter-clockwise order - */ - function ensurePolygonPoints(points = []) { - const polygonPoints = (0, optimized_1.map)(points, ensureVectorPoint); - return clockwise(polygonPoints) - ? polygonPoints.reverse() - : polygonPoints; - } - exports.ensurePolygonPoints = ensurePolygonPoints; - /** - * get distance between two Vector points - */ - function distance(bodyA, bodyB) { - const xDiff = bodyA.x - bodyB.x; - const yDiff = bodyA.y - bodyB.y; - return Math.hypot(xDiff, yDiff); - } - exports.distance = distance; - /** - * check [is clockwise] direction of polygon - */ - function clockwise(points) { - const length = points.length; - let sum = 0; - (0, optimized_1.forEach)(points, (v1, index) => { - const v2 = points[(index + 1) % length]; - sum += (v2.x - v1.x) * (v2.y + v1.y); - }); - return sum > 0; - } - exports.clockwise = clockwise; - /** - * used for all types of bodies in constructor - */ - function extendBody(body, options = {}) { - body.isStatic = !!options.isStatic; - body.isTrigger = !!options.isTrigger; - body.padding = options.padding || 0; - body.group = - typeof options.group === "number" ? options.group : 0x7fffffff; - if (body.typeGroup !== model_1.BodyGroup.Circle) { - body.isCentered = options.isCentered || false; - } - body.setAngle(options.angle || 0); - } - exports.extendBody = extendBody; - /** - * check if body moved outside of its padding - */ - function bodyMoved(body) { - const { bbox, minX, minY, maxX, maxY } = body; - return ( - bbox.minX < minX || - bbox.minY < minY || - bbox.maxX > maxX || - bbox.maxY > maxY - ); - } - exports.bodyMoved = bodyMoved; - /** - * returns true if two boxes not intersect - */ - function notIntersectAABB(bodyA, bodyB) { - return ( - bodyB.minX > bodyA.maxX || - bodyB.minY > bodyA.maxY || - bodyB.maxX < bodyA.minX || - bodyB.maxY < bodyA.minY - ); - } - exports.notIntersectAABB = notIntersectAABB; - /** - * checks if two boxes intersect - */ - function intersectAABB(bodyA, bodyB) { - return !notIntersectAABB(bodyA, bodyB); - } - exports.intersectAABB = intersectAABB; - /** - * checks if two bodies can interact (for collision filtering) - */ - function canInteract(bodyA, bodyB) { - return ( - ((bodyA.group >> 16) & (bodyB.group & 0xffff) && - (bodyB.group >> 16) & (bodyA.group & 0xffff)) !== 0 - ); - } - exports.canInteract = canInteract; - /** - * checks if body a is in body b - */ - function checkAInB(bodyA, bodyB) { - const check = - bodyA.typeGroup === model_1.BodyGroup.Circle - ? circleInFunctions - : polygonInFunctions; - return check[bodyB.type](bodyA, bodyB); - } - exports.checkAInB = checkAInB; - /** - * clone sat vector points array into vector points array - */ - function clonePointsArray(points) { - return (0, optimized_1.map)(points, ({ x, y }) => ({ x, y })); - } - exports.clonePointsArray = clonePointsArray; - /** - * change format from SAT.js to poly-decomp - */ - function mapVectorToArray({ x, y } = { x: 0, y: 0 }) { - return [x, y]; - } - exports.mapVectorToArray = mapVectorToArray; - /** - * change format from poly-decomp to SAT.js - */ - function mapArrayToVector([x, y] = [0, 0]) { - return { x, y }; - } - exports.mapArrayToVector = mapArrayToVector; - /** - * given 2 bodies calculate vector of bounce assuming equal mass and they are circles - */ - function getBounceDirection(body, collider) { - const v2 = new sat_1.Vector(collider.x - body.x, collider.y - body.y); - const v1 = new sat_1.Vector(body.x - collider.x, body.y - collider.y); - const len = v1.dot(v2.normalize()) * 2; - return new sat_1.Vector( - v2.x * len - v1.x, - v2.y * len - v1.y, - ).normalize(); - } - exports.getBounceDirection = getBounceDirection; - /** - * returns correct sat.js testing function based on body types - */ - function getSATTest(bodyA, bodyB) { - const check = - bodyA.typeGroup === model_1.BodyGroup.Circle - ? circleSATFunctions - : polygonSATFunctions; - return check[bodyB.type]; - } - exports.getSATTest = getSATTest; - /** - * draws dashed line on canvas context - */ - function dashLineTo( - context, - fromX, - fromY, - toX, - toY, - dash = 2, - gap = 4, - ) { - const xDiff = toX - fromX; - const yDiff = toY - fromY; - const arc = Math.atan2(yDiff, xDiff); - const offsetX = Math.cos(arc); - const offsetY = Math.sin(arc); - let posX = fromX; - let posY = fromY; - let dist = Math.hypot(xDiff, yDiff); - while (dist > 0) { - const step = Math.min(dist, dash); - context.moveTo(posX, posY); - context.lineTo(posX + offsetX * step, posY + offsetY * step); - posX += offsetX * (dash + gap); - posY += offsetY * (dash + gap); - dist -= dash + gap; - } - } - exports.dashLineTo = dashLineTo; - /** - * draw polygon - */ - function drawPolygon(context, { pos, calcPoints }, isTrigger = false) { - const lastPoint = calcPoints[calcPoints.length - 1]; - const fromX = pos.x + lastPoint.x; - const fromY = pos.y + lastPoint.y; - if (calcPoints.length === 1) { - context.arc(fromX, fromY, 1, 0, Math.PI * 2); - } else { - context.moveTo(fromX, fromY); - } - (0, optimized_1.forEach)(calcPoints, (point, index) => { - const toX = pos.x + point.x; - const toY = pos.y + point.y; - if (isTrigger) { - const prev = calcPoints[index - 1] || lastPoint; - dashLineTo(context, pos.x + prev.x, pos.y + prev.y, toX, toY); - } else { - context.lineTo(toX, toY); + collides(bbox) { + let node = this.data; + + if (!intersects(bbox, node)) return false; + + const nodesToSearch = []; + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? this.toBBox(child) : child; + + if (intersects(bbox, childBBox)) { + if (node.leaf || contains(bbox, childBBox)) return true; + nodesToSearch.push(child); + } } - }); - } - exports.drawPolygon = drawPolygon; - /** - * draw body bounding body box - */ - function drawBVH(context, body) { - drawPolygon(context, { - pos: { x: body.minX, y: body.minY }, - calcPoints: createBox(body.maxX - body.minX, body.maxY - body.minY), - }); - } - exports.drawBVH = drawBVH; - /** - * clone response object returning new response with previous ones values - */ - function cloneResponse(response) { - const clone = new sat_1.Response(); - const { a, b, overlap, overlapN, overlapV, aInB, bInA } = response; - clone.a = a; - clone.b = b; - clone.overlap = overlap; - clone.overlapN = overlapN.clone(); - clone.overlapV = overlapV.clone(); - clone.aInB = aInB; - clone.bInA = bInA; - return clone; - } - exports.cloneResponse = cloneResponse; - /** - * dummy fn used as default, for optimization - */ - function returnTrue() { - return true; - } - exports.returnTrue = returnTrue; - /** - * for groups - */ - function getGroup(group) { - return Math.max(0, Math.min(group, 0x7fffffff)); + node = nodesToSearch.pop(); } - exports.getGroup = getGroup; - /** - * binary string to decimal number - */ - function bin2dec(binary) { - return Number(`0b${binary}`.replace(/\s/g, "")); - } - exports.bin2dec = bin2dec; - /** - * helper for groupBits() - * - * @param input - number or binary string - */ - function ensureNumber(input) { - return typeof input === "number" ? input : bin2dec(input); - } - exports.ensureNumber = ensureNumber; - /** - * create group bits from category and mask - * - * @param category - category bits - * @param mask - mask bits (default: category) - */ - function groupBits(category, mask = category) { - return (ensureNumber(category) << 16) | ensureNumber(mask); + + return false; + } + + load(data) { + if (!(data && data.length)) return this; + + if (data.length < this._minEntries) { + for (let i = 0; i < data.length; i++) { + this.insert(data[i]); + } + return this; } - exports.groupBits = groupBits; - /***/ - }, + // recursively build the tree with the given data from scratch using OMT algorithm + let node = this._build(data.slice(), 0, data.length - 1, 0); - /***/ "./src/demo/canvas.js": - /*!****************************!*\ - !*** ./src/demo/canvas.js ***! - \****************************/ - /***/ (module) => { - const width = window.innerWidth || 1024; - const height = window.innerHeight || 768; + if (!this.data.children.length) { + // save as is if tree is empty + this.data = node; - class TestCanvas { - constructor(test) { - this.test = test; + } else if (this.data.height === node.height) { + // split root if trees have the same height + this._splitRoot(this.data, node); - this.element = document.createElement("div"); - this.element.id = "debug"; - this.element.innerHTML = `${this.test.legend} -
- -
`; + } else { + if (this.data.height < node.height) { + // swap trees if inserted one is bigger + const tmpNode = this.data; + this.data = node; + node = tmpNode; + } - this.canvas = document.createElement("canvas"); - this.canvas.width = width; - this.canvas.height = height; + // insert the small tree into the large tree at appropriate level + this._insert(node, this.data.height - node.height - 1, true); + } - this.context = this.canvas.getContext("2d"); - this.context.font = "24px Arial"; - this.test.context = this.context; + return this; + } - this.bvhCheckbox = this.element.querySelector("#bvh"); + insert(item) { + if (item) this._insert(item, this.data.height - 1); + return this; + } - if (this.canvas instanceof Node) { - this.element.appendChild(this.canvas); - } + clear() { + this.data = createNode([]); + return this; + } - this.fps = 0; - this.frame = 0; - this.started = Date.now(); + remove(item, equalsFn) { + if (!item) return this; - loop(this.update.bind(this)); - } + let node = this.data; + const bbox = this.toBBox(item); + const path = []; + const indexes = []; + let i, parent, goingUp; - update() { - this.frame++; + // depth-first iterative tree traversal + while (node || path.length) { - const timeDiff = Date.now() - this.started; - if (timeDiff >= 1000) { - this.fps = this.frame / (timeDiff / 1000); - this.frame = 0; - this.started = Date.now(); + if (!node) { // go up + node = path.pop(); + parent = path[path.length - 1]; + i = indexes.pop(); + goingUp = true; } - // Clear the canvas - this.context.fillStyle = "#000000"; - this.context.fillRect(0, 0, width, height); - - // Render the bodies - this.context.strokeStyle = "#FFFFFF"; - this.context.beginPath(); - this.test.physics.draw(this.context); - this.context.stroke(); - - // Render the BVH - if (this.bvhCheckbox.checked) { - this.context.strokeStyle = "#00FF00"; - this.context.beginPath(); - this.test.physics.drawBVH(this.context); - this.context.stroke(); + if (node.leaf) { // check current node + const index = findItem(item, node.children, equalsFn); + + if (index !== -1) { + // item found, remove the item and condense tree upwards + node.children.splice(index, 1); + path.push(node); + this._condense(path); + return this; + } } - // Render the FPS - this.context.fillStyle = "#FFCC00"; - this.context.fillText( - `FPS: ${this.fps ? this.fps.toFixed(0) : "?"}`, - 24, - 48, - ); + if (!goingUp && !node.leaf && contains(node, bbox)) { // go down + path.push(node); + indexes.push(i); + i = 0; + parent = node; + node = node.children[0]; - if (this.test.drawCallback) { - this.test.drawCallback(); - } - } - } + } else if (parent) { // go right + i++; + node = parent.children[i]; + goingUp = false; - function loop(callback) { - // interval for fps instead of setTimeout - // and ms = 1 which is lowest nonzero value - // for responsiveness of user input - setInterval(callback, 1); + } else node = null; // nothing found } - module.exports.TestCanvas = TestCanvas; + return this; + } - module.exports.loop = loop; + toBBox(item) { return item; } - module.exports.width = width; + compareMinX(a, b) { return a.minX - b.minX; } + compareMinY(a, b) { return a.minY - b.minY; } - module.exports.height = height; + toJSON() { return this.data; } - /***/ - }, + fromJSON(data) { + this.data = data; + return this; + } - /***/ "./src/demo/stress.js": - /*!****************************!*\ - !*** ./src/demo/stress.js ***! - \****************************/ - /***/ (module, __unused_webpack_exports, __webpack_require__) => { - const { BodyGroup } = __webpack_require__( - /*! ../model */ "./src/model.ts", - ); - const { System } = __webpack_require__( - /*! ../system */ "./src/system.ts", - ); - const { getBounceDirection, groupBits } = __webpack_require__( - /*! ../utils */ "./src/utils.ts", - ); - const { width, height, loop } = __webpack_require__( - /*! ./canvas */ "./src/demo/canvas.js", - ); - const seededRandom = __webpack_require__( - /*! random-seed */ "./node_modules/.pnpm/random-seed@0.3.0/node_modules/random-seed/index.js", - ).create("@Prozi").random; + _all(node, result) { + const nodesToSearch = []; + while (node) { + if (node.leaf) result.push(...node.children); + else nodesToSearch.push(...node.children); - function random(min, max) { - return Math.floor(seededRandom() * max) + min; + node = nodesToSearch.pop(); } + return result; + } - class Stress { - constructor(count = 2000) { - this.size = Math.sqrt((width * height) / (count * 50)); - - this.physics = new System(5); - this.bodies = []; - this.polygons = 0; - this.boxes = 0; - this.circles = 0; - this.ellipses = 0; - this.lines = 0; - this.lastVariant = 0; - this.count = count; - this.bounds = this.getBounds(); - this.enableFiltering = false; - - for (let i = 0; i < count; ++i) { - this.createShape(!random(0, 20)); - } + _build(items, left, right, height) { - this.legend = `
Total: ${count}
-
Polygons: ${this.polygons}
-
Boxes: ${this.boxes}
-
Circles: ${this.circles}
-
Ellipses: ${this.ellipses}
-
Lines: ${this.lines}
-
- -
- `; + const N = right - left + 1; + let M = this._maxEntries; + let node; - this.lastTime = Date.now(); - this.updateBody = this.updateBody.bind(this); - - // observer #debug & add filtering checkbox event - const observer = new window.MutationObserver((mutations) => { - mutations.forEach((mutation) => { - mutation.addedNodes.forEach((node) => { - if (node.id == "debug") { - document - .querySelector("#filtering") - .addEventListener("change", () => this.toggleFiltering()); - observer.disconnect(); - } - }); - }); - }); - observer.observe(document.querySelector("body"), { - subtree: false, - childList: true, - }); + if (N <= M) { + // reached leaf level; return leaf + node = createNode(items.slice(left, right + 1)); + calcBBox(node, this.toBBox); + return node; + } - this.start = () => { - loop(this.update.bind(this)); - }; - } + if (!height) { + // target height of the bulk-loaded tree + height = Math.ceil(Math.log(N) / Math.log(M)); - getBounds() { - return [ - this.physics.createBox({ x: 0, y: 0 }, width, 10, { - isStatic: true, - }), - this.physics.createBox({ x: width - 10, y: 0 }, 10, height, { - isStatic: true, - }), - this.physics.createBox({ x: 0, y: height - 10 }, width, 10, { - isStatic: true, - }), - this.physics.createBox({ x: 0, y: 0 }, 10, height, { - isStatic: true, - }), - ]; - } + // target number of root entries to maximize storage utilization + M = Math.ceil(N / Math.pow(M, height - 1)); + } - toggleFiltering() { - this.enableFiltering = !this.enableFiltering; - this.physics.clear(); - this.bodies.length = 0; - this.polygons = 0; - this.boxes = 0; - this.circles = 0; - this.ellipses = 0; - this.lines = 0; - this.lastVariant = 0; - this.bounds = this.getBounds(); - for (let i = 0; i < this.count; ++i) { - this.createShape(!random(0, 20)); - } - } + node = createNode([]); + node.leaf = false; + node.height = height; - update() { - const now = Date.now(); - this.timeScale = Math.min(1000, now - this.lastTime) / 60; - this.lastTime = now; - this.bodies.forEach(this.updateBody); - } + // split the items into M mostly square tiles - updateBody(body) { - body.setAngle( - body.angle + body.rotationSpeed * this.timeScale, - false, - ); + const N2 = Math.ceil(N / M); + const N1 = N2 * Math.ceil(Math.sqrt(M)); - if (seededRandom() < 0.05 * this.timeScale) { - body.targetScale.x = 0.5 + seededRandom(); - } + multiSelect(items, left, right, N1, this.compareMinX); - if (seededRandom() < 0.05 * this.timeScale) { - body.targetScale.y = 0.5 + seededRandom(); - } + for (let i = left; i <= right; i += N1) { - if (Math.abs(body.targetScale.x - body.scaleX) > 0.01) { - const scaleX = - body.scaleX + - Math.sign(body.targetScale.x - body.scaleX) * - 0.02 * - this.timeScale; - const scaleY = - body.scaleY + - Math.sign(body.targetScale.y - body.scaleY) * - 0.02 * - this.timeScale; - - body.setScale(scaleX, scaleY, false); - } + const right2 = Math.min(i + N1 - 1, right); - // as last step update position, and bounding box - body.setPosition( - body.x + body.directionX * this.timeScale, - body.y + body.directionY * this.timeScale, - ); + multiSelect(items, i, right2, N2, this.compareMinY); - // separate + bounce - this.bounceBody(body); - } + for (let j = i; j <= right2; j += N2) { - bounceBody(body) { - const bounces = { x: 0, y: 0 }; - const addBounces = ({ overlapV: { x, y } }) => { - bounces.x += x; - bounces.y += y; - }; + const right3 = Math.min(j + N2 - 1, right2); - this.physics.checkOne(body, addBounces); + // pack each entry recursively + node.children.push(this._build(items, j, right3, height - 1)); + } + } - if (bounces.x || bounces.y) { - const size = 0.5 * (body.scaleX + body.scaleY); - const bounce = getBounceDirection(body, { - x: body.x + bounces.x, - y: body.y + bounces.y, - }); + calcBBox(node, this.toBBox); - bounce.scale(body.size).add({ - x: body.directionX * size, - y: body.directionY * size, - }); + return node; + } - const { x, y } = bounce.normalize(); + _chooseSubtree(bbox, node, level, path) { + while (true) { + path.push(node); - body.directionX = x; - body.directionY = y; - body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; + if (node.leaf || path.length - 1 === level) break; - body.setPosition(body.x - bounces.x, body.y - bounces.y); - } - } + let minArea = Infinity; + let minEnlargement = Infinity; + let targetNode; - createShape(large) { - const minSize = this.size * 1.0 * (large ? seededRandom() + 1 : 1); - const maxSize = - this.size * 1.25 * (large ? seededRandom() * 2 + 1 : 1); - const x = random(0, width); - const y = random(0, height); - const direction = (random(0, 360) * Math.PI) / 180; - const options = { - isCentered: true, - padding: (minSize + maxSize) * 0.2, - }; - - let body; - let variant = this.lastVariant++ % 5; - - switch (variant) { - case 0: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Circle); - } - body = this.physics.createCircle( - { x, y }, - random(minSize, maxSize) / 2, - options, - ); - - ++this.circles; - break; - - case 1: - const width = random(minSize, maxSize); - const height = random(minSize, maxSize); - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Ellipse); - console.log(); - } - body = this.physics.createEllipse( - { x, y }, - width, - height, - 2, - options, - ); - - ++this.ellipses; - break; - - case 2: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Box); - } - body = this.physics.createBox( - { x, y }, - random(minSize, maxSize), - random(minSize, maxSize), - options, - ); - - ++this.boxes; - break; - - case 3: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Line); - } - body = this.physics.createLine( - { x, y }, - { - x: x + random(minSize, maxSize), - y: y + random(minSize, maxSize), - }, - options, - ); - - ++this.lines; - break; - - default: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Polygon); + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const area = bboxArea(child); + const enlargement = enlargedArea(bbox, child) - area; + + // choose entry with the least area enlargement + if (enlargement < minEnlargement) { + minEnlargement = enlargement; + minArea = area < minArea ? area : minArea; + targetNode = child; + + } else if (enlargement === minEnlargement) { + // otherwise choose one with the smallest area + if (area < minArea) { + minArea = area; + targetNode = child; + } } - body = this.physics.createPolygon( - { x, y }, - [ - { - x: -random(minSize, maxSize), - y: random(minSize, maxSize), - }, - { - x: random(minSize, maxSize), - y: random(minSize, maxSize), - }, - { - x: random(minSize, maxSize), - y: -random(minSize, maxSize), - }, - { - x: -random(minSize, maxSize), - y: -random(minSize, maxSize), - }, - ], - options, - ); - - ++this.polygons; - break; } - // set initial rotation angle direction - body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; - body.setAngle((random(0, 360) * Math.PI) / 180); + node = targetNode || node.children[0]; + } + + return node; + } + + _insert(item, level, isNode) { + const bbox = isNode ? item : this.toBBox(item); + const insertPath = []; - body.targetScale = { x: 1, y: 1 }; - body.size = (minSize + maxSize) / 2; + // find the best node for accommodating the item, saving all nodes along the path too + const node = this._chooseSubtree(bbox, this.data, level, insertPath); - body.directionX = Math.cos(direction); - body.directionY = Math.sin(direction); + // put the item into the node + node.children.push(item); + extend(node, bbox); - this.bodies.push(body); - } + // split on node overflow; propagate upwards if necessary + while (level >= 0) { + if (insertPath[level].children.length > this._maxEntries) { + this._split(insertPath, level); + level--; + } else break; } - module.exports = Stress; + // adjust bboxes along the insertion path + this._adjustParentBBoxes(bbox, insertPath, level); + } - /***/ - }, + // split overflowed node into two + _split(insertPath, level) { + const node = insertPath[level]; + const M = node.children.length; + const m = this._minEntries; - /***/ "./src/demo/tank.js": - /*!**************************!*\ - !*** ./src/demo/tank.js ***! - \**************************/ - /***/ (module, __unused_webpack_exports, __webpack_require__) => { - const { BodyGroup } = __webpack_require__( - /*! ../model */ "./src/model.ts", - ); - const { System } = __webpack_require__( - /*! ../system */ "./src/system.ts", - ); - const { mapVectorToArray } = __webpack_require__( - /*! ../utils */ "./src/utils.ts", - ); - const { width, height, loop } = __webpack_require__( - /*! ./canvas */ "./src/demo/canvas.js", - ); + this._chooseSplitAxis(node, m, M); - class Tank { - constructor() { - this.physics = new System(); - this.bodies = []; - this.player = this.createPlayer(400, 300); - - this.createPolygon( - 300, - 300, - [ - { x: -11.25, y: -6.76 }, - { x: -12.5, y: -6.76 }, - { x: -12.5, y: 6.75 }, - { x: -3.1, y: 6.75 }, - { x: -3.1, y: 0.41 }, - { x: -2.35, y: 0.41 }, - { x: -2.35, y: 6.75 }, - { x: 0.77, y: 6.75 }, - { x: 0.77, y: 7.5 }, - { x: -13.25, y: 7.5 }, - { x: -13.25, y: -7.51 }, - { x: -11.25, y: -7.51 }, - ] - .map(mapVectorToArray) - .map(([x, y]) => [x * 10, y * 10]), - ); - - this.up = false; - this.down = false; - this.left = false; - this.right = false; - - this.legend = `
W, S - Accelerate/Decelerate
-
A, D - Turn
`; + const splitIndex = this._chooseSplitIndex(node, m, M); - const updateKeys = ({ type, key }) => { - const keyDown = type === "keydown"; - const keyLowerCase = key.toLowerCase(); + const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex)); + newNode.height = node.height; + newNode.leaf = node.leaf; - keyLowerCase === "w" && (this.up = keyDown); - keyLowerCase === "s" && (this.down = keyDown); - keyLowerCase === "a" && (this.left = keyDown); - keyLowerCase === "d" && (this.right = keyDown); - }; + calcBBox(node, this.toBBox); + calcBBox(newNode, this.toBBox); - document.addEventListener("keydown", updateKeys); - document.addEventListener("keyup", updateKeys); + if (level) insertPath[level - 1].children.push(newNode); + else this._splitRoot(node, newNode); + } - if (this.canvas instanceof Node) { - this.element.appendChild(this.canvas); - } + _splitRoot(node, newNode) { + // split root node + this.data = createNode([node, newNode]); + this.data.height = node.height + 1; + this.data.leaf = false; + calcBBox(this.data, this.toBBox); + } - this.createMap(); - this.lastTime = Date.now(); + _chooseSplitIndex(node, m, M) { + let index; + let minOverlap = Infinity; + let minArea = Infinity; - this.start = () => { - loop(this.update.bind(this)); - }; - } + for (let i = m; i <= M - m; i++) { + const bbox1 = distBBox(node, 0, i, this.toBBox); + const bbox2 = distBBox(node, i, M, this.toBBox); - update() { - const now = Date.now(); - this.timeScale = Math.min(1000, now - this.lastTime) / 60; - this.lastTime = now; - this.handleInput(); - this.processGameLogic(); - this.handleCollisions(); - this.updateTurret(); - } + const overlap = intersectionArea(bbox1, bbox2); + const area = bboxArea(bbox1) + bboxArea(bbox2); - handleInput() { - if (this.up) { - this.player.velocity += 0.2 * this.timeScale; - } + // choose distribution with minimum overlap + if (overlap < minOverlap) { + minOverlap = overlap; + index = i; - if (this.down) { - this.player.velocity -= 0.2 * this.timeScale; - } + minArea = area < minArea ? area : minArea; - if (this.left) { - this.player.setAngle(this.player.angle - 0.2 * this.timeScale); + } else if (overlap === minOverlap) { + // otherwise choose distribution with minimum area + if (area < minArea) { + minArea = area; + index = i; + } } + } - if (this.right) { - this.player.setAngle(this.player.angle + 0.2 * this.timeScale); - } - } + return index || M - m; + } - processGameLogic() { - const x = Math.cos(this.player.angle); - const y = Math.sin(this.player.angle); - - if (this.player.velocity > 0) { - this.player.velocity = Math.max( - this.player.velocity - 0.1 * this.timeScale, - 0, - ); - - if (this.player.velocity > 2) { - this.player.velocity = 2; - } - } else if (this.player.velocity < 0) { - this.player.velocity = Math.min( - this.player.velocity + 0.1 * this.timeScale, - 0, - ); - - if (this.player.velocity < -2) { - this.player.velocity = -2; - } - } + // sorts node children by the best axis for split + _chooseSplitAxis(node, m, M) { + const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX; + const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY; + const xMargin = this._allDistMargin(node, m, M, compareMinX); + const yMargin = this._allDistMargin(node, m, M, compareMinY); - if (!Math.round(this.player.velocity * 100)) { - this.player.velocity = 0; - } + // if total distributions margin value is minimal for x, sort by minX, + // otherwise it's already sorted by minY + if (xMargin < yMargin) node.children.sort(compareMinX); + } - if (this.player.velocity) { - this.player.setPosition( - this.player.x + x * this.player.velocity, - this.player.y + y * this.player.velocity, - ); - } - } + // total margin of all possible split distributions where each node is at least m full + _allDistMargin(node, m, M, compare) { + node.children.sort(compare); - handleCollisions() { - this.physics.checkAll(({ a, b, overlapV }) => { - if (a.isTrigger || b.isTrigger) { - return; - } + const toBBox = this.toBBox; + const leftBBox = distBBox(node, 0, m, toBBox); + const rightBBox = distBBox(node, M - m, M, toBBox); + let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox); - if (a.typeGroup === BodyGroup.Polygon || a === this.player) { - a.setPosition(a.pos.x - overlapV.x, a.pos.y - overlapV.y); - } + for (let i = m; i < M - m; i++) { + const child = node.children[i]; + extend(leftBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(leftBBox); + } - if (b.typeGroup === BodyGroup.Circle || b === this.player) { - b.setPosition(b.pos.x + overlapV.x, b.pos.y + overlapV.y); - } + for (let i = M - m - 1; i >= m; i--) { + const child = node.children[i]; + extend(rightBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(rightBBox); + } - if (a === this.player) { - a.velocity *= 0.9; - } - }); - } + return margin; + } - updateTurret() { - this.playerTurret.setAngle(this.player.angle, false); - this.playerTurret.setPosition(this.player.x, this.player.y); - - const hit = this.physics.raycast( - this.playerTurret.start, - this.playerTurret.end, - (test) => test !== this.player, - ); - - this.drawCallback = () => { - if (hit) { - this.context.strokeStyle = "#FF0000"; - this.context.beginPath(); - this.context.arc(hit.point.x, hit.point.y, 5, 0, 2 * Math.PI); - this.context.stroke(); - } - }; - } + _adjustParentBBoxes(bbox, path, level) { + // adjust bboxes along the given tree path + for (let i = level; i >= 0; i--) { + extend(path[i], bbox); + } + } - createPlayer(x, y, size = 13) { - const player = - Math.random() < 0.5 - ? this.physics.createCircle( - { x: this.scaleX(x), y: this.scaleY(y) }, - this.scaleX(size / 2), - { isCentered: true }, - ) - : this.physics.createBox( - { - x: this.scaleX(x - size / 2), - y: this.scaleY(y - size / 2), - }, - this.scaleX(size), - this.scaleX(size), - { isCentered: true }, - ); - - player.velocity = 0; - player.setOffset({ x: -this.scaleX(size / 2), y: 0 }); - player.setAngle(0.2); - - this.physics.updateBody(player); - this.playerTurret = this.physics.createLine( - player, - { x: player.x + this.scaleX(20) + this.scaleY(20), y: player.y }, - { angle: 0.2, isTrigger: true }, - ); - - return player; - } + _condense(path) { + // go through the path, removing empty nodes and updating bboxes + for (let i = path.length - 1, siblings; i >= 0; i--) { + if (path[i].children.length === 0) { + if (i > 0) { + siblings = path[i - 1].children; + siblings.splice(siblings.indexOf(path[i]), 1); - scaleX(x) { - return (x / 800) * width; - } + } else this.clear(); - scaleY(y) { - return (y / 600) * height; - } + } else calcBBox(path[i], this.toBBox); + } + } +} - createCircle(x, y, radius) { - this.physics.createCircle( - { x: this.scaleX(x), y: this.scaleY(y) }, - this.scaleX(radius), - ); - } +function findItem(item, items, equalsFn) { + if (!equalsFn) return items.indexOf(item); - createEllipse(x, y, radiusX, radiusY, step, angle) { - this.physics.createEllipse( - { x: this.scaleX(x), y: this.scaleY(y) }, - this.scaleX(radiusX), - this.scaleY(radiusY), - step, - { angle }, - ); - } + for (let i = 0; i < items.length; i++) { + if (equalsFn(item, items[i])) return i; + } + return -1; +} + +// calculate node's bbox from bboxes of its children +function calcBBox(node, toBBox) { + distBBox(node, 0, node.children.length, toBBox, node); +} + +// min bounding rectangle of node children from k to p-1 +function distBBox(node, k, p, toBBox, destNode) { + if (!destNode) destNode = createNode(null); + destNode.minX = Infinity; + destNode.minY = Infinity; + destNode.maxX = -Infinity; + destNode.maxY = -Infinity; + + for (let i = k; i < p; i++) { + const child = node.children[i]; + extend(destNode, node.leaf ? toBBox(child) : child); + } - createPolygon(x, y, points, angle) { - const scaledPoints = points.map(([pointX, pointY]) => ({ - x: this.scaleX(pointX), - y: this.scaleY(pointY), - })); - - return this.physics.createPolygon( - { x: this.scaleX(x), y: this.scaleY(y) }, - scaledPoints, - { angle }, - ); - } + return destNode; +} + +function extend(a, b) { + a.minX = Math.min(a.minX, b.minX); + a.minY = Math.min(a.minY, b.minY); + a.maxX = Math.max(a.maxX, b.maxX); + a.maxY = Math.max(a.maxY, b.maxY); + return a; +} + +function compareNodeMinX(a, b) { return a.minX - b.minX; } +function compareNodeMinY(a, b) { return a.minY - b.minY; } + +function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); } +function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); } + +function enlargedArea(a, b) { + return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * + (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY)); +} + +function intersectionArea(a, b) { + const minX = Math.max(a.minX, b.minX); + const minY = Math.max(a.minY, b.minY); + const maxX = Math.min(a.maxX, b.maxX); + const maxY = Math.min(a.maxY, b.maxY); + + return Math.max(0, maxX - minX) * + Math.max(0, maxY - minY); +} + +function contains(a, b) { + return a.minX <= b.minX && + a.minY <= b.minY && + b.maxX <= a.maxX && + b.maxY <= a.maxY; +} + +function intersects(a, b) { + return b.minX <= a.maxX && + b.minY <= a.maxY && + b.maxX >= a.minX && + b.maxY >= a.minY; +} + +function createNode(children) { + return { + children, + height: 1, + leaf: true, + minX: Infinity, + minY: Infinity, + maxX: -Infinity, + maxY: -Infinity + }; +} - createMap(width = 800, height = 600) { - // World bounds - // World bounds - this.createPolygon(0, 0, [ - [0, 0], - [width, 0], - ]); - this.createPolygon(0, 0, [ - [width, 0], - [width, height], - ]); - this.createPolygon(0, 0, [ - [width, height], - [0, height], - ]); - this.createPolygon(0, 0, [ - [0, height], - [0, 0], - ]); - - // Factory - this.createPolygon( - 100, - 100, - [ - [-50, -50], - [50, -50], - [50, 50], - [-50, 50], - ], - 0.4, - ); - this.createPolygon( - 190, - 105, - [ - [-20, -20], - [20, -20], - [20, 20], - [-20, 20], - ], - 0.4, - ); - this.createCircle(170, 140, 6); - this.createCircle(185, 155, 6); - this.createCircle(165, 165, 6); - this.createCircle(145, 165, 6); - - // Airstrip - this.createPolygon( - 230, - 50, - [ - [-150, -30], - [150, -30], - [150, 30], - [-150, 30], - ], - 0.4, - ); - - // HQ - this.createPolygon( - 100, - 500, - [ - [-40, -50], - [40, -50], - [50, 50], - [-50, 50], - ], - 0.2, - ); - this.createCircle(180, 490, 12); - this.createCircle(175, 540, 12); - - // Barracks - this.createPolygon( - 400, - 500, - [ - [-60, -20], - [60, -20], - [60, 20], - [-60, 20], - ], - 1.7, - ); - this.createPolygon( - 350, - 494, - [ - [-60, -20], - [60, -20], - [60, 20], - [-60, 20], - ], - 1.7, - ); - - // Mountains - this.createPolygon(750, 0, [ - [0, 0], - [-20, 100], - ]); - this.createPolygon(750, 0, [ - [-20, 100], - [30, 250], - ]); - this.createPolygon(750, 0, [ - [30, 250], - [20, 300], - ]); - this.createPolygon(750, 0, [ - [20, 300], - [-50, 320], - ]); - this.createPolygon(750, 0, [ - [-50, 320], - [-90, 500], - ]); - this.createPolygon(750, 0, [ - [-90, 500], - [-200, 600], - ]); - - // Lake - this.createEllipse(530, 130, 80, 70, 10, -0.2); - } - } +// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; +// combines selection algorithm with binary divide & conquer approach - module.exports = Tank; +function multiSelect(arr, left, right, n, compare) { + const stack = [left, right]; - /***/ - }, + while (stack.length) { + right = stack.pop(); + left = stack.pop(); - /******/ - }; - /************************************************************************/ - /******/ // The module cache - /******/ var __webpack_module_cache__ = {}; - /******/ - /******/ // The require function - /******/ function __webpack_require__(moduleId) { - /******/ // Check if module is in cache - /******/ var cachedModule = __webpack_module_cache__[moduleId]; - /******/ if (cachedModule !== undefined) { - /******/ return cachedModule.exports; - /******/ - } - /******/ // Create a new module (and put it into the cache) - /******/ var module = (__webpack_module_cache__[moduleId] = { - /******/ // no module.id needed - /******/ // no module.loaded needed - /******/ exports: {}, - /******/ - }); - /******/ - /******/ // Execute the module function - /******/ __webpack_modules__[moduleId].call( - module.exports, - module, - module.exports, - __webpack_require__, - ); - /******/ - /******/ // Return the exports of the module - /******/ return module.exports; - /******/ - } - /******/ - /************************************************************************/ - /******/ /* webpack/runtime/define property getters */ - /******/ (() => { - /******/ // define getter functions for harmony exports - /******/ __webpack_require__.d = (exports, definition) => { - /******/ for (var key in definition) { - /******/ if ( - __webpack_require__.o(definition, key) && - !__webpack_require__.o(exports, key) - ) { - /******/ Object.defineProperty(exports, key, { - enumerable: true, - get: definition[key], - }); - /******/ - } - /******/ - } - /******/ - }; - /******/ - })(); - /******/ - /******/ /* webpack/runtime/hasOwnProperty shorthand */ - /******/ (() => { - /******/ __webpack_require__.o = (obj, prop) => - Object.prototype.hasOwnProperty.call(obj, prop); - /******/ - })(); - /******/ - /******/ /* webpack/runtime/make namespace object */ - /******/ (() => { - /******/ // define __esModule on exports - /******/ __webpack_require__.r = (exports) => { - /******/ if (typeof Symbol !== "undefined" && Symbol.toStringTag) { - /******/ Object.defineProperty(exports, Symbol.toStringTag, { - value: "Module", - }); - /******/ - } - /******/ Object.defineProperty(exports, "__esModule", { value: true }); - /******/ - }; - /******/ - })(); - /******/ - /************************************************************************/ - var __webpack_exports__ = {}; - /*!***************************!*\ + if (right - left <= n) continue; + + const mid = left + Math.ceil((right - left) / n / 2) * n; + (0,quickselect__WEBPACK_IMPORTED_MODULE_0__["default"])(arr, mid, left, right, compare); + + stack.push(left, mid, mid, right); + } +} + + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +/*!***************************!*\ !*** ./src/demo/index.js ***! \***************************/ - const { TestCanvas } = __webpack_require__( - /*! ./canvas */ "./src/demo/canvas.js", - ); +const { TestCanvas } = __webpack_require__(/*! ./canvas */ "./src/demo/canvas.js"); - const isStressTest = window.location.search.indexOf("?stress") !== -1; - const Test = isStressTest - ? __webpack_require__(/*! ./stress */ "./src/demo/stress.js") - : __webpack_require__(/*! ./tank */ "./src/demo/tank.js"); +const isStressTest = window.location.search.indexOf("?stress") !== -1; +const Test = isStressTest ? __webpack_require__(/*! ./stress */ "./src/demo/stress.js") : __webpack_require__(/*! ./tank */ "./src/demo/tank.js"); - const test = new Test(); - const canvas = new TestCanvas(test); +const test = new Test(); +const canvas = new TestCanvas(test); - document.body.appendChild(canvas.element); +document.body.appendChild(canvas.element); - if (test.start) { - test.start(); - } +if (test.start) { + test.start(); +} - /******/ -})(); +/******/ })() +; \ No newline at end of file diff --git a/docs/demo/index.html b/docs/demo/index.html index ab476592..26b2181b 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -50,7 +50,5 @@ - - - + diff --git a/docs/demo/stress.d.ts b/docs/demo/stress.d.ts index 8aba18da..ab4a022e 100644 --- a/docs/demo/stress.d.ts +++ b/docs/demo/stress.d.ts @@ -1,27 +1,27 @@ export = Stress; declare class Stress { - constructor(count?: number); - size: number; - physics: System; - bodies: any[]; - polygons: number; - boxes: number; - circles: number; - ellipses: number; - lines: number; - lastVariant: number; - count: number; - bounds: import("..").Box[]; - enableFiltering: boolean; - legend: string; - lastTime: number; - updateBody(body: any): void; - start: () => void; - getBounds(): import("..").Box[]; - toggleFiltering(): void; - update(): void; - timeScale: number | undefined; - bounceBody(body: any): void; - createShape(large: any): void; + constructor(count?: number); + size: number; + physics: System; + bodies: any[]; + polygons: number; + boxes: number; + circles: number; + ellipses: number; + lines: number; + lastVariant: number; + count: number; + bounds: import("..").Box[]; + enableFiltering: boolean; + legend: string; + lastTime: number; + updateBody(body: any): void; + start: () => void; + getBounds(): import("..").Box[]; + toggleFiltering(): void; + update(): void; + timeScale: number | undefined; + bounceBody(body: any): void; + createShape(large: any): void; } import { System } from "../system"; diff --git a/docs/demo/stress.js b/docs/demo/stress.js index 01fb8614..6b4a20e2 100644 --- a/docs/demo/stress.js +++ b/docs/demo/stress.js @@ -5,26 +5,26 @@ const { getBounceDirection, groupBits } = require("../utils"); const { width, height, loop } = require("./canvas"); const seededRandom = require("random-seed").create("@Prozi").random; function random(min, max) { - return Math.floor(seededRandom() * max) + min; + return Math.floor(seededRandom() * max) + min; } class Stress { - constructor(count = 2000) { - this.size = Math.sqrt((width * height) / (count * 50)); - this.physics = new System(5); - this.bodies = []; - this.polygons = 0; - this.boxes = 0; - this.circles = 0; - this.ellipses = 0; - this.lines = 0; - this.lastVariant = 0; - this.count = count; - this.bounds = this.getBounds(); - this.enableFiltering = false; - for (let i = 0; i < count; ++i) { - this.createShape(!random(0, 20)); - } - this.legend = `
Total: ${count}
+ constructor(count = 2000) { + this.size = Math.sqrt((width * height) / (count * 50)); + this.physics = new System(5); + this.bodies = []; + this.polygons = 0; + this.boxes = 0; + this.circles = 0; + this.ellipses = 0; + this.lines = 0; + this.lastVariant = 0; + this.count = count; + this.bounds = this.getBounds(); + this.enableFiltering = false; + for (let i = 0; i < count; ++i) { + this.createShape(!random(0, 20)); + } + this.legend = `
Total: ${count}
Polygons: ${this.polygons}
Boxes: ${this.boxes}
Circles: ${this.circles}
@@ -36,200 +36,178 @@ class Stress { `; - this.lastTime = Date.now(); - this.updateBody = this.updateBody.bind(this); - // observer #debug & add filtering checkbox event - const observer = new window.MutationObserver((mutations) => { - mutations.forEach((mutation) => { - mutation.addedNodes.forEach((node) => { - if (node.id == "debug") { - document - .querySelector("#filtering") - .addEventListener("change", () => this.toggleFiltering()); - observer.disconnect(); - } + this.lastTime = Date.now(); + this.updateBody = this.updateBody.bind(this); + // observer #debug & add filtering checkbox event + const observer = new window.MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((node) => { + if (node.id == "debug") { + document + .querySelector("#filtering") + .addEventListener("change", () => this.toggleFiltering()); + observer.disconnect(); + } + }); + }); }); - }); - }); - observer.observe(document.querySelector("body"), { - subtree: false, - childList: true, - }); - this.start = () => { - loop(this.update.bind(this)); - }; - } - getBounds() { - return [ - this.physics.createBox({ x: 0, y: 0 }, width, 10, { - isStatic: true, - }), - this.physics.createBox({ x: width - 10, y: 0 }, 10, height, { - isStatic: true, - }), - this.physics.createBox({ x: 0, y: height - 10 }, width, 10, { - isStatic: true, - }), - this.physics.createBox({ x: 0, y: 0 }, 10, height, { - isStatic: true, - }), - ]; - } - toggleFiltering() { - this.enableFiltering = !this.enableFiltering; - this.physics.clear(); - this.bodies.length = 0; - this.polygons = 0; - this.boxes = 0; - this.circles = 0; - this.ellipses = 0; - this.lines = 0; - this.lastVariant = 0; - this.bounds = this.getBounds(); - for (let i = 0; i < this.count; ++i) { - this.createShape(!random(0, 20)); - } - } - update() { - const now = Date.now(); - this.timeScale = Math.min(1000, now - this.lastTime) / 60; - this.lastTime = now; - this.bodies.forEach(this.updateBody); - } - updateBody(body) { - body.setAngle(body.angle + body.rotationSpeed * this.timeScale, false); - if (seededRandom() < 0.05 * this.timeScale) { - body.targetScale.x = 0.5 + seededRandom(); + observer.observe(document.querySelector("body"), { + subtree: false, + childList: true, + }); + this.start = () => { + loop(this.update.bind(this)); + }; } - if (seededRandom() < 0.05 * this.timeScale) { - body.targetScale.y = 0.5 + seededRandom(); + getBounds() { + return [ + this.physics.createBox({ x: 0, y: 0 }, width, 10, { + isStatic: true, + }), + this.physics.createBox({ x: width - 10, y: 0 }, 10, height, { + isStatic: true, + }), + this.physics.createBox({ x: 0, y: height - 10 }, width, 10, { + isStatic: true, + }), + this.physics.createBox({ x: 0, y: 0 }, 10, height, { + isStatic: true, + }), + ]; } - if (Math.abs(body.targetScale.x - body.scaleX) > 0.01) { - const scaleX = - body.scaleX + - Math.sign(body.targetScale.x - body.scaleX) * 0.02 * this.timeScale; - const scaleY = - body.scaleY + - Math.sign(body.targetScale.y - body.scaleY) * 0.02 * this.timeScale; - body.setScale(scaleX, scaleY, false); + toggleFiltering() { + this.enableFiltering = !this.enableFiltering; + this.physics.clear(); + this.bodies.length = 0; + this.polygons = 0; + this.boxes = 0; + this.circles = 0; + this.ellipses = 0; + this.lines = 0; + this.lastVariant = 0; + this.bounds = this.getBounds(); + for (let i = 0; i < this.count; ++i) { + this.createShape(!random(0, 20)); + } } - // as last step update position, and bounding box - body.setPosition( - body.x + body.directionX * this.timeScale, - body.y + body.directionY * this.timeScale, - ); - // separate + bounce - this.bounceBody(body); - } - bounceBody(body) { - const bounces = { x: 0, y: 0 }; - const addBounces = ({ overlapV: { x, y } }) => { - bounces.x += x; - bounces.y += y; - }; - this.physics.checkOne(body, addBounces); - if (bounces.x || bounces.y) { - const size = 0.5 * (body.scaleX + body.scaleY); - const bounce = getBounceDirection(body, { - x: body.x + bounces.x, - y: body.y + bounces.y, - }); - bounce.scale(body.size).add({ - x: body.directionX * size, - y: body.directionY * size, - }); - const { x, y } = bounce.normalize(); - body.directionX = x; - body.directionY = y; - body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; - body.setPosition(body.x - bounces.x, body.y - bounces.y); + update() { + const now = Date.now(); + this.timeScale = Math.min(1000, now - this.lastTime) / 60; + this.lastTime = now; + this.bodies.forEach(this.updateBody); } - } - createShape(large) { - const minSize = this.size * 1.0 * (large ? seededRandom() + 1 : 1); - const maxSize = this.size * 1.25 * (large ? seededRandom() * 2 + 1 : 1); - const x = random(0, width); - const y = random(0, height); - const direction = (random(0, 360) * Math.PI) / 180; - const options = { - isCentered: true, - padding: (minSize + maxSize) * 0.2, - }; - let body; - let variant = this.lastVariant++ % 5; - switch (variant) { - case 0: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Circle); + updateBody(body) { + body.setAngle(body.angle + body.rotationSpeed * this.timeScale, false); + if (seededRandom() < 0.05 * this.timeScale) { + body.targetScale.x = 0.5 + seededRandom(); } - body = this.physics.createCircle( - { x, y }, - random(minSize, maxSize) / 2, - options, - ); - ++this.circles; - break; - case 1: - const width = random(minSize, maxSize); - const height = random(minSize, maxSize); - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Ellipse); - console.log(); + if (seededRandom() < 0.05 * this.timeScale) { + body.targetScale.y = 0.5 + seededRandom(); } - body = this.physics.createEllipse({ x, y }, width, height, 2, options); - ++this.ellipses; - break; - case 2: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Box); + if (Math.abs(body.targetScale.x - body.scaleX) > 0.01) { + const scaleX = body.scaleX + + Math.sign(body.targetScale.x - body.scaleX) * 0.02 * this.timeScale; + const scaleY = body.scaleY + + Math.sign(body.targetScale.y - body.scaleY) * 0.02 * this.timeScale; + body.setScale(scaleX, scaleY, false); } - body = this.physics.createBox( - { x, y }, - random(minSize, maxSize), - random(minSize, maxSize), - options, - ); - ++this.boxes; - break; - case 3: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Line); + // as last step update position, and bounding box + body.setPosition(body.x + body.directionX * this.timeScale, body.y + body.directionY * this.timeScale); + // separate + bounce + this.bounceBody(body); + } + bounceBody(body) { + const bounces = { x: 0, y: 0 }; + const addBounces = ({ overlapV: { x, y } }) => { + bounces.x += x; + bounces.y += y; + }; + this.physics.checkOne(body, addBounces); + if (bounces.x || bounces.y) { + const size = 0.5 * (body.scaleX + body.scaleY); + const bounce = getBounceDirection(body, { + x: body.x + bounces.x, + y: body.y + bounces.y, + }); + bounce.scale(body.size).add({ + x: body.directionX * size, + y: body.directionY * size, + }); + const { x, y } = bounce.normalize(); + body.directionX = x; + body.directionY = y; + body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; + body.setPosition(body.x - bounces.x, body.y - bounces.y); } - body = this.physics.createLine( - { x, y }, - { - x: x + random(minSize, maxSize), - y: y + random(minSize, maxSize), - }, - options, - ); - ++this.lines; - break; - default: - if (this.enableFiltering) { - options.group = groupBits(BodyGroup.Polygon); + } + createShape(large) { + const minSize = this.size * 1.0 * (large ? seededRandom() + 1 : 1); + const maxSize = this.size * 1.25 * (large ? seededRandom() * 2 + 1 : 1); + const x = random(0, width); + const y = random(0, height); + const direction = (random(0, 360) * Math.PI) / 180; + const options = { + isCentered: true, + padding: (minSize + maxSize) * 0.2, + }; + let body; + let variant = this.lastVariant++ % 5; + switch (variant) { + case 0: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Circle); + } + body = this.physics.createCircle({ x, y }, random(minSize, maxSize) / 2, options); + ++this.circles; + break; + case 1: + const width = random(minSize, maxSize); + const height = random(minSize, maxSize); + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Ellipse); + console.log(); + } + body = this.physics.createEllipse({ x, y }, width, height, 2, options); + ++this.ellipses; + break; + case 2: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Box); + } + body = this.physics.createBox({ x, y }, random(minSize, maxSize), random(minSize, maxSize), options); + ++this.boxes; + break; + case 3: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Line); + } + body = this.physics.createLine({ x, y }, { + x: x + random(minSize, maxSize), + y: y + random(minSize, maxSize), + }, options); + ++this.lines; + break; + default: + if (this.enableFiltering) { + options.group = groupBits(BodyGroup.Polygon); + } + body = this.physics.createPolygon({ x, y }, [ + { x: -random(minSize, maxSize), y: random(minSize, maxSize) }, + { x: random(minSize, maxSize), y: random(minSize, maxSize) }, + { x: random(minSize, maxSize), y: -random(minSize, maxSize) }, + { x: -random(minSize, maxSize), y: -random(minSize, maxSize) }, + ], options); + ++this.polygons; + break; } - body = this.physics.createPolygon( - { x, y }, - [ - { x: -random(minSize, maxSize), y: random(minSize, maxSize) }, - { x: random(minSize, maxSize), y: random(minSize, maxSize) }, - { x: random(minSize, maxSize), y: -random(minSize, maxSize) }, - { x: -random(minSize, maxSize), y: -random(minSize, maxSize) }, - ], - options, - ); - ++this.polygons; - break; + // set initial rotation angle direction + body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; + body.setAngle((random(0, 360) * Math.PI) / 180); + body.targetScale = { x: 1, y: 1 }; + body.size = (minSize + maxSize) / 2; + body.directionX = Math.cos(direction); + body.directionY = Math.sin(direction); + this.bodies.push(body); } - // set initial rotation angle direction - body.rotationSpeed = (seededRandom() - seededRandom()) * 0.1; - body.setAngle((random(0, 360) * Math.PI) / 180); - body.targetScale = { x: 1, y: 1 }; - body.size = (minSize + maxSize) / 2; - body.directionX = Math.cos(direction); - body.directionY = Math.sin(direction); - this.bodies.push(body); - } } module.exports = Stress; diff --git a/docs/enums/BodyGroup.html b/docs/enums/BodyGroup.html index c2785216..f7bd620a 100644 --- a/docs/enums/BodyGroup.html +++ b/docs/enums/BodyGroup.html @@ -1,520 +1,8 @@ - - - - - - BodyGroup | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Enumeration BodyGroup

-
-
-

for groups

-
-
- -
-
-
- - - -
-
-

Enumeration Members

- -
-
-
-
-
-
-

Enumeration Members

-
- - -
- Box: - 4 -
- -
-
- - -
- Circle: - 16 -
- -
-
- - -
- Ellipse: - 32 -
- -
-
- - -
- Line: - 2 -
- -
-
- - -
- Point: - 1 -
- -
-
- - -
- Polygon: - 8 -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +BodyGroup | Detect-Collisions

Enumeration BodyGroup

for groups

+

Enumeration Members

Enumeration Members

Box: 4
Circle: 16
Ellipse: 32
Line: 2
Point: 1
Polygon: 8
diff --git a/docs/enums/BodyType.html b/docs/enums/BodyType.html index 6859d50b..f7dc6464 100644 --- a/docs/enums/BodyType.html +++ b/docs/enums/BodyType.html @@ -1,520 +1,8 @@ - - - - - - BodyType | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Enumeration BodyType

-
-
-

types

-
-
- -
-
-
- - - -
-
-

Enumeration Members

- -
-
-
-
-
-
-

Enumeration Members

-
- - -
- Box: - "Box" -
- -
-
- - -
- Circle: - "Circle" -
- -
-
- - -
- Ellipse: - "Ellipse" -
- -
-
- - -
- Line: - "Line" -
- -
-
- - -
- Point: - "Point" -
- -
-
- - -
- Polygon: - "Polygon" -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +BodyType | Detect-Collisions

Enumeration BodyType

types

+

Enumeration Members

Enumeration Members

Box: "Box"
Circle: "Circle"
Ellipse: "Ellipse"
Line: "Line"
Point: "Point"
Polygon: "Polygon"
diff --git a/docs/functions/bin2dec.html b/docs/functions/bin2dec.html index 3844a633..d2a9545b 100644 --- a/docs/functions/bin2dec.html +++ b/docs/functions/bin2dec.html @@ -1,302 +1,2 @@ - - - - - - bin2dec | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function bin2dec

-
-
-
    - -
  • -
    -

    binary string to decimal number

    -
    -
    -

    Parameters

    -
      -
    • - binary: - string -
    • -
    -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +bin2dec | Detect-Collisions

Function bin2dec

  • binary string to decimal number

    +

    Parameters

    • binary: string

    Returns number

diff --git a/docs/functions/bodyMoved.html b/docs/functions/bodyMoved.html index 610ad618..3152a084 100644 --- a/docs/functions/bodyMoved.html +++ b/docs/functions/bodyMoved.html @@ -1,309 +1,2 @@ - - - - - - bodyMoved | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function bodyMoved

-
-
-
    - -
  • -
    -

    check if body moved outside of its padding

    -
    -
    -

    Parameters

    -
      -
    • - body: - Body -
    • -
    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +bodyMoved | Detect-Collisions

Function bodyMoved

  • check if body moved outside of its padding

    +

    Parameters

    Returns boolean

diff --git a/docs/functions/canInteract.html b/docs/functions/canInteract.html index 5e9c617f..9a36cb72 100644 --- a/docs/functions/canInteract.html +++ b/docs/functions/canInteract.html @@ -1,322 +1,2 @@ - - - - - - canInteract | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function canInteract

-
-
-
    - -
  • -
    -

    - checks if two bodies can interact (for collision filtering) -

    -
    -
    -

    Parameters

    -
      -
    • - bodyA: - Body -
    • -
    • - bodyB: - Body -
    • -
    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +canInteract | Detect-Collisions

Function canInteract

  • checks if two bodies can interact (for collision filtering)

    +

    Parameters

    Returns boolean

diff --git a/docs/functions/checkAInB.html b/docs/functions/checkAInB.html index ddacdb12..f292ac27 100644 --- a/docs/functions/checkAInB.html +++ b/docs/functions/checkAInB.html @@ -1,320 +1,2 @@ - - - - - - checkAInB | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function checkAInB

-
-
-
    - -
  • -
    -

    checks if body a is in body b

    -
    -
    -

    Parameters

    -
      -
    • - bodyA: - Body -
    • -
    • - bodyB: - Body -
    • -
    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +checkAInB | Detect-Collisions

Function checkAInB

  • checks if body a is in body b

    +

    Parameters

    Returns boolean

diff --git a/docs/functions/circleInCircle.html b/docs/functions/circleInCircle.html index 3eeac953..d2812d77 100644 --- a/docs/functions/circleInCircle.html +++ b/docs/functions/circleInCircle.html @@ -1,337 +1,2 @@ - - - - - - circleInCircle | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function circleInCircle

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +circleInCircle | Detect-Collisions

Function circleInCircle

diff --git a/docs/functions/circleInPolygon.html b/docs/functions/circleInPolygon.html index 2c7802e5..3c2bb0cd 100644 --- a/docs/functions/circleInPolygon.html +++ b/docs/functions/circleInPolygon.html @@ -1,331 +1,2 @@ - - - - - - circleInPolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function circleInPolygon

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +circleInPolygon | Detect-Collisions

Function circleInPolygon

diff --git a/docs/functions/circleOutsidePolygon.html b/docs/functions/circleOutsidePolygon.html index 07b377ef..5d50b1f9 100644 --- a/docs/functions/circleOutsidePolygon.html +++ b/docs/functions/circleOutsidePolygon.html @@ -1,333 +1,2 @@ - - - - - - circleOutsidePolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function circleOutsidePolygon

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +circleOutsidePolygon | Detect-Collisions

Function circleOutsidePolygon

diff --git a/docs/functions/clockwise.html b/docs/functions/clockwise.html index 255e08c7..cf137289 100644 --- a/docs/functions/clockwise.html +++ b/docs/functions/clockwise.html @@ -1,309 +1,2 @@ - - - - - - clockwise | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function clockwise

-
-
-
    - -
  • -
    -

    check [is clockwise] direction of polygon

    -
    -
    -

    Parameters

    - -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +clockwise | Detect-Collisions

Function clockwise

  • check [is clockwise] direction of polygon

    +

    Parameters

    Returns boolean

diff --git a/docs/functions/clonePointsArray.html b/docs/functions/clonePointsArray.html index c69bfc64..fbc81330 100644 --- a/docs/functions/clonePointsArray.html +++ b/docs/functions/clonePointsArray.html @@ -1,319 +1,2 @@ - - - - - - clonePointsArray | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function clonePointsArray

-
-
-
    - -
  • -
    -

    clone sat vector points array into vector points array

    -
    -
    -

    Parameters

    - -
    -

    - Returns - Vector[] -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +clonePointsArray | Detect-Collisions

Function clonePointsArray

diff --git a/docs/functions/cloneResponse.html b/docs/functions/cloneResponse.html index 43ad11ae..7b5ac345 100644 --- a/docs/functions/cloneResponse.html +++ b/docs/functions/cloneResponse.html @@ -1,320 +1,2 @@ - - - - - - cloneResponse | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function cloneResponse

-
-
-
    - -
  • -
    -

    - clone response object returning new response with previous - ones values -

    -
    -
    -

    Parameters

    - -
    -

    - Returns - Response -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +cloneResponse | Detect-Collisions

Function cloneResponse

diff --git a/docs/functions/createBox.html b/docs/functions/createBox.html index f8a925e4..3eedb8e2 100644 --- a/docs/functions/createBox.html +++ b/docs/functions/createBox.html @@ -1,321 +1,2 @@ - - - - - - createBox | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function createBox

-
-
-
    - -
  • -
    -

    creates box shaped polygon points

    -
    -
    -

    Parameters

    -
      -
    • - width: - number -
    • -
    • - height: - number -
    • -
    -
    -

    - Returns - SATVector[] -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +createBox | Detect-Collisions

Function createBox

diff --git a/docs/functions/createEllipse.html b/docs/functions/createEllipse.html index 115186a2..5809c327 100644 --- a/docs/functions/createEllipse.html +++ b/docs/functions/createEllipse.html @@ -1,334 +1,2 @@ - - - - - - createEllipse | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function createEllipse

-
-
-
    - -
  • -
    -

    creates ellipse-shaped polygon based on params

    -
    -
    -

    Parameters

    -
      -
    • - radiusX: - number -
    • -
    • - radiusY: - number - = radiusX -
    • -
    • - step: - number = 1 -
    • -
    -
    -

    - Returns - SATVector[] -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +createEllipse | Detect-Collisions

Function createEllipse

  • creates ellipse-shaped polygon based on params

    +

    Parameters

    • radiusX: number
    • radiusY: number = radiusX
    • step: number = 1

    Returns SATVector[]

diff --git a/docs/functions/dashLineTo.html b/docs/functions/dashLineTo.html index 506a1f0c..bcfb5b81 100644 --- a/docs/functions/dashLineTo.html +++ b/docs/functions/dashLineTo.html @@ -1,354 +1,2 @@ - - - - - - dashLineTo | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function dashLineTo

-
-
-
    - -
  • -
    -

    draws dashed line on canvas context

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    • - fromX: - number -
    • -
    • - fromY: - number -
    • -
    • - toX: - number -
    • -
    • - toY: - number -
    • -
    • - dash: - number = 2 -
    • -
    • - gap: - number = 4 -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +dashLineTo | Detect-Collisions

Function dashLineTo

  • draws dashed line on canvas context

    +

    Parameters

    • context: CanvasRenderingContext2D
    • fromX: number
    • fromY: number
    • toX: number
    • toY: number
    • dash: number = 2
    • gap: number = 4

    Returns void

diff --git a/docs/functions/deg2rad-1.html b/docs/functions/deg2rad-1.html index f383017d..e2dedd08 100644 --- a/docs/functions/deg2rad-1.html +++ b/docs/functions/deg2rad-1.html @@ -1,302 +1,2 @@ - - - - - - deg2rad | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function deg2rad

-
-
-
    - -
  • -
    -

    convert from degrees to radians

    -
    -
    -

    Parameters

    -
      -
    • - degrees: - number -
    • -
    -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +deg2rad | Detect-Collisions

Function deg2rad

  • convert from degrees to radians

    +

    Parameters

    • degrees: number

    Returns number

diff --git a/docs/functions/distance.html b/docs/functions/distance.html index 91603a31..991af08d 100644 --- a/docs/functions/distance.html +++ b/docs/functions/distance.html @@ -1,320 +1,2 @@ - - - - - - distance | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function distance

-
-
-
    - -
  • -
    -

    get distance between two Vector points

    -
    -
    -

    Parameters

    - -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +distance | Detect-Collisions

Function distance

  • get distance between two Vector points

    +

    Parameters

    Returns number

diff --git a/docs/functions/drawBVH.html b/docs/functions/drawBVH.html index b75a1d4d..4cc1c6cd 100644 --- a/docs/functions/drawBVH.html +++ b/docs/functions/drawBVH.html @@ -1,315 +1,2 @@ - - - - - - drawBVH | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function drawBVH

-
-
-
    - -
  • -
    -

    draw body bounding body box

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    • - body: - Body -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +drawBVH | Detect-Collisions

Function drawBVH

  • draw body bounding body box

    +

    Parameters

    • context: CanvasRenderingContext2D
    • body: Body

    Returns void

diff --git a/docs/functions/drawPolygon.html b/docs/functions/drawPolygon.html index 6bf429b7..b7740832 100644 --- a/docs/functions/drawPolygon.html +++ b/docs/functions/drawPolygon.html @@ -1,348 +1,2 @@ - - - - - - drawPolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function drawPolygon

-
-
-
    - -
  • -

    draw polygon

    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    • - __namedParameters: Pick<SATPolygon | Polygon, "calcPoints"> & {
          pos: Vector;
      }
      -
    • -
    • - isTrigger: - boolean = false -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +drawPolygon | Detect-Collisions

Function drawPolygon

  • draw polygon

    +

    Parameters

    • context: CanvasRenderingContext2D
    • __namedParameters: Pick<SATPolygon | Polygon, "calcPoints"> & {
          pos: Vector;
      }
    • isTrigger: boolean = false

    Returns void

diff --git a/docs/functions/ensureConvex.html b/docs/functions/ensureConvex.html index 4b9988b9..12203bc2 100644 --- a/docs/functions/ensureConvex.html +++ b/docs/functions/ensureConvex.html @@ -1,370 +1,2 @@ - - - - - - ensureConvex | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function ensureConvex

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +ensureConvex | Detect-Collisions

Function ensureConvex

diff --git a/docs/functions/ensureNumber.html b/docs/functions/ensureNumber.html index c694bd79..02f3293a 100644 --- a/docs/functions/ensureNumber.html +++ b/docs/functions/ensureNumber.html @@ -1,311 +1,3 @@ - - - - - - ensureNumber | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function ensureNumber

-
-
-
    - -
  • -
    -

    helper for groupBits()

    -
    -
    -

    Parameters

    -
      -
    • - input: - string | number -
      -

      number or binary string

      -
      -
      -
    • -
    -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +ensureNumber | Detect-Collisions

Function ensureNumber

  • helper for groupBits()

    +

    Parameters

    • input: string | number

      number or binary string

      +

    Returns number

diff --git a/docs/functions/ensurePolygonPoints.html b/docs/functions/ensurePolygonPoints.html index 135bcff2..bc623da4 100644 --- a/docs/functions/ensurePolygonPoints.html +++ b/docs/functions/ensurePolygonPoints.html @@ -1,323 +1,2 @@ - - - - - - ensurePolygonPoints | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function ensurePolygonPoints

-
-
-
    - -
  • -
    -

    - ensure Vector points (for polygon) in counter-clockwise order -

    -
    -
    -

    Parameters

    - -
    -

    - Returns - SATVector[] -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +ensurePolygonPoints | Detect-Collisions

Function ensurePolygonPoints

diff --git a/docs/functions/ensureVectorPoint.html b/docs/functions/ensureVectorPoint.html index a6b635b0..672edac3 100644 --- a/docs/functions/ensureVectorPoint.html +++ b/docs/functions/ensureVectorPoint.html @@ -1,319 +1,2 @@ - - - - - - ensureVectorPoint | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function ensureVectorPoint

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +ensureVectorPoint | Detect-Collisions

Function ensureVectorPoint

diff --git a/docs/functions/extendBody.html b/docs/functions/extendBody.html index 571ab35d..63664cd5 100644 --- a/docs/functions/extendBody.html +++ b/docs/functions/extendBody.html @@ -1,321 +1,2 @@ - - - - - - extendBody | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function extendBody

-
-
-
    - -
  • -
    -

    used for all types of bodies in constructor

    -
    -
    -

    Parameters

    - -
    -

    - Returns void -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +extendBody | Detect-Collisions

Function extendBody

  • used for all types of bodies in constructor

    +

    Parameters

    Returns void

diff --git a/docs/functions/getBounceDirection.html b/docs/functions/getBounceDirection.html index e2cf0002..fbc140de 100644 --- a/docs/functions/getBounceDirection.html +++ b/docs/functions/getBounceDirection.html @@ -1,332 +1,2 @@ - - - - - - getBounceDirection | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function getBounceDirection

-
-
-
    - -
  • -
    -

    - given 2 bodies calculate vector of bounce assuming equal mass - and they are circles -

    -
    -
    -

    Parameters

    - -
    -

    - Returns - SATVector -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +getBounceDirection | Detect-Collisions

Function getBounceDirection

diff --git a/docs/functions/getGroup.html b/docs/functions/getGroup.html index cc219d86..996a2d5c 100644 --- a/docs/functions/getGroup.html +++ b/docs/functions/getGroup.html @@ -1,303 +1,2 @@ - - - - - - getGroup | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function getGroup

-
-
-
    - -
  • -

    for groups

    -
    -

    Parameters

    -
      -
    • - group: - number -
    • -
    -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +getGroup | Detect-Collisions

Function getGroup

  • for groups

    +

    Parameters

    • group: number

    Returns number

diff --git a/docs/functions/getSATTest.html b/docs/functions/getSATTest.html index d9aab22b..d234c5fc 100644 --- a/docs/functions/getSATTest.html +++ b/docs/functions/getSATTest.html @@ -1,330 +1,2 @@ - - - - - - getSATTest | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function getSATTest

-
-
-
    - -
  • -
    -

    - returns correct sat.js testing function based on body types -

    -
    -
    -

    Parameters

    -
      -
    • - bodyA: - Body -
    • -
    • - bodyB: - Body -
    • -
    -
    -

    - Returns - SATTest -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +getSATTest | Detect-Collisions

Function getSATTest

diff --git a/docs/functions/groupBits.html b/docs/functions/groupBits.html index 28ef1754..ba866ab0 100644 --- a/docs/functions/groupBits.html +++ b/docs/functions/groupBits.html @@ -1,328 +1,4 @@ - - - - - - groupBits | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function groupBits

-
-
-
    - -
  • -
    -

    create group bits from category and mask

    -
    -
    -

    Parameters

    -
      -
    • - category: - string | number -
      -

      category bits

      -
      -
      -
    • -
    • - mask: - string | number - = category -
      -

      mask bits (default: category)

      -
      -
      -
    • -
    -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +groupBits | Detect-Collisions

Function groupBits

  • create group bits from category and mask

    +

    Parameters

    • category: string | number

      category bits

      +
    • mask: string | number = category

      mask bits (default: category)

      +

    Returns number

diff --git a/docs/functions/intersectAABB.html b/docs/functions/intersectAABB.html index d0162dd7..123caf09 100644 --- a/docs/functions/intersectAABB.html +++ b/docs/functions/intersectAABB.html @@ -1,320 +1,2 @@ - - - - - - intersectAABB | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function intersectAABB

-
-
-
    - -
  • -
    -

    checks if two boxes intersect

    -
    -
    -

    Parameters

    -
      -
    • - bodyA: - BBox -
    • -
    • - bodyB: - BBox -
    • -
    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +intersectAABB | Detect-Collisions

Function intersectAABB

  • checks if two boxes intersect

    +

    Parameters

    Returns boolean

diff --git a/docs/functions/intersectLineCircle.html b/docs/functions/intersectLineCircle.html index 0cb7d35f..04c18045 100644 --- a/docs/functions/intersectLineCircle.html +++ b/docs/functions/intersectLineCircle.html @@ -1,346 +1,2 @@ - - - - - - intersectLineCircle | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function intersectLineCircle

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +intersectLineCircle | Detect-Collisions

Function intersectLineCircle

diff --git a/docs/functions/intersectLineLine.html b/docs/functions/intersectLineLine.html index af728e7a..ef484e6b 100644 --- a/docs/functions/intersectLineLine.html +++ b/docs/functions/intersectLineLine.html @@ -1,349 +1,3 @@ - - - - - - intersectLineLine | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function intersectLineLine

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +intersectLineLine | Detect-Collisions

Function intersectLineLine

diff --git a/docs/functions/intersectLineLineFast.html b/docs/functions/intersectLineLineFast.html index 2c89ba89..a58d5603 100644 --- a/docs/functions/intersectLineLineFast.html +++ b/docs/functions/intersectLineLineFast.html @@ -1,340 +1,3 @@ - - - - - - intersectLineLineFast | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function intersectLineLineFast

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +intersectLineLineFast | Detect-Collisions

Function intersectLineLineFast

diff --git a/docs/functions/intersectLinePolygon.html b/docs/functions/intersectLinePolygon.html index d07ab99a..283a0d43 100644 --- a/docs/functions/intersectLinePolygon.html +++ b/docs/functions/intersectLinePolygon.html @@ -1,328 +1 @@ - - - - - - intersectLinePolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function intersectLinePolygon

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +intersectLinePolygon | Detect-Collisions

Function intersectLinePolygon

diff --git a/docs/functions/isSimple.html b/docs/functions/isSimple.html index b02230aa..b9a5b521 100644 --- a/docs/functions/isSimple.html +++ b/docs/functions/isSimple.html @@ -1,302 +1 @@ - - - - - - isSimple | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function isSimple

-
-
-
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns boolean -

    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +isSimple | Detect-Collisions

Function isSimple

  • Parameters

    Returns boolean

diff --git a/docs/functions/mapArrayToVector.html b/docs/functions/mapArrayToVector.html index 63aed5ca..4327a62a 100644 --- a/docs/functions/mapArrayToVector.html +++ b/docs/functions/mapArrayToVector.html @@ -1,320 +1,2 @@ - - - - - - mapArrayToVector | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function mapArrayToVector

-
-
-
    - -
  • -
    -

    change format from poly-decomp to SAT.js

    -
    -
    -

    Parameters

    - -
    -

    - Returns - Vector -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +mapArrayToVector | Detect-Collisions

Function mapArrayToVector

diff --git a/docs/functions/mapVectorToArray.html b/docs/functions/mapVectorToArray.html index 16570837..9b470ccb 100644 --- a/docs/functions/mapVectorToArray.html +++ b/docs/functions/mapVectorToArray.html @@ -1,320 +1,2 @@ - - - - - - mapVectorToArray | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function mapVectorToArray

-
-
-
    - -
  • -
    -

    change format from SAT.js to poly-decomp

    -
    -
    -

    Parameters

    -
      -
    • - __namedParameters: - Vector = ... -
    • -
    -
    -

    - Returns - DecompPoint -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +mapVectorToArray | Detect-Collisions

Function mapVectorToArray

diff --git a/docs/functions/move.html b/docs/functions/move.html new file mode 100644 index 00000000..ecb52ccf --- /dev/null +++ b/docs/functions/move.html @@ -0,0 +1 @@ +move | Detect-Collisions
  • Parameters

    • body: Body
    • speed: number = 1
    • updateNow: boolean = true

    Returns void

diff --git a/docs/functions/notIntersectAABB.html b/docs/functions/notIntersectAABB.html index a87c8874..e5046949 100644 --- a/docs/functions/notIntersectAABB.html +++ b/docs/functions/notIntersectAABB.html @@ -1,321 +1,2 @@ - - - - - - notIntersectAABB | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function notIntersectAABB

-
-
-
    - -
  • -
    -

    returns true if two boxes not intersect

    -
    -
    -

    Parameters

    -
      -
    • - bodyA: - BBox -
    • -
    • - bodyB: - BBox -
    • -
    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +notIntersectAABB | Detect-Collisions

Function notIntersectAABB

  • returns true if two boxes not intersect

    +

    Parameters

    Returns boolean

diff --git a/docs/functions/pointInPolygon.html b/docs/functions/pointInPolygon.html index 99e6afe2..b55f3ab3 100644 --- a/docs/functions/pointInPolygon.html +++ b/docs/functions/pointInPolygon.html @@ -1,317 +1 @@ - - - - - - pointInPolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function pointInPolygon

-
-
-
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns boolean -

    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +pointInPolygon | Detect-Collisions

Function pointInPolygon

diff --git a/docs/functions/pointOnCircle.html b/docs/functions/pointOnCircle.html index 8e99ff9f..5f940d23 100644 --- a/docs/functions/pointOnCircle.html +++ b/docs/functions/pointOnCircle.html @@ -1,331 +1,2 @@ - - - - - - pointOnCircle | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function pointOnCircle

-
-
- -
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +pointOnCircle | Detect-Collisions

Function pointOnCircle

diff --git a/docs/functions/polygonInCircle.html b/docs/functions/polygonInCircle.html index dc5d382a..eb33d31e 100644 --- a/docs/functions/polygonInCircle.html +++ b/docs/functions/polygonInCircle.html @@ -1,323 +1 @@ - - - - - - polygonInCircle | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function polygonInCircle

-
-
-
    - -
  • -
    -

    Parameters

    -
      -
    • - polygon: - Polygon -
    • -
    • - circle: - Pick<Circle, "pos" | "r"> -
    • -
    -
    -

    - Returns boolean -

    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +polygonInCircle | Detect-Collisions

Function polygonInCircle

diff --git a/docs/functions/polygonInPolygon.html b/docs/functions/polygonInPolygon.html index b4047764..8c3a96bb 100644 --- a/docs/functions/polygonInPolygon.html +++ b/docs/functions/polygonInPolygon.html @@ -1,317 +1 @@ - - - - - - polygonInPolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function polygonInPolygon

-
-
-
    - -
  • -
    -

    Parameters

    - -
    -

    - Returns boolean -

    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +polygonInPolygon | Detect-Collisions

Function polygonInPolygon

diff --git a/docs/functions/rad2deg-1.html b/docs/functions/rad2deg-1.html index 71d0a5e0..c6de09d9 100644 --- a/docs/functions/rad2deg-1.html +++ b/docs/functions/rad2deg-1.html @@ -1,302 +1,2 @@ - - - - - - rad2deg | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function rad2deg

-
-
-
    - -
  • -
    -

    convert from radians to degrees

    -
    -
    -

    Parameters

    -
      -
    • - radians: - number -
    • -
    -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +rad2deg | Detect-Collisions

Function rad2deg

  • convert from radians to degrees

    +

    Parameters

    • radians: number

    Returns number

diff --git a/docs/functions/returnTrue.html b/docs/functions/returnTrue.html index f0087423..e1cf41b0 100644 --- a/docs/functions/returnTrue.html +++ b/docs/functions/returnTrue.html @@ -1,293 +1,2 @@ - - - - - - returnTrue | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Function returnTrue

-
-
-
    - -
  • -
    -

    dummy fn used as default, for optimization

    -
    -

    - Returns boolean -

    -
    - -
  • -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +returnTrue | Detect-Collisions

Function returnTrue

  • dummy fn used as default, for optimization

    +

    Returns boolean

diff --git a/docs/hierarchy.html b/docs/hierarchy.html index 6ca17591..2b83448d 100644 --- a/docs/hierarchy.html +++ b/docs/hierarchy.html @@ -1,486 +1 @@ - - - - - - Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-

Detect-Collisions

-

Class Hierarchy

- - - - - -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Detect-Collisions
diff --git a/docs/index.html b/docs/index.html index 1decff2d..0c5c5445 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,647 +1,77 @@ - - - - - - Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-

Detect-Collisions

-
- -

Detect-Collisions

-

- npm version - npm downloads per week - build status -

- -

Introduction

-

- Detect-Collisions is a robust TypeScript library for detecting - collisions among various entities. It employs Bounding Volume - Hierarchy (BVH) and the Separating Axis Theorem (SAT) for efficient - collision detection. Unique features include managing rotation, - scale of bodies, and supporting the decomposition of concave - polygons into convex ones. It optimizes detection with body padding, - making it ideal for gaming, simulations, or projects requiring - advanced collision detection with customization and fast - performance. -

- -

Demos

- - -

Installation

-
$ npm i detect-collisions --save
-
- -

API Documentation

-

- For detailed documentation on the library's API, refer to the - following link: -

-

- Detect-Collisions API Documentation -

- -

Usage

- -

- Step 1: Initialize Collision System -

-

Initialize a unique collision system using Detect-Collisions:

-
const { System } = require("detect-collisions");
const system = new System(); -
- -

- Step 2: Understand Body Attributes -

-

Bodies possess various properties:

-
    -
  • - Position: pos: Vector, - x: number, y: number. -
  • -
  • - Scale: Use - setScale(x: number, y: number) for setting and - scale: Vector for getting scale -
  • -
  • - Rotation: Use - setAngle(radians: number) for setting and - angle: number for getting and - deg2rad(degrees: number) to convert to radians. -
  • -
  • - Offset: Use - setOffset(offset: Vector) for setting and - offset: Vector for getting offset from the body - center. -
  • -
  • - AABB Bounding Box: Use - aabb: BBox for inserted or - getAABBAsBBox(): BBox for non inserted bodies to get - the bounding box. -
  • -
  • - Padding: Use padding: number and set - to nonzero value to reduce costly reinserts on attributes' - change. -
  • -
  • - Collision Filtering: Use - group: number for collision filtering, with a range - within 0x0 ~ 0x7fffffff. -
  • -
  • - Body Options: Use - isStatic: boolean to mark body as non movable and - isTrigger: boolean to set body as ghost. -
  • -
- -

- Step 3: Create and Manage Bodies -

-

Create bodies of various types and manage them:

-
const {
Box,
Circle,
Ellipse,
Line,
Point,
Polygon,
} = require("detect-collisions");

// Example: Create and insert box1 body
const box1 = system.createBox(position, width, height, options);
// Example: Create box2 body
const box2 = new Box(position, width, height, options);
// Example: Insert box2 body
system.insert(box2); -
- -

- Step 4: Manipulate Bodies -

-

Manipulate body attributes and update the collision system:

-
box.setPosition(x, y);
box.setScale(scaleX, scaleY);
box.setAngle(angle);
box.setOffset({ x, y });
system.update(); // Update the system after manipulation
box.group = group; // Immediate effect, no system.update needed -
- -

- Step 5: Collision Detection and Resolution -

-

Detect collisions and respond accordingly:

-
if (system.checkAll()) {
// Do something yourself
}

// Or separate bodies based on isStatic/isTrigger
system.separate(); -
- -

Step 6: Cleaning Up

-

Remove bodies when they're no longer needed:

-
system.remove(body);
-
-

- And that's it! You're now ready to utilize the - Detect-Collisions library in your project. -

- -

- Visual Debugging with Rendering -

-

- To facilitate debugging, Detect-Collisions allows you to visually - represent the collision bodies. By invoking the - draw() method and supplying a 2D context of a - <canvas> element, you can draw all the bodies - within a collision system. -

-
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");

context.strokeStyle = "#FFFFFF";
context.beginPath();
system.draw(context);
context.stroke(); -
-

You can also opt to draw individual bodies.

-
context.strokeStyle = "#FFFFFF";
context.beginPath();
// draw specific body
body.draw(context);
// draw whole system
system.draw(context);
context.stroke(); -
-

- To assess the - Bounding Volume Hierarchy, you can draw the BVH. -

-
context.strokeStyle = "#FFFFFF";
context.beginPath();
// draw specific body bounding box
body.drawBVH(context);
// draw bounding volume hierarchy of the system
system.drawBVH(context);
context.stroke(); -
- -

Raycasting

-

- Detect-Collisions provides the functionality to gather raycast data. - Here's how: -

-
const start = { x: 0, y: 0 };
const end = { x: 0, y: -10 };
const hit = system.raycast(start, end);

if (hit) {
const { point, body } = hit;

console.log({ point, body });
} -
-

- In this example, point is a Vector with - the coordinates of the nearest intersection, and - body is a reference to the closest body. -

- -

- Contributing to the Project -

-

- We welcome contributions! Feel free to open a merge request. When - doing so, please adhere to the following code style guidelines: -

-
    -
  • - Execute the npm run precommit script prior to - submitting your merge request -
  • -
  • - Follow the - conventional commits - standard -
  • -
  • Refrain from using the any type
  • -
- -

- Additional Considerations -

- -

- Why not use a physics engine? -

-

- While physics engines like - Matter-js or - Planck.js are - recommended for projects that need comprehensive physics simulation, - not all projects require such complexity. In fact, using a physics - engine solely for collision detection can lead to unnecessary - overhead and complications due to built-in assumptions (gravity, - velocity, friction, etc.). Detect-Collisions is purpose-built for - efficient and robust collision detection, making it an excellent - choice for projects that primarily require this functionality. It - can also serve as the foundation for a custom physics engine. -

- -

Benchmark

-

- This will provide you with the results of both the insertion test - benchmark and a headless - Stress Demo - benchmark, featuring moving bodies, with increasing amounts in each - step. -

-
$ git clone https://github.com/Prozi/detect-collisions.git
$ cd detect-collisions
$ npm i && npm run build # will build & run tests & run benchmarks -
- -

License

-

MIT

- -

- You can buy me a coffee -

-

- https://paypal.me/jacekpietal -

-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Detect-Collisions

Detect-Collisions

Detect-Collisions

npm version +npm downloads per week +build status

+

Detect-Collisions is a robust TypeScript library for detecting collisions among various entities. It employs Bounding Volume Hierarchy (BVH) and the Separating Axis Theorem (SAT) for efficient collision detection. Unique features include managing rotation, scale of bodies, and supporting the decomposition of concave polygons into convex ones. It optimizes detection with body padding, making it ideal for gaming, simulations, or projects requiring advanced collision detection with customization and fast performance.

+ +
$ npm i detect-collisions --save
+
+ +

For detailed documentation on the library's API, refer to the following link:

+

Detect-Collisions API Documentation

+

Initialize a unique collision system using Detect-Collisions:

+
const { System } = require("detect-collisions");
const system = new System(); +
+ +

Bodies possess various properties:

+
    +
  • Position: pos: Vector, x: number, y: number.
  • +
  • Scale: Use setScale(x: number, y: number) for setting and scale: Vector for getting scale
  • +
  • Rotation: Use setAngle(radians: number) for setting and angle: number for getting and deg2rad(degrees: number) to convert to radians.
  • +
  • Offset: Use setOffset(offset: Vector) for setting and offset: Vector for getting offset from the body center.
  • +
  • AABB Bounding Box: Use aabb: BBox for inserted or getAABBAsBBox(): BBox for non inserted bodies to get the bounding box.
  • +
  • Padding: Use padding: number and set to nonzero value to reduce costly reinserts on attributes' change.
  • +
  • Collision Filtering: Use group: number for collision filtering, with a range within 0x0 ~ 0x7fffffff.
  • +
  • Body Options: Use isStatic: boolean to mark body as non movable and isTrigger: boolean to set body as ghost.
  • +
+

Create bodies of various types and manage them:

+
const {
Box,
Circle,
Ellipse,
Line,
Point,
Polygon,
} = require("detect-collisions");

// Example: Create and insert box1 body
const box1 = system.createBox(position, width, height, options);
// Example: Create box2 body
const box2 = new Box(position, width, height, options);
// Example: Insert box2 body
system.insert(box2); +
+ +

Manipulate body attributes and update the collision system:

+
// if omitted updateNow is true
const updateNow = false;

// teleport
box.setPosition(x, y, updateNow);
box.setScale(scaleX, scaleY, updateNow);
box.setAngle(angle, updateNow);
box.move(1, updateNow);
box.setOffset({ x, y }, updateNow);
console.log(box.dirty); // true

box.updateBody(); // Update the body once, when all manipulations are done
console.log(box.dirty); // false

box.group = group; // Immediate effect, no body/system update needed
console.log(box.dirty); // false +
+ +

Detect collisions and respond accordingly:

+
if (system.checkAll(callback)) {
// Do something yourself
}

if (system.checkOne(body, callback)) {
// Do something yourself
}

// Or separate bodies based on isStatic/isTrigger
system.separate(); +
+ +

Remove bodies when they're no longer needed:

+
system.remove(body);
+
+ +

And that's it! You're now ready to utilize the Detect-Collisions library in your project.

+

To facilitate debugging, Detect-Collisions allows you to visually represent the collision bodies. By invoking the draw() method and supplying a 2D context of a <canvas> element, you can draw all the bodies within a collision system.

+
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");

context.strokeStyle = "#FFFFFF";
context.beginPath();
system.draw(context);
context.stroke(); +
+ +

You can also opt to draw individual bodies.

+
context.strokeStyle = "#FFFFFF";
context.beginPath();
// draw specific body
body.draw(context);
// draw whole system
system.draw(context);
context.stroke(); +
+ +

To assess the Bounding Volume Hierarchy, you can draw the BVH.

+
context.strokeStyle = "#FFFFFF";
context.beginPath();
// draw specific body bounding box
body.drawBVH(context);
// draw bounding volume hierarchy of the system
system.drawBVH(context);
context.stroke(); +
+ +

Detect-Collisions provides the functionality to gather raycast data. Here's how:

+
const start = { x: 0, y: 0 };
const end = { x: 0, y: -10 };
const hit = system.raycast(start, end);

if (hit) {
const { point, body } = hit;

console.log({ point, body });
} +
+ +

In this example, point is a Vector with the coordinates of the nearest intersection, and body is a reference to the closest body.

+

We welcome contributions! Feel free to open a merge request. When doing so, please adhere to the following code style guidelines:

+
    +
  • Execute the npm run precommit script prior to submitting your merge request
  • +
  • Follow the conventional commits standard
  • +
  • Refrain from using the any type
  • +
+

While physics engines like Matter-js or Planck.js are recommended for projects that need comprehensive physics simulation, not all projects require such complexity. In fact, using a physics engine solely for collision detection can lead to unnecessary overhead and complications due to built-in assumptions (gravity, velocity, friction, etc.). Detect-Collisions is purpose-built for efficient and robust collision detection, making it an excellent choice for projects that primarily require this functionality. It can also serve as the foundation for a custom physics engine.

+

This will provide you with the results of both the insertion test benchmark and a headless Stress Demo benchmark, featuring moving bodies, with increasing amounts in each step.

+
$ git clone https://github.com/Prozi/detect-collisions.git
$ cd detect-collisions
$ npm i && npm run build # will build & run tests & run benchmarks +
+ +

MIT

+

https://paypal.me/jacekpietal

+
diff --git a/docs/interfaces/BBox.html b/docs/interfaces/BBox.html index e77ab18d..5f8ee2fc 100644 --- a/docs/interfaces/BBox.html +++ b/docs/interfaces/BBox.html @@ -1,482 +1,5 @@ - - - - - - BBox | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface BBox

-
-
- interface BBox - {
    maxX: number;
    maxY: number;
    minX: number;
    minY: number;
} -
-
-

Implemented by

- -
- -
-
-
- - - -
-
-

Properties

- -
-
-
-
-
-
-

Properties

-
- - -
- maxX: - number -
- -
-
- - -
- maxY: - number -
- -
-
- - -
- minX: - number -
- -
-
- - -
- minY: - number -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +BBox | Detect-Collisions

Interface BBox

interface BBox {
    maxX: number;
    maxY: number;
    minX: number;
    minY: number;
}

Implemented by

Properties

Properties

maxX: number
maxY: number
minX: number
minY: number
diff --git a/docs/interfaces/BodyOptions.html b/docs/interfaces/BodyOptions.html index 64d3df11..33ac2ddc 100644 --- a/docs/interfaces/BodyOptions.html +++ b/docs/interfaces/BodyOptions.html @@ -1,599 +1,14 @@ - - - - - - BodyOptions | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface BodyOptions

-
-
-
-

BodyOptions for body creation

-
-
-
-
- interface BodyOptions - {
    angle?: number;
    group?: number;
    isCentered?: boolean;
    isStatic?: boolean;
    isTrigger?: boolean;
    padding?: number;
} -
- -
-
-
- - - - -
-
-
-
-

Properties

-
- - -
- angle?: - number -
-
-

body angle in radians use deg2rad to convert

-
-
- -
-
- - -
- group?: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- isCentered?: - boolean -
-
-

is body offset centered for rotation purpouses

-
-
- -
-
- - -
- isStatic?: - boolean -
-
-

system.separate() doesn't move this body

-
-
- -
-
- - -
- isTrigger?: - boolean -
-
-

- system.separate() doesn't trigger collision of this body -

-
-
- -
-
- - -
- padding?: - number -
-
-

BHV padding for bounding box, preventing costly updates

-
-
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +BodyOptions | Detect-Collisions

Interface BodyOptions

BodyOptions for body creation

+
interface BodyOptions {
    angle?: number;
    group?: number;
    isCentered?: boolean;
    isStatic?: boolean;
    isTrigger?: boolean;
    padding?: number;
}

Properties

angle?: number

body angle in radians use deg2rad to convert

+
group?: number

group for collision filtering

+
isCentered?: boolean

is body offset centered for rotation purpouses

+
isStatic?: boolean

system.separate() doesn't move this body

+
isTrigger?: boolean

system.separate() doesn't trigger collision of this body

+
padding?: number

BHV padding for bounding box, preventing costly updates

+
diff --git a/docs/interfaces/BodyProps.html b/docs/interfaces/BodyProps.html index 75f80e25..7af599fc 100644 --- a/docs/interfaces/BodyProps.html +++ b/docs/interfaces/BodyProps.html @@ -1,1860 +1,48 @@ - - - - - - BodyProps | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface BodyProps

-
-
-
-

each body contains those regardless of type

-
-
-
-
- interface BodyProps - {
    angle: number;
    bbox: BBox;
    dirty: boolean;
    group: number;
    isCentered: boolean;
    isConvex: boolean;
    isStatic: boolean;
    isTrigger: boolean;
    offset: SATVector;
    padding: number;
    system?: System<Body>;
    type: BodyType;
    typeGroup: BodyGroup;
    get scaleX(): number;
    get scaleY(): number;
    draw(context): void;
    drawBVH(context): void;
    getAABBAsBBox(): BBox;
    setAngle(angle, - update?): SATPolygon | Circle;
    setOffset(offset, - update?): SATPolygon | Circle;
    setPosition(x, - y, - update?): SATPolygon | Circle;
    setScale(x, - y, - update?): SATPolygon | Circle;
} -
-
-

Hierarchy

- -
-
-

Implemented by

- -
- -
-
-
- - - - -
-
-
-
-

Properties

-
- - -
- angle: - number -
-
-

body angle in radians use deg2rad to convert

-
-
- -
-
- - -
- bbox: - BBox -
-
-

bounding box cache, without padding

-
-
- -
-
- - -
- dirty: - boolean -
-
-

- was the body modified and needs update in the next - checkCollision -

-
-
- -
-
- - -
- group: - number -
-
-

group for collision filtering

-
-
- -
-
- - -
- isCentered: - boolean -
-
-

is body offset centered for rotation purpouses

-
-
- -
-
- - -
- isConvex: - boolean -
-
-

flag to show is it a convex body or non convex polygon

-
-
- -
-
- - -
- isStatic: - boolean -
-
-

system.separate() doesn't move this body

-
-
- -
-
- - -
- isTrigger: - boolean -
-
-

- system.separate() doesn't trigger collision of this body -

-
-
- -
-
- - -
- offset: - SATVector -
-
-

each body may have offset from center

-
-
- -
-
- - -
- padding: - number -
-
-

BHV padding for bounding box, preventing costly updates

-
-
- -
-
- - -
- system?: - System<Body> -
-
-

collisions system reference

-
-
- -
-
- - -
- type: - BodyType -
-

type of body

-
- -
-
- - -
- typeGroup: - BodyGroup -
-
-

faster for comparision, inner, type of body as number

-
-
- -
-
-
-

Accessors

-
- - -
    -
  • - get scaleX(): number -
  • -
  • -
    -

    scale getter (x)

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
- - -
    -
  • - get scaleY(): number -
  • -
  • -
    -

    scale getter (y = x for Circle)

    -
    -

    - Returns number -

    -
    - -
  • -
-
-
-
-

Methods

-
- - -
    - -
  • -
    -

    draw the collider

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    draw the bounding box

    -
    -
    -

    Parameters

    -
      -
    • - context: - CanvasRenderingContext2D -
    • -
    -
    -

    - Returns void -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    return bounding box without padding

    -
    -

    - Returns - BBox -

    -
    - -
  • -
-
-
- - - -
-
- - - -
-
- - -
    - -
  • -
    -

    update position, and cached convexes positions

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    • - y: - number -
    • -
    • - Optional - update: - boolean -
    • -
    -
    -

    - Returns - SATPolygon | Circle -

    -
    - -
  • -
-
-
- - -
    - -
  • -
    -

    for setting scale

    -
    -
    -

    Parameters

    -
      -
    • - x: - number -
    • -
    • - y: - number -
    • -
    • - Optional - update: - boolean -
    • -
    -
    -

    - Returns - SATPolygon | Circle -

    -
    - -
  • -
-
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +BodyProps | Detect-Collisions

Interface BodyProps

each body contains those regardless of type

+
interface BodyProps {
    angle: number;
    bbox: BBox;
    dirty: boolean;
    group: number;
    isCentered: boolean;
    isConvex: boolean;
    isStatic: boolean;
    isTrigger: boolean;
    offset: SATVector;
    padding: number;
    system?: System<Body>;
    type: BodyType;
    typeGroup: BodyGroup;
    get scaleX(): number;
    get scaleY(): number;
    draw(context: CanvasRenderingContext2D): void;
    drawBVH(context: CanvasRenderingContext2D): void;
    getAABBAsBBox(): BBox;
    move(speed: number, updateNow?: boolean): SATPolygon | Circle;
    setAngle(angle: number, updateNow?: boolean): SATPolygon | Circle;
    setOffset(offset: Vector, updateNow?: boolean): SATPolygon | Circle;
    setPosition(x: number, y: number, updateNow?: boolean): SATPolygon | Circle;
    setScale(x: number, y: number, updateNow?: boolean): SATPolygon | Circle;
}

Hierarchy

Implemented by

Properties

angle: number

body angle in radians use deg2rad to convert

+
bbox: BBox

bounding box cache, without padding

+
dirty: boolean

was the body modified and needs update in the next checkCollision

+
group: number

group for collision filtering

+
isCentered: boolean

is body offset centered for rotation purpouses

+
isConvex: boolean

flag to show is it a convex body or non convex polygon

+
isStatic: boolean

system.separate() doesn't move this body

+
isTrigger: boolean

system.separate() doesn't trigger collision of this body

+
offset: SATVector

each body may have offset from center

+
padding: number

BHV padding for bounding box, preventing costly updates

+
system?: System<Body>

collisions system reference

+
type: BodyType

type of body

+
typeGroup: BodyGroup

faster for comparision, inner, type of body as number

+

Accessors

  • get scaleY(): number
  • scale getter (y = x for Circle)

    +

    Returns number

Methods

  • draw the collider

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • draw the bounding box

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

diff --git a/docs/interfaces/ChildrenData.html b/docs/interfaces/ChildrenData.html index 7a7e7543..9867ae7e 100644 --- a/docs/interfaces/ChildrenData.html +++ b/docs/interfaces/ChildrenData.html @@ -1,404 +1,3 @@ - - - - - - ChildrenData | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface ChildrenData<TBody>

-
-
-

rbush data

-
-
-
- interface ChildrenData<TBody> - {
    children: Leaf<TBody>[];
} -
-
-

Type Parameters

-
    -
  • - TBody extends Body -
  • -
-
- -
-
-
- - - -
-
-

Properties

- -
-
-
-
-
-
-

Properties

-
- - -
- children: - Leaf<TBody>[] -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +ChildrenData | Detect-Collisions

Interface ChildrenData<TBody>

rbush data

+
interface ChildrenData<TBody> {
    children: Leaf<TBody>[];
}

Type Parameters

Properties

Properties

children: Leaf<TBody>[]
diff --git a/docs/interfaces/Data.html b/docs/interfaces/Data.html index 5fb1374e..48f54154 100644 --- a/docs/interfaces/Data.html +++ b/docs/interfaces/Data.html @@ -1,400 +1,3 @@ - - - - - - Data | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface Data<TBody>

-
-
-
-

for use of private function of sat.js

-
-
-
-
- interface Data<TBody> - {
    data: ChildrenData<TBody>;
} -
-
-

Type Parameters

-
    -
  • - TBody extends Body -
  • -
-
- -
-
-
- - - -
-
-

Properties

-
- - data -
-
-
-
-
-
-
-

Properties

-
- - -
- data: - ChildrenData<TBody> -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Data | Detect-Collisions

Interface Data<TBody>

for use of private function of sat.js

+
interface Data<TBody> {
    data: ChildrenData<TBody>;
}

Type Parameters

Properties

Properties

diff --git a/docs/interfaces/GetAABBAsBox.html b/docs/interfaces/GetAABBAsBox.html index 888b3470..528f863b 100644 --- a/docs/interfaces/GetAABBAsBox.html +++ b/docs/interfaces/GetAABBAsBox.html @@ -1,471 +1,3 @@ - - - - - - GetAABBAsBox | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface GetAABBAsBox

-
-
-
-

for use of private function of sat.js

-
-
-
-
- interface GetAABBAsBox - {
    getAABBAsBox(): {
        h: number;
        pos: Vector;
        w: number;
    };
} -
- -
-
-
- - - -
-
-

Methods

- -
-
-
-
-
-
-

Methods

-
- - -
    - -
  • -

    - Returns {
        h: number;
        pos: Vector;
        w: number;
    } -

    -
      -
    • -
      - h: number -
      -
    • -
    • -
      - pos: Vector -
      -
    • -
    • -
      - w: number -
      -
    • -
    - -
  • -
-
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +GetAABBAsBox | Detect-Collisions

Interface GetAABBAsBox

for use of private function of sat.js

+
interface GetAABBAsBox {
    getAABBAsBox(): {
        h: number;
        pos: Vector;
        w: number;
    };
}

Methods

Methods

  • Returns {
        h: number;
        pos: Vector;
        w: number;
    }

diff --git a/docs/interfaces/PotentialVector.html b/docs/interfaces/PotentialVector.html index 5c32809a..2e826533 100644 --- a/docs/interfaces/PotentialVector.html +++ b/docs/interfaces/PotentialVector.html @@ -1,419 +1,4 @@ - - - - - - PotentialVector | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface PotentialVector

-
-
-

potential vector

-
-
-
- interface PotentialVector - {
    x?: number;
    y?: number;
} -
-
-

- Hierarchy (view full) -

-
    -
  • - PotentialVector - -
  • -
-
- -
-
-
- - - -
-
-

Properties

-
- - x? - - y? -
-
-
-
-
-
-
-

Properties

-
- - -
- x?: - number -
- -
-
- - -
- y?: - number -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +PotentialVector | Detect-Collisions

Interface PotentialVector

potential vector

+
interface PotentialVector {
    x?: number;
    y?: number;
}

Hierarchy (view full)

Properties

x? +y? +

Properties

x?: number
y?: number
diff --git a/docs/interfaces/RaycastHit.html b/docs/interfaces/RaycastHit.html index bc4f23df..6f1d122f 100644 --- a/docs/interfaces/RaycastHit.html +++ b/docs/interfaces/RaycastHit.html @@ -1,427 +1,4 @@ - - - - - - RaycastHit | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface RaycastHit<TBody>

-
-
-
-

system.raycast(from, to) result

-
-
-
-
- interface RaycastHit<TBody> - {
    body: TBody;
    point: Vector;
} -
-
-

Type Parameters

-
    -
  • - TBody -
  • -
-
- -
-
-
- - - -
-
-

Properties

- -
-
-
-
-
-
-

Properties

-
- - -
- body: - TBody -
- -
-
- - -
- point: - Vector -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +RaycastHit | Detect-Collisions

Interface RaycastHit<TBody>

system.raycast(from, to) result

+
interface RaycastHit<TBody> {
    body: TBody;
    point: Vector;
}

Type Parameters

  • TBody

Properties

Properties

body: TBody
point: Vector
diff --git a/docs/interfaces/Vector.html b/docs/interfaces/Vector.html index d4bad8c1..988ce9d8 100644 --- a/docs/interfaces/Vector.html +++ b/docs/interfaces/Vector.html @@ -1,427 +1,4 @@ - - - - - - Vector | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Interface Vector

-
-
-

x, y vector

-
-
-
- interface Vector - {
    x: number;
    y: number;
} -
-
-

- Hierarchy (view full) -

- -
- -
-
-
- - - -
-
-

Properties

-
- - x - - y -
-
-
-
-
-
-
-

Properties

-
- - -
- x: - number -
- -
-
- - -
- y: - number -
- -
-
-
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Vector | Detect-Collisions

Interface Vector

x, y vector

+
interface Vector {
    x: number;
    y: number;
}

Hierarchy (view full)

Properties

x +y +

Properties

x: number
y: number
diff --git a/docs/modules.html b/docs/modules.html index 60264e4e..bdcc23aa 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -1,687 +1,76 @@ - - - - - - Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
- -
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Detect-Collisions
diff --git a/docs/types/Body.html b/docs/types/Body.html index 5b8aa509..a595a0d5 100644 --- a/docs/types/Body.html +++ b/docs/types/Body.html @@ -1,303 +1,2 @@ - - - - - - Body | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias Body

-
-
- Body: - Point | Line | Ellipse | Circle | Box | Polygon -
-
-

generic body union type

-
-
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Body | Detect-Collisions

Type Alias Body

Body:
    | Point
    | Line
    | Ellipse
    | Circle
    | Box
    | Polygon

generic body union type

+
diff --git a/docs/types/CollisionCallback.html b/docs/types/CollisionCallback.html index 223df31c..6e1e5996 100644 --- a/docs/types/CollisionCallback.html +++ b/docs/types/CollisionCallback.html @@ -1,318 +1 @@ - - - - - - CollisionCallback | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias CollisionCallback

-
-
- CollisionCallback: - ((response) => boolean | void) -
-
-

Type declaration

-
    -
  • -
      -
    • - (response): boolean | void -
    • -
    • -
      -

      Parameters

      - -
      -

      - Returns boolean | void -

      -
    • -
    -
  • -
-
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +CollisionCallback | Detect-Collisions

Type Alias CollisionCallback

CollisionCallback: ((response: Response) => boolean | void)
diff --git a/docs/types/DecompPoint.html b/docs/types/DecompPoint.html index 54b332f4..79470547 100644 --- a/docs/types/DecompPoint.html +++ b/docs/types/DecompPoint.html @@ -1,271 +1 @@ - - - - - - DecompPoint | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias DecompPoint

-
-
- DecompPoint: - [number, number] -
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +DecompPoint | Detect-Collisions

Type Alias DecompPoint

DecompPoint: [number, number]
diff --git a/docs/types/DecompPolygon.html b/docs/types/DecompPolygon.html index c0583a35..d529dad7 100644 --- a/docs/types/DecompPolygon.html +++ b/docs/types/DecompPolygon.html @@ -1,271 +1 @@ - - - - - - DecompPolygon | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias DecompPolygon

-
-
- DecompPolygon: - DecompPoint[] -
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +DecompPolygon | Detect-Collisions

Type Alias DecompPolygon

DecompPolygon: DecompPoint[]
diff --git a/docs/types/InTest.html b/docs/types/InTest.html index 3b9e6ae4..72dab34a 100644 --- a/docs/types/InTest.html +++ b/docs/types/InTest.html @@ -1,353 +1 @@ - - - - - - InTest | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias InTest<TBody>

-
-
- InTest<TBody>: - ((bodyA, - bodyB) => boolean) -
-
-

Type Parameters

- -
-
-

Type declaration

-
    -
  • -
      -
    • - (bodyA, - bodyB): boolean -
    • -
    • -
      -

      Parameters

      - -
      -

      - Returns boolean -

      -
    • -
    -
  • -
-
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +InTest | Detect-Collisions

Type Alias InTest<TBody>

InTest<TBody>: ((bodyA: TBody, bodyB: TBody) => boolean)

Type Parameters

diff --git a/docs/types/Leaf.html b/docs/types/Leaf.html index 86570387..d413b82b 100644 --- a/docs/types/Leaf.html +++ b/docs/types/Leaf.html @@ -1,340 +1,2 @@ - - - - - - Leaf | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias Leaf<TBody>

-
-
- Leaf<TBody>: - TBody & {
    children?: Leaf<TBody>[];
} -
-
-

body with children (rbush)

-
-
-

Type Parameters

-
    -
  • - TBody extends Body -
  • -
-
-
-

Type declaration

-
    -
  • -
    - Optional - children?: Leaf<TBody>[] -
    -
  • -
-
-
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +Leaf | Detect-Collisions

Type Alias Leaf<TBody>

Leaf<TBody>: TBody & {
    children?: Leaf<TBody>[];
}

body with children (rbush)

+

Type Parameters

diff --git a/docs/types/SATTest.html b/docs/types/SATTest.html index 8f431719..121df377 100644 --- a/docs/types/SATTest.html +++ b/docs/types/SATTest.html @@ -1,398 +1 @@ - - - - - - SATTest | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias SATTest<T, Y>

-
-
- SATTest<T, Y>: - ((bodyA, - bodyB, - response) => boolean) -
-
-

Type Parameters

- -
-
-

Type declaration

-
    -
  • -
      -
    • - (bodyA, - bodyB, - response): boolean -
    • -
    • -
      -

      Parameters

      -
        -
      • - bodyA: - T -
      • -
      • - bodyB: - Y -
      • -
      • - response: - Response -
      • -
      -
      -

      - Returns boolean -

      -
    • -
    -
  • -
-
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +SATTest | Detect-Collisions

Type Alias SATTest<T, Y>

SATTest<T, Y>: ((bodyA: T, bodyB: Y, response: Response) => boolean)

Type Parameters

diff --git a/docs/types/TraverseFunction.html b/docs/types/TraverseFunction.html index 1823b0ac..d17f1315 100644 --- a/docs/types/TraverseFunction.html +++ b/docs/types/TraverseFunction.html @@ -1,378 +1 @@ - - - - - - TraverseFunction | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

Type alias TraverseFunction<TBody>

-
-
- TraverseFunction<TBody>: - ((child, - children, - index) => boolean | void) -
-
-

Type Parameters

- -
-
-

Type declaration

-
    -
  • -
      -
    • - (child, - children, - index): boolean | void -
    • -
    • -
      -

      Parameters

      - -
      -

      - Returns boolean | void -

      -
    • -
    -
  • -
-
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +TraverseFunction | Detect-Collisions

Type Alias TraverseFunction<TBody>

TraverseFunction<TBody>: ((child: Leaf<TBody>, children: Leaf<TBody>[], index: number) => boolean | void)

Type Parameters

diff --git a/docs/variables/DEG2RAD.html b/docs/variables/DEG2RAD.html index 25b1a322..a3a1d306 100644 --- a/docs/variables/DEG2RAD.html +++ b/docs/variables/DEG2RAD.html @@ -1,273 +1 @@ - - - - - - DEG2RAD | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

- Variable DEG2RADConst -

-
-
- DEG2RAD: - number = ... -
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +DEG2RAD | Detect-Collisions

Variable DEG2RADConst

DEG2RAD: number = ...
diff --git a/docs/variables/RAD2DEG.html b/docs/variables/RAD2DEG.html index 4ab4dfff..9580a2a4 100644 --- a/docs/variables/RAD2DEG.html +++ b/docs/variables/RAD2DEG.html @@ -1,273 +1 @@ - - - - - - RAD2DEG | Detect-Collisions - - - - - - - - - - - - -
-
- -
- - -
-
-
-
-
-
- -

- Variable RAD2DEGConst -

-
-
- RAD2DEG: - number = ... -
- -
-
- - -
-
-
-

- Generated using - TypeDoc -

-
-
- - +RAD2DEG | Detect-Collisions

Variable RAD2DEGConst

RAD2DEG: number = ...
diff --git a/jest.config.js b/jest.config.js index 3abcbd94..49c1207c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,4 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { - preset: "ts-jest", - testEnvironment: "node", + preset: "ts-jest/presets/js-with-ts-esm", }; diff --git a/package.json b/package.json index 50cd3efb..4f977ea3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "detect-collisions", - "version": "9.8.1", + "version": "9.9.0", "description": "detecting collisions between bodies: Points, Lines, Boxes, Polygons, Ellipses, Circles. RayCasting. Bodies have offset, rotation, scale, bbox padding, be static (non moving), be trigger bodies (non colliding).", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -8,26 +8,26 @@ "start": "chef-express dist/demo --debug", "test": "jest --silent --verbose --forceExit", "dev": "webpack serve --port 4200", - "update": "ncu -u && yarn add typescript@^4 -D", "amend": "npm run precommit;git commit -a --am --no-edit", - "prebuild": "rimraf dist", + "prebuild": "rm -rf dist", "build": "tsc", "postbuild": "npm run test && npm run build:docs && npm run build:demo && npm run format && npm run benchmark", "build:docs": "typedoc --customCss typedoc.css", "postbuild:docs": "npm run docs-from-master || echo ok", "build:demo": "webpack", "postbuild:demo": "cp -r dist/demo docs", - "prebuild:docs": "rimraf docs", + "prebuild:docs": "rm -rf docs", "docs": "npm run build:docs && chef-express docs --debug", - "docs-from-master": "find docs -type f -name '*.html' -exec sed -i '' -r 's_/blob/[^/]+/_/blob/master/_g' {} +", + "docs-from-master-macos": "find docs -type f -name '*.html' -exec sed -i '' -r 's_/blob/[^/]+/_/blob/master/_g' {} +", + "docs-from-master-linux": "find docs -type f -name '*.html' -exec sed -i -r 's_/blob/[^/]+/_/blob/master/_g' {} +", + "docs-from-master": "npm run docs-from-master-macos || npm run docs-from-master-linux", "demo": "npm run build:demo && npm start", "precommit": "npm run lint && npm run build", "lint": "tslint --project tsconfig.json 'src/**/*.ts' --fix", "format": "prettier --write {src,docs,*.*}", "benchmark": "npm run benchmark-insertion && npm run benchmark-stress", - "benchmark-stress": "node -r pixi-shim -e 'require(`./dist/benchmarks`).stressBenchmark()'", - "benchmark-insertion": "node -e 'require(`./dist/benchmarks`).insertionBenchmark()'", - "downgrade": "yarn add typescript@^4 -D" + "benchmark-stress": "node -r pixi-shim -e 'import(\"./dist/benchmarks/index.js\").then(({ stressBenchmark }) => stressBenchmark());'", + "benchmark-insertion": "node -r pixi-shim -e 'import(\"./dist/benchmarks/index.js\").then(({ insertionBenchmark }) => insertionBenchmark());'" }, "repository": "git://github.com/Prozi/detect-collisions.git", "files": [ @@ -65,30 +65,31 @@ "@types/rbush": "^3.0.3", "@types/sat": "^0.0.35", "poly-decomp-es": "^0.4.2", - "rbush": "^3.0.1", + "rbush": "^4.0.0", "sat": "^0.9.0" }, "devDependencies": { - "@types/node": "^20.12.12", + "@types/node": "^20.14.10", "chef-express": "^2.1.4", "html-webpack-plugin": "^5.6.0", "husky": "^9.0.11", "jest": "^29.7.0", "pixi-shim": "^2.5.3", - "prettier": "^3.2.5", + "prettier": "^3.3.3", "random-seed": "^0.3.0", - "rimraf": "^5.0.7", "tinybench": "^2.8.0", - "ts-jest": "^29.1.3", + "ts-jest": "^29.2.2", "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", "tslint": "^6.1.3", - "typedoc": "^0.25.13", - "typescript": "^4", - "webpack": "^5.91.0", + "typedoc": "^0.26.4", + "typescript": "^5", + "webpack": "^5.93.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" }, "resolutions": { + "canvas": "2.11.2", "minimist": "^1.2.6", "terser": "^5.14.2", "json5": "^2.2.2", diff --git a/src/base-system.ts b/src/base-system.ts index 4b3dbbc8..cc1c884f 100644 --- a/src/base-system.ts +++ b/src/base-system.ts @@ -1,9 +1,3 @@ -import { Box } from "./bodies/box"; -import { Circle } from "./bodies/circle"; -import { Ellipse } from "./bodies/ellipse"; -import { Line } from "./bodies/line"; -import { Point } from "./bodies/point"; -import { Polygon } from "./bodies/polygon"; import { Body, BodyOptions, @@ -14,40 +8,46 @@ import { PotentialVector, RBush, TraverseFunction, - Vector, -} from "./model"; -import { filter, forEach } from "./optimized"; -import { bodyMoved, drawBVH } from "./utils"; + Vector +} from "./model" +import { bodyMoved, drawBVH } from "./utils" +import { filter, forEach } from "./optimized" + +import { Box } from "./bodies/box" +import { Circle } from "./bodies/circle" +import { Ellipse } from "./bodies/ellipse" +import { Line } from "./bodies/line" +import { Point } from "./bodies/point" +import { Polygon } from "./bodies/polygon" /** * very base collision system (create, insert, update, draw, remove) */ export class BaseSystem - extends RBush - implements Data -{ - data!: ChildrenData; + extends RBush + implements Data { + data!: ChildrenData /** * create point at position with options and add to system */ createPoint(position: PotentialVector, options?: BodyOptions): Point { - const point = new Point(position, options); + const point = new Point(position, options) - this.insert(point as TBody); + this.insert(point as TBody) - return point; + return point } /** * create line at position with options and add to system */ createLine(start: Vector, end: Vector, options?: BodyOptions): Line { - const line = new Line(start, end, options); + const line = new Line(start, end, options) - this.insert(line as TBody); + this.insert(line as TBody) - return line; + return line } /** @@ -56,13 +56,13 @@ export class BaseSystem createCircle( position: PotentialVector, radius: number, - options?: BodyOptions, + options?: BodyOptions ): Circle { - const circle = new Circle(position, radius, options); + const circle = new Circle(position, radius, options) - this.insert(circle as TBody); + this.insert(circle as TBody) - return circle; + return circle } /** @@ -72,13 +72,13 @@ export class BaseSystem position: PotentialVector, width: number, height: number, - options?: BodyOptions, + options?: BodyOptions ): Box { - const box = new Box(position, width, height, options); + const box = new Box(position, width, height, options) - this.insert(box as TBody); + this.insert(box as TBody) - return box; + return box } /** @@ -89,13 +89,13 @@ export class BaseSystem radiusX: number, radiusY: number = radiusX, step?: number, - options?: BodyOptions, + options?: BodyOptions ): Ellipse { - const ellipse = new Ellipse(position, radiusX, radiusY, step, options); + const ellipse = new Ellipse(position, radiusX, radiusY, step, options) - this.insert(ellipse as TBody); + this.insert(ellipse as TBody) - return ellipse; + return ellipse } /** @@ -104,47 +104,47 @@ export class BaseSystem createPolygon( position: PotentialVector, points: PotentialVector[], - options?: BodyOptions, + options?: BodyOptions ): Polygon { - const polygon = new Polygon(position, points, options); + const polygon = new Polygon(position, points, options) - this.insert(polygon as TBody); + this.insert(polygon as TBody) - return polygon; + return polygon } /** * re-insert body into collision tree and update its bbox * every body can be part of only one system */ - insert(body: TBody): RBush { - body.bbox = body.getAABBAsBBox(); + insert(body: TBody): this { + body.bbox = body.getAABBAsBBox() if (body.system) { // allow end if body inserted and not moved if (!bodyMoved(body)) { - return this; + return this } // old bounding box *needs* to be removed - body.system.remove(body); + body.system.remove(body) } // only then we update min, max - body.minX = body.bbox.minX - body.padding; - body.minY = body.bbox.minY - body.padding; - body.maxX = body.bbox.maxX + body.padding; - body.maxY = body.bbox.maxY + body.padding; + body.minX = body.bbox.minX - body.padding + body.minY = body.bbox.minY - body.padding + body.maxX = body.bbox.maxX + body.padding + body.maxY = body.bbox.maxY + body.padding // reinsert bounding box to collision tree - return super.insert(body); + return super.insert(body) } /** * updates body in collision tree */ updateBody(body: TBody): void { - body.updateBody(); + body.updateBody() } /** @@ -152,8 +152,8 @@ export class BaseSystem */ update(): void { forEach(this.all(), (body: TBody) => { - this.updateBody(body); - }); + this.updateBody(body) + }) } /** @@ -161,8 +161,8 @@ export class BaseSystem */ draw(context: CanvasRenderingContext2D): void { forEach(this.all(), (body: TBody) => { - body.draw(context); - }); + body.draw(context) + }) } /** @@ -170,23 +170,23 @@ export class BaseSystem */ drawBVH(context: CanvasRenderingContext2D): void { const drawChildren = (body: Leaf) => { - drawBVH(context, body as TBody); + drawBVH(context, body as TBody) if (body.children) { - forEach(body.children, drawChildren); + forEach(body.children, drawChildren) } - }; + } - forEach(this.data.children, drawChildren); + forEach(this.data.children, drawChildren) } /** * remove body aabb from collision tree */ - remove(body: TBody, equals?: InTest): RBush { - body.system = undefined; + remove(body: TBody, equals?: InTest): this { + body.system = undefined - return super.remove(body, equals); + return super.remove(body, equals) } /** @@ -195,7 +195,7 @@ export class BaseSystem */ getPotentials(body: TBody): TBody[] { // filter here is required as collides with self - return filter(this.search(body), (candidate: TBody) => candidate !== body); + return filter(this.search(body), (candidate: TBody) => candidate !== body) } /** @@ -203,21 +203,21 @@ export class BaseSystem */ traverse( traverseFunction: TraverseFunction, - { children }: { children?: Leaf[] } = this.data, + { children }: { children?: Leaf[] } = this.data ): TBody | undefined { return children?.find((body, index) => { if (!body) { - return false; + return false } if (body.typeGroup && traverseFunction(body, children, index)) { - return true; + return true } // if callback returns true, ends forEach if (body.children) { - this.traverse(traverseFunction, body); + this.traverse(traverseFunction, body) } - }); + }) } } diff --git a/src/benchmarks/index.ts b/src/benchmarks/index.ts index d9d099a2..ddaf4ed1 100644 --- a/src/benchmarks/index.ts +++ b/src/benchmarks/index.ts @@ -1,2 +1,2 @@ -export { insertionBenchmark } from "./insertion.bench"; -export { stressBenchmark } from "./stress.bench"; +export { insertionBenchmark } from "./insertion.bench" +export { stressBenchmark } from "./stress.bench" diff --git a/src/benchmarks/insertion.bench.ts b/src/benchmarks/insertion.bench.ts index 82361f71..bb1ddb18 100644 --- a/src/benchmarks/insertion.bench.ts +++ b/src/benchmarks/insertion.bench.ts @@ -1,99 +1,98 @@ /* tslint:disable:no-implicit-dependencies */ -import { Bench } from "tinybench"; - -import { Circle } from "../bodies/circle"; -import { Polygon } from "../bodies/polygon"; -import { SATVector } from "../model"; -import { System } from "../system"; +import { Bench } from "tinybench" +import { Circle } from "../bodies/circle.js" +import { Polygon } from "../bodies/polygon.js" +import { SATVector } from "../model.js" +import { System } from "../system.js" export const insertionBenchmark = () => { - const benchmark = new Bench({}); - const nonoverlappingBodies: Circle[] = []; - const nonoverlappingTriangles: Polygon[] = []; - const nonoverlappingRectangles: Polygon[] = []; - const overlappingBodies: Circle[] = []; - const overlappingTriangles: Polygon[] = []; - const overlappingRectangles: Polygon[] = []; - const BODY_COUNT = 1000; + const benchmark = new Bench({}) + const nonoverlappingBodies: Circle[] = [] + const nonoverlappingTriangles: Polygon[] = [] + const nonoverlappingRectangles: Polygon[] = [] + const overlappingBodies: Circle[] = [] + const overlappingTriangles: Polygon[] = [] + const overlappingRectangles: Polygon[] = [] + const BODY_COUNT = 1000 for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - nonoverlappingBodies.push(new Circle(new SATVector(ndx, 0), 0.25)); - overlappingBodies.push(new Circle(new SATVector(0, 0), 0.25)); + nonoverlappingBodies.push(new Circle(new SATVector(ndx, 0), 0.25)) + overlappingBodies.push(new Circle(new SATVector(0, 0), 0.25)) nonoverlappingTriangles.push( new Polygon(new SATVector(ndx * 2, 0), [ new SATVector(0, 0), new SATVector(0, 1), - new SATVector(1, 0), - ]), - ); + new SATVector(1, 0) + ]) + ) overlappingTriangles.push( new Polygon(new SATVector(0, 0), [ new SATVector(0, 0), new SATVector(0, 1), - new SATVector(1, 0), - ]), - ); + new SATVector(1, 0) + ]) + ) nonoverlappingRectangles.push( new Polygon(new SATVector(0, 0), [ new SATVector(0, 0), new SATVector(0, 1), new SATVector(1, 1), - new SATVector(1, 0), - ]), - ); + new SATVector(1, 0) + ]) + ) overlappingRectangles.push( new Polygon(new SATVector(0, 0), [ new SATVector(0, 0), new SATVector(0, 1), new SATVector(1, 1), - new SATVector(1, 0), - ]), - ); + new SATVector(1, 0) + ]) + ) } benchmark .add("non overlapping circles", () => { - const uut = new System(BODY_COUNT); + const uut = new System(BODY_COUNT) for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - uut.insert(nonoverlappingBodies[ndx]); + uut.insert(nonoverlappingBodies[ndx]) } }) .add("overlapping circles", () => { - const uut = new System(BODY_COUNT); + const uut = new System(BODY_COUNT) for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - uut.insert(overlappingBodies[ndx]); + uut.insert(overlappingBodies[ndx]) } }) .add("non-overlapping triangles", () => { - const uut = new System(BODY_COUNT); + const uut = new System(BODY_COUNT) for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - uut.insert(nonoverlappingTriangles[ndx]); + uut.insert(nonoverlappingTriangles[ndx]) } }) .add("overlapping triangles", () => { - const uut = new System(BODY_COUNT); + const uut = new System(BODY_COUNT) for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - uut.insert(overlappingTriangles[ndx]); + uut.insert(overlappingTriangles[ndx]) } }) .add("non-overlapping quad", () => { - const uut = new System(BODY_COUNT); + const uut = new System(BODY_COUNT) for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - uut.insert(nonoverlappingRectangles[ndx]); + uut.insert(nonoverlappingRectangles[ndx]) } }) .add("overlapping quad", () => { - const uut = new System(BODY_COUNT); + const uut = new System(BODY_COUNT) for (let ndx = 0; ndx < BODY_COUNT; ndx++) { - uut.insert(overlappingRectangles[ndx]); + uut.insert(overlappingRectangles[ndx]) } - }); + }) benchmark .run() @@ -105,11 +104,11 @@ export const insertionBenchmark = () => { "Standard Deviation (s)": parseFloat((result?.sd ?? 0).toFixed(3)), hz: parseFloat((result?.hz ?? 0).toFixed(3)), "p99 (s)": parseFloat((result?.p99 ?? 0).toFixed(3)), - "p995 (s)": parseFloat((result?.p995 ?? 0).toFixed(3)), - })), - ); + "p995 (s)": parseFloat((result?.p995 ?? 0).toFixed(3)) + })) + ) + }) + .catch(err => { + console.warn(err.message || err) }) - .catch((err) => { - console.warn(err.message || err); - }); -}; +} diff --git a/src/benchmarks/stress.bench.ts b/src/benchmarks/stress.bench.ts index 88e48561..6db55b4c 100644 --- a/src/benchmarks/stress.bench.ts +++ b/src/benchmarks/stress.bench.ts @@ -1,39 +1,39 @@ /* tslint:disable:no-implicit-dependencies variable-name no-any */ -import { Bench } from "tinybench"; +import { Bench } from "tinybench" -export const stressBenchmark = async () => { - const { default: Stress } = await import("../demo/stress"); +export const stressBenchmark = async() => { + const { default: Stress } = await import("../demo/stress.js") - let stressTest: any; + let stressTest: any const benchmark = new Bench({ time: 1000, warmupIterations: 0, setup: ({ opts }: any) => { - stressTest = new Stress(opts.items); + stressTest = new Stress(opts.items) }, teardown: () => { - stressTest.physics.clear(); - }, - }); + stressTest.physics.clear() + } + }) const recursiveAddTest = (items: number) => { benchmark.add( `stress test, items=${items}`, () => { - stressTest.update(); + stressTest.update() }, - { items } as any, - ); + { items } as any + ) if (items < 10000) { - recursiveAddTest(items + 1000); + recursiveAddTest(items + 1000) } - }; + } - recursiveAddTest(1000); + recursiveAddTest(1000) - await benchmark.run(); + await benchmark.run() - console.table(benchmark.table()); -}; + console.table(benchmark.table()) +} diff --git a/src/bodies/box.spec.js b/src/bodies/box.spec.js index f9f923ff..6e7b00c0 100644 --- a/src/bodies/box.spec.js +++ b/src/bodies/box.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - describe("GIVEN Box", () => { it("THEN changing width works correctly", () => { const { System } = require("../../src"); diff --git a/src/bodies/box.ts b/src/bodies/box.ts index 4d678b93..2aa945e8 100644 --- a/src/bodies/box.ts +++ b/src/bodies/box.ts @@ -1,6 +1,7 @@ -import { BodyGroup, BodyOptions, BodyType, PotentialVector } from "../model"; -import { createBox } from "../utils"; -import { Polygon } from "./polygon"; +import { BodyGroup, BodyOptions, BodyType, PotentialVector } from "../model" + +import { Polygon } from "./polygon" +import { createBox } from "../utils" /** * collider - box @@ -9,27 +10,27 @@ export class Box extends Polygon { /** * type of body */ - readonly type: BodyType.Box | BodyType.Point = BodyType.Box; + readonly type: BodyType.Box | BodyType.Point = BodyType.Box /** * faster than type */ - readonly typeGroup: BodyGroup.Box | BodyGroup.Point = BodyGroup.Box; + readonly typeGroup: BodyGroup.Box | BodyGroup.Point = BodyGroup.Box /** * boxes are convex */ - readonly isConvex = true; + readonly isConvex = true /** * inner width */ - protected _width: number; + protected _width: number /** * inner height */ - protected _height: number; + protected _height: number /** * collider - box @@ -38,42 +39,42 @@ export class Box extends Polygon { position: PotentialVector, width: number, height: number, - options?: BodyOptions, + options?: BodyOptions ) { - super(position, createBox(width, height), options); + super(position, createBox(width, height), options) - this._width = width; - this._height = height; + this._width = width + this._height = height } /** * get box width */ get width(): number { - return this._width; + return this._width } /** * set box width, update points */ set width(width: number) { - this._width = width; - this.afterUpdateSize(); + this._width = width + this.afterUpdateSize() } /** * get box height */ get height(): number { - return this._height; + return this._height } /** * set box height, update points */ set height(height: number) { - this._height = height; - this.afterUpdateSize(); + this._height = height + this.afterUpdateSize() } /** @@ -82,13 +83,13 @@ export class Box extends Polygon { */ protected afterUpdateSize(): void { if (this.isCentered) { - this.retranslate(false); + this.retranslate(false) } - this.setPoints(createBox(this._width, this._height)); + this.setPoints(createBox(this._width, this._height)) if (this.isCentered) { - this.retranslate(); + this.retranslate() } } @@ -96,6 +97,6 @@ export class Box extends Polygon { * do not attempt to use Polygon.updateIsConvex() */ protected updateIsConvex(): void { - return; + return } } diff --git a/src/bodies/circle.spec.js b/src/bodies/circle.spec.js index 09d7e940..73df3825 100644 --- a/src/bodies/circle.spec.js +++ b/src/bodies/circle.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - describe("GIVEN Circle", () => { describe("AND you adjust radius", () => { it("THEN it gives correct collision results", () => { diff --git a/src/bodies/circle.ts b/src/bodies/circle.ts index 2b6beb4a..c4055d0c 100644 --- a/src/bodies/circle.ts +++ b/src/bodies/circle.ts @@ -1,23 +1,24 @@ -import { BBox } from "rbush"; -import { Circle as SATCircle } from "sat"; - -import { System } from "../system"; import { + BBox, BodyGroup, BodyOptions, BodyProps, BodyType, PotentialVector, SATVector, - Vector, -} from "../model"; + Vector +} from "../model" import { dashLineTo, drawBVH, ensureVectorPoint, extendBody, getGroup, -} from "../utils"; + move +} from "../utils" + +import { Circle as SATCircle } from "sat" +import { System } from "../system" /** * collider - circle @@ -26,97 +27,97 @@ export class Circle extends SATCircle implements BBox, BodyProps { /** * minimum x bound of body */ - minX!: number; + minX!: number /** * maximum x bound of body */ - maxX!: number; + maxX!: number /** * minimum y bound of body */ - minY!: number; + minY!: number /** * maximum y bound of body */ - maxY!: number; + maxY!: number /** * bounding box cache, without padding */ - bbox!: BBox; + bbox!: BBox /** * offset */ - offset!: SATVector; + offset!: SATVector /** * offset copy without angle applied */ - offsetCopy: Vector = { x: 0, y: 0 }; + offsetCopy: Vector = { x: 0, y: 0 } /** * bodies are not reinserted during update if their bbox didnt move outside bbox + padding */ - padding!: number; + padding!: number /** * for compatibility reasons circle has angle */ - angle!: number; + angle!: number /** * static bodies don't move but they collide */ - isStatic!: boolean; + isStatic!: boolean /** * trigger bodies move but are like ghosts */ - isTrigger!: boolean; + isTrigger!: boolean /** * reference to collision system */ - system?: System; + system?: System /** * was the polygon modified and needs update in the next checkCollision */ - dirty = false; + dirty = false /* * circles are convex */ - readonly isConvex = true; + readonly isConvex = true /** * circle type */ - readonly type: BodyType.Circle = BodyType.Circle; + readonly type: BodyType.Circle = BodyType.Circle /** * faster than type */ - readonly typeGroup: BodyGroup.Circle = BodyGroup.Circle; + readonly typeGroup: BodyGroup.Circle = BodyGroup.Circle /** * always centered */ - readonly isCentered = true; + readonly isCentered = true /** * group for collision filtering */ - protected _group!: number; + protected _group!: number /** * saved initial radius - internal */ - protected readonly unscaledRadius: number; + protected readonly unscaledRadius: number /** * collider - circle @@ -124,173 +125,182 @@ export class Circle extends SATCircle implements BBox, BodyProps { constructor( position: PotentialVector, radius: number, - options?: BodyOptions, + options?: BodyOptions ) { - super(ensureVectorPoint(position), radius); + super(ensureVectorPoint(position), radius) - extendBody(this, options); + extendBody(this, options) - this.unscaledRadius = radius; + this.unscaledRadius = radius } /** * get this.pos.x */ get x(): number { - return this.pos.x; + return this.pos.x } /** * updating this.pos.x by this.x = x updates AABB */ set x(x: number) { - this.pos.x = x; - this.markAsDirty(); + this.pos.x = x + this.markAsDirty() } /** * get this.pos.y */ get y(): number { - return this.pos.y; + return this.pos.y } /** * updating this.pos.y by this.y = y updates AABB */ set y(y: number) { - this.pos.y = y; - this.markAsDirty(); + this.pos.y = y + this.markAsDirty() } /** * allow get scale */ get scale(): number { - return this.r / this.unscaledRadius; + return this.r / this.unscaledRadius } /** * shorthand for setScale() */ set scale(scale: number) { - this.setScale(scale); + this.setScale(scale) } /** * scaleX = scale in case of Circles */ get scaleX(): number { - return this.scale; + return this.scale } /** * scaleY = scale in case of Circles */ get scaleY(): number { - return this.scale; + return this.scale } /** * group for collision filtering */ get group(): number { - return this._group; + return this._group } set group(group: number) { - this._group = getGroup(group); + this._group = getGroup(group) + } + + /** + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true): Circle { + move(this, speed, updateNow) + + return this } /** - * update position + * update position BY TELEPORTING */ - setPosition(x: number, y: number, update = true): Circle { - this.pos.x = x; - this.pos.y = y; - this.markAsDirty(update); + setPosition(x: number, y: number, updateNow = true): Circle { + this.pos.x = x + this.pos.y = y + this.markAsDirty(updateNow) - return this; + return this } /** * update scale */ - setScale(scaleX: number, _scaleY = scaleX, update = true): Circle { - this.r = this.unscaledRadius * Math.abs(scaleX); - this.markAsDirty(update); + setScale(scaleX: number, _scaleY = scaleX, updateNow = true): Circle { + this.r = this.unscaledRadius * Math.abs(scaleX) + this.markAsDirty(updateNow) - return this; + return this } /** * set rotation */ - setAngle(angle: number, update = true): Circle { - this.angle = angle; + setAngle(angle: number, updateNow = true): Circle { + this.angle = angle - const { x, y } = this.getOffsetWithAngle(); - this.offset.x = x; - this.offset.y = y; - this.markAsDirty(update); + const { x, y } = this.getOffsetWithAngle() + this.offset.x = x + this.offset.y = y + this.markAsDirty(updateNow) - return this; + return this } /** * set offset from center */ - setOffset(offset: Vector, update = true): Circle { - this.offsetCopy.x = offset.x; - this.offsetCopy.y = offset.y; + setOffset(offset: Vector, updateNow = true): Circle { + this.offsetCopy.x = offset.x + this.offsetCopy.y = offset.y - const { x, y } = this.getOffsetWithAngle(); - this.offset.x = x; - this.offset.y = y; - this.markAsDirty(update); + const { x, y } = this.getOffsetWithAngle() + this.offset.x = x + this.offset.y = y + this.markAsDirty(updateNow) - return this; + return this } /** * get body bounding box, without padding */ getAABBAsBBox(): BBox { - const x = this.pos.x + this.offset.x; - const y = this.pos.y + this.offset.y; + const x = this.pos.x + this.offset.x + const y = this.pos.y + this.offset.y return { minX: x - this.r, maxX: x + this.r, minY: y - this.r, - maxY: y + this.r, - }; + maxY: y + this.r + } } /** * Draws collider on a CanvasRenderingContext2D's current path */ draw(context: CanvasRenderingContext2D) { - const x = this.pos.x + this.offset.x; - const y = this.pos.y + this.offset.y; - const r = Math.abs(this.r); + const x = this.pos.x + this.offset.x + const y = this.pos.y + this.offset.y + const r = Math.abs(this.r) if (this.isTrigger) { - const max = Math.max(8, this.r); + const max = Math.max(8, this.r) for (let i = 0; i < max; i++) { - const arc = (i / max) * 2 * Math.PI; - const arcPrev = ((i - 1) / max) * 2 * Math.PI; - const fromX = x + Math.cos(arcPrev) * this.r; - const fromY = y + Math.sin(arcPrev) * this.r; - const toX = x + Math.cos(arc) * this.r; - const toY = y + Math.sin(arc) * this.r; - - dashLineTo(context, fromX, fromY, toX, toY); + const arc = (i / max) * 2 * Math.PI + const arcPrev = ((i - 1) / max) * 2 * Math.PI + const fromX = x + Math.cos(arcPrev) * this.r + const fromY = y + Math.sin(arcPrev) * this.r + const toX = x + Math.cos(arc) * this.r + const toY = y + Math.sin(arc) * this.r + + dashLineTo(context, fromX, fromY, toX, toY) } } else { - context.moveTo(x + r, y); - context.arc(x, y, r, 0, Math.PI * 2); + context.moveTo(x + r, y) + context.arc(x, y, r, 0, Math.PI * 2) } } @@ -298,27 +308,27 @@ export class Circle extends SATCircle implements BBox, BodyProps { * Draws Bounding Box on canvas context */ drawBVH(context: CanvasRenderingContext2D) { - drawBVH(context, this); + drawBVH(context, this) } /** * inner function for after position change update aabb in system */ - updateBody(update = this.dirty): void { - if (update) { - this.system?.insert(this); - this.dirty = false; + updateBody(updateNow = this.dirty): void { + if (updateNow) { + this.system?.insert(this) + this.dirty = false } } /** * update instantly or mark as dirty */ - protected markAsDirty(update = false): void { - if (update) { - this.updateBody(true); + protected markAsDirty(updateNow = false): void { + if (updateNow) { + this.updateBody(true) } else { - this.dirty = true; + this.dirty = true } } @@ -327,14 +337,14 @@ export class Circle extends SATCircle implements BBox, BodyProps { */ protected getOffsetWithAngle(): Vector { if ((!this.offsetCopy.x && !this.offsetCopy.y) || !this.angle) { - return this.offsetCopy; + return this.offsetCopy } - const sin = Math.sin(this.angle); - const cos = Math.cos(this.angle); - const x = this.offsetCopy.x * cos - this.offsetCopy.y * sin; - const y = this.offsetCopy.x * sin + this.offsetCopy.y * cos; + const sin = Math.sin(this.angle) + const cos = Math.cos(this.angle) + const x = this.offsetCopy.x * cos - this.offsetCopy.y * sin + const y = this.offsetCopy.x * sin + this.offsetCopy.y * cos - return { x, y }; + return { x, y } } } diff --git a/src/bodies/ellipse.spec.js b/src/bodies/ellipse.spec.js index 4fa61b33..ab690045 100644 --- a/src/bodies/ellipse.spec.js +++ b/src/bodies/ellipse.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - describe("GIVEN Ellipse", () => { describe("AND you adjust radiusX", () => { it("THEN it gives correct collision results", () => { diff --git a/src/bodies/ellipse.ts b/src/bodies/ellipse.ts index 7673cd56..daf36556 100644 --- a/src/bodies/ellipse.ts +++ b/src/bodies/ellipse.ts @@ -1,6 +1,7 @@ -import { BodyGroup, BodyOptions, BodyType, PotentialVector } from "../model"; -import { createEllipse } from "../utils"; -import { Polygon } from "./polygon"; +import { BodyGroup, BodyOptions, BodyType, PotentialVector } from "../model" + +import { Polygon } from "./polygon" +import { createEllipse } from "../utils" /** * collider - ellipse @@ -9,24 +10,24 @@ export class Ellipse extends Polygon { /** * ellipse type */ - readonly type: BodyType.Ellipse = BodyType.Ellipse; + readonly type: BodyType.Ellipse = BodyType.Ellipse /** * faster than type */ - readonly typeGroup: BodyGroup.Ellipse = BodyGroup.Ellipse; + readonly typeGroup: BodyGroup.Ellipse = BodyGroup.Ellipse /** * ellipses are convex */ - readonly isConvex = true; + readonly isConvex = true /** * inner initial params save */ - protected _radiusX: number; - protected _radiusY: number; - protected _step: number; + protected _radiusX: number + protected _radiusY: number + protected _step: number /** * collider - ellipse @@ -36,13 +37,13 @@ export class Ellipse extends Polygon { radiusX: number, radiusY: number = radiusX, step: number = (radiusX + radiusY) / Math.PI, - options?: BodyOptions, + options?: BodyOptions ) { - super(position, createEllipse(radiusX, radiusY, step), options); + super(position, createEllipse(radiusX, radiusY, step), options) - this._radiusX = radiusX; - this._radiusY = radiusY; - this._step = step; + this._radiusX = radiusX + this._radiusY = radiusY + this._step = step } /** @@ -54,65 +55,65 @@ export class Ellipse extends Polygon { * is body centered? */ get isCentered(): boolean { - return true; + return true } /** * get ellipse step number */ get step(): number { - return this._step; + return this._step } /** * set ellipse step number */ set step(step: number) { - this._step = step; - this.setPoints(createEllipse(this._radiusX, this._radiusY, this._step)); + this._step = step + this.setPoints(createEllipse(this._radiusX, this._radiusY, this._step)) } /** * get ellipse radiusX */ get radiusX(): number { - return this._radiusX; + return this._radiusX } /** * set ellipse radiusX, update points */ set radiusX(radiusX: number) { - this._radiusX = radiusX; - this.setPoints(createEllipse(this._radiusX, this._radiusY, this._step)); + this._radiusX = radiusX + this.setPoints(createEllipse(this._radiusX, this._radiusY, this._step)) } /** * get ellipse radiusY */ get radiusY(): number { - return this._radiusY; + return this._radiusY } /** * set ellipse radiusY, update points */ set radiusY(radiusY: number) { - this._radiusY = radiusY; - this.setPoints(createEllipse(this._radiusX, this._radiusY, this._step)); + this._radiusY = radiusY + this.setPoints(createEllipse(this._radiusX, this._radiusY, this._step)) } /** * do not attempt to use Polygon.center() */ center(): void { - return; + return } /** * do not attempt to use Polygon.updateIsConvex() */ protected updateIsConvex(): void { - return; + return } } diff --git a/src/bodies/line.spec.js b/src/bodies/line.spec.js index fd2667f6..bbb8f2bf 100644 --- a/src/bodies/line.spec.js +++ b/src/bodies/line.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - describe("GIVEN Line", () => { it("THEN without constructor values it throws", () => { const { Line } = require("../../src"); diff --git a/src/bodies/line.ts b/src/bodies/line.ts index 6f129751..d4a248e1 100644 --- a/src/bodies/line.ts +++ b/src/bodies/line.ts @@ -1,7 +1,7 @@ -import { Vector as SATVector } from "sat"; +import { BodyGroup, BodyOptions, BodyType, Vector } from "../model" -import { BodyGroup, BodyOptions, BodyType, Vector } from "../model"; -import { Polygon } from "./polygon"; +import { Polygon } from "./polygon" +import { Vector as SATVector } from "sat" /** * collider - line @@ -10,17 +10,17 @@ export class Line extends Polygon { /** * line type */ - readonly type: BodyType.Line = BodyType.Line; + readonly type: BodyType.Line = BodyType.Line /** * faster than type */ - readonly typeGroup: BodyGroup.Line = BodyGroup.Line; + readonly typeGroup: BodyGroup.Line = BodyGroup.Line /** * line is convex */ - readonly isConvex = true; + readonly isConvex = true /** * collider - line from start to end @@ -30,54 +30,54 @@ export class Line extends Polygon { start, [ { x: 0, y: 0 }, - { x: end.x - start.x, y: end.y - start.y }, + { x: end.x - start.x, y: end.y - start.y } ], - options, - ); + options + ) if (this.calcPoints.length === 1 || !end) { - console.error({ start, end }); + console.error({ start, end }) - throw new Error("No end point for line provided"); + throw new Error("No end point for line provided") } } get start(): Vector { return { x: this.x + this.calcPoints[0].x, - y: this.y + this.calcPoints[0].y, - }; + y: this.y + this.calcPoints[0].y + } } set start({ x, y }: Vector) { - this.x = x; - this.y = y; + this.x = x + this.y = y } get end(): Vector { return { x: this.x + this.calcPoints[1].x, - y: this.y + this.calcPoints[1].y, - }; + y: this.y + this.calcPoints[1].y + } } set end({ x, y }: Vector) { - this.points[1].x = x - this.start.x; - this.points[1].y = y - this.start.y; - this.setPoints(this.points); + this.points[1].x = x - this.start.x + this.points[1].y = y - this.start.y + this.setPoints(this.points) } getCentroid(): SATVector { return new SATVector( (this.end.x - this.start.x) / 2, - (this.end.y - this.start.y) / 2, - ); + (this.end.y - this.start.y) / 2 + ) } /** * do not attempt to use Polygon.updateIsConvex() */ protected updateIsConvex(): void { - return; + return } } diff --git a/src/bodies/point.spec.js b/src/bodies/point.spec.js index 1df32107..c328445d 100644 --- a/src/bodies/point.spec.js +++ b/src/bodies/point.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - describe("GIVEN Point", () => { it("THEN without constructor values, initializes with (0, 0)", () => { const { Point } = require("../../src"); diff --git a/src/bodies/point.ts b/src/bodies/point.ts index 1d2e5c09..933a5246 100644 --- a/src/bodies/point.ts +++ b/src/bodies/point.ts @@ -1,6 +1,7 @@ -import { BodyGroup, BodyOptions, BodyType, PotentialVector } from "../model"; -import { ensureVectorPoint } from "../utils"; -import { Box } from "./box"; +import { BodyGroup, BodyOptions, BodyType, PotentialVector } from "../model" + +import { Box } from "./box" +import { ensureVectorPoint } from "../utils" /** * collider - point (very tiny box) @@ -9,17 +10,17 @@ export class Point extends Box { /** * point type */ - readonly type: BodyType.Point = BodyType.Point; + readonly type: BodyType.Point = BodyType.Point /** * faster than type */ - readonly typeGroup: BodyGroup.Point = BodyGroup.Point; + readonly typeGroup: BodyGroup.Point = BodyGroup.Point /** * collider - point (very tiny box) */ constructor(position: PotentialVector, options?: BodyOptions) { - super(ensureVectorPoint(position), 0.001, 0.001, options); + super(ensureVectorPoint(position), 0.001, 0.001, options) } } diff --git a/src/bodies/polygon.spec.js b/src/bodies/polygon.spec.js index 33f340bc..7f4915a3 100644 --- a/src/bodies/polygon.spec.js +++ b/src/bodies/polygon.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - describe("GIVEN Polygon", () => { it("THEN you need at least one point to create", () => { const { Polygon } = require("../../src"); diff --git a/src/bodies/polygon.ts b/src/bodies/polygon.ts index 93b8c269..02c5c4aa 100644 --- a/src/bodies/polygon.ts +++ b/src/bodies/polygon.ts @@ -1,8 +1,5 @@ -import { isSimple, quickDecomp } from "poly-decomp-es"; -import { BBox } from "rbush"; -import { Polygon as SATPolygon } from "sat"; - import { + BBox, BodyGroup, BodyOptions, BodyProps, @@ -11,10 +8,8 @@ import { GetAABBAsBox, PotentialVector, SATVector, - Vector, -} from "../model"; -import { forEach, map } from "../optimized"; -import { System } from "../system"; + Vector +} from "../model" import { clonePointsArray, drawBVH, @@ -25,9 +20,15 @@ import { getGroup, mapArrayToVector, mapVectorToArray, -} from "../utils"; + move +} from "../utils" +import { forEach, map } from "../optimized" +import { isSimple, quickDecomp } from "poly-decomp-es" + +import { Polygon as SATPolygon } from "sat" +import { System } from "../system" -export { isSimple }; +export { isSimple } /** * collider - polygon @@ -36,62 +37,62 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { /** * minimum x bound of body */ - minX!: number; + minX!: number /** * maximum x bound of body */ - maxX!: number; + maxX!: number /** * minimum y bound of body */ - minY!: number; + minY!: number /** * maximum y bound of body */ - maxY!: number; + maxY!: number /** * bounding box cache, without padding */ - bbox!: BBox; + bbox!: BBox /** * is it a convex polgyon as opposed to a hollow inside (concave) polygon */ - isConvex!: boolean; + isConvex!: boolean /** * optimization for convex polygons */ - convexPolygons!: SATPolygon[]; + convexPolygons!: SATPolygon[] /** * bodies are not reinserted during update if their bbox didnt move outside bbox + padding */ - padding!: number; + padding!: number /** * static bodies don't move but they collide */ - isStatic!: boolean; + isStatic!: boolean /** * trigger bodies move but are like ghosts */ - isTrigger!: boolean; + isTrigger!: boolean /** * reference to collision system */ - system?: System; + system?: System /** * was the polygon modified and needs update in the next checkCollision */ - dirty = false; + dirty = false /** * type of body @@ -101,7 +102,7 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { | BodyType.Box | BodyType.Point | BodyType.Ellipse - | BodyType.Line = BodyType.Polygon; + | BodyType.Line = BodyType.Polygon /** * faster than type @@ -111,27 +112,27 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { | BodyGroup.Box | BodyGroup.Point | BodyGroup.Ellipse - | BodyGroup.Line = BodyGroup.Polygon; + | BodyGroup.Line = BodyGroup.Polygon /** * backup of points used for scaling */ - protected pointsBackup!: Vector[]; + protected pointsBackup!: Vector[] /** * is body centered */ - protected centered = false; + protected centered = false /** * group for collision filtering */ - protected _group!: number; + protected _group!: number /** * scale Vector of body */ - protected readonly scaleVector: Vector = { x: 1, y: 1 }; + protected readonly scaleVector: Vector = { x: 1, y: 1 } /** * collider - polygon @@ -139,15 +140,15 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { constructor( position: PotentialVector, points: PotentialVector[], - options?: BodyOptions, + options?: BodyOptions ) { - super(ensureVectorPoint(position), ensurePolygonPoints(points)); + super(ensureVectorPoint(position), ensurePolygonPoints(points)) if (!points.length) { - throw new Error("No points in polygon"); + throw new Error("No points in polygon") } - extendBody(this, options); + extendBody(this, options) } /** @@ -155,162 +156,171 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { */ set isCentered(isCentered: boolean) { if (this.centered === isCentered) { - return; + return } - const centroid = this.getCentroidWithoutRotation(); + const centroid = this.getCentroidWithoutRotation() if (centroid.x || centroid.y) { - const x = centroid.x * (isCentered ? 1 : -1); - const y = centroid.y * (isCentered ? 1 : -1); + const x = centroid.x * (isCentered ? 1 : -1) + const y = centroid.y * (isCentered ? 1 : -1) - this.translate(-x, -y); + this.translate(-x, -y) } - this.centered = isCentered; + this.centered = isCentered } /** * is polygon centered? */ get isCentered(): boolean { - return this.centered; + return this.centered } get x(): number { - return this.pos.x; + return this.pos.x } /** * updating this.pos.x by this.x = x updates AABB */ set x(x: number) { - this.pos.x = x; - this.markAsDirty(); + this.pos.x = x + this.markAsDirty() } get y(): number { - return this.pos.y; + return this.pos.y } /** * updating this.pos.y by this.y = y updates AABB */ set y(y: number) { - this.pos.y = y; - this.markAsDirty(); + this.pos.y = y + this.markAsDirty() } /** * allow exact getting of scale x - use setScale(x, y) to set */ get scaleX(): number { - return this.scaleVector.x; + return this.scaleVector.x } /** * allow exact getting of scale y - use setScale(x, y) to set */ get scaleY(): number { - return this.scaleVector.y; + return this.scaleVector.y } /** * allow approx getting of scale */ get scale(): number { - return (this.scaleVector.x + this.scaleVector.y) / 2; + return (this.scaleVector.x + this.scaleVector.y) / 2 } /** * allow easier setting of scale */ set scale(scale: number) { - this.setScale(scale); + this.setScale(scale) } /** * group for collision filtering */ get group(): number { - return this._group; + return this._group } set group(group: number) { - this._group = getGroup(group); + this._group = getGroup(group) + } + + /** + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed = 1, updateNow = true): SATPolygon { + move(this, speed, updateNow) + + return this } /** - * update position + * update position BY TELEPORTING */ - setPosition(x: number, y: number, update = true): SATPolygon { - this.pos.x = x; - this.pos.y = y; - this.markAsDirty(update); + setPosition(x: number, y: number, updateNow = true): SATPolygon { + this.pos.x = x + this.pos.y = y + this.markAsDirty(updateNow) - return this; + return this } /** * update scale */ - setScale(x: number, y: number = x, update = true): SATPolygon { - this.scaleVector.x = Math.abs(x); - this.scaleVector.y = Math.abs(y); + setScale(x: number, y: number = x, updateNow = true): SATPolygon { + this.scaleVector.x = Math.abs(x) + this.scaleVector.y = Math.abs(y) super.setPoints( map(this.points, (point: SATVector, index: number) => { - point.x = this.pointsBackup[index].x * this.scaleVector.x; - point.y = this.pointsBackup[index].y * this.scaleVector.y; + point.x = this.pointsBackup[index].x * this.scaleVector.x + point.y = this.pointsBackup[index].y * this.scaleVector.y - return point; - }), - ); + return point + }) + ) - this.markAsDirty(update); + this.markAsDirty(updateNow) - return this; + return this } - setAngle(angle: number, update = true): SATPolygon { - super.setAngle(angle); - this.markAsDirty(update); + setAngle(angle: number, updateNow = true): SATPolygon { + super.setAngle(angle) + this.markAsDirty(updateNow) - return this; + return this } - setOffset(offset: SATVector, update = true): SATPolygon { - super.setOffset(offset); - this.markAsDirty(update); + setOffset(offset: SATVector, updateNow = true): SATPolygon { + super.setOffset(offset) + this.markAsDirty(updateNow) - return this; + return this } /** * get body bounding box, without padding */ getAABBAsBBox(): BBox { - const { pos, w, h } = (this as unknown as GetAABBAsBox).getAABBAsBox(); + const { pos, w, h } = (this as unknown as GetAABBAsBox).getAABBAsBox() return { minX: pos.x, minY: pos.y, maxX: pos.x + w, - maxY: pos.y + h, - }; + maxY: pos.y + h + } } /** * Draws exact collider on canvas context */ draw(context: CanvasRenderingContext2D) { - drawPolygon(context, this, this.isTrigger); + drawPolygon(context, this, this.isTrigger) } /** * Draws Bounding Box on canvas context */ drawBVH(context: CanvasRenderingContext2D) { - drawBVH(context, this); + drawBVH(context, this) } /** @@ -318,90 +328,90 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { */ getCentroidWithoutRotation(): Vector { // keep angle copy - const angle = this.angle; + const angle = this.angle if (angle) { // reset angle for get centroid - this.setAngle(0); + this.setAngle(0) // get centroid - const centroid = this.getCentroid(); + const centroid = this.getCentroid() // revert angle change - this.setAngle(angle); + this.setAngle(angle) - return centroid; + return centroid } - return this.getCentroid(); + return this.getCentroid() } /** * sets polygon points to new array of vectors */ setPoints(points: SATVector[]): Polygon { - super.setPoints(points); - this.updateIsConvex(); - this.pointsBackup = clonePointsArray(points); + super.setPoints(points) + this.updateIsConvex() + this.pointsBackup = clonePointsArray(points) - return this; + return this } /** * translates polygon points in x, y direction */ translate(x: number, y: number): Polygon { - super.translate(x, y); - this.pointsBackup = clonePointsArray(this.points); + super.translate(x, y) + this.pointsBackup = clonePointsArray(this.points) - return this; + return this } /** * rotates polygon points by angle, in radians */ rotate(angle: number): Polygon { - super.rotate(angle); - this.pointsBackup = clonePointsArray(this.points); + super.rotate(angle) + this.pointsBackup = clonePointsArray(this.points) - return this; + return this } /** * if true, polygon is not an invalid, self-crossing polygon */ isSimple(): boolean { - return isSimple(this.calcPoints.map(mapVectorToArray)); + return isSimple(this.calcPoints.map(mapVectorToArray)) } /** * inner function for after position change update aabb in system and convex inner polygons */ - updateBody(update = this.dirty): void { - if (update) { - this.updateConvexPolygonPositions(); - this.system?.insert(this); - this.dirty = false; + updateBody(updateNow = this.dirty): void { + if (updateNow) { + this.updateConvexPolygonPositions() + this.system?.insert(this) + this.dirty = false } } protected retranslate(isCentered = this.isCentered): void { - const centroid = this.getCentroidWithoutRotation(); + const centroid = this.getCentroidWithoutRotation() if (centroid.x || centroid.y) { - const x = centroid.x * (isCentered ? 1 : -1); - const y = centroid.y * (isCentered ? 1 : -1); + const x = centroid.x * (isCentered ? 1 : -1) + const y = centroid.y * (isCentered ? 1 : -1) - this.translate(-x, -y); + this.translate(-x, -y) } } /** * update instantly or mark as dirty */ - protected markAsDirty(update = false): void { - if (update) { - this.updateBody(true); + protected markAsDirty(updateNow = false): void { + if (updateNow) { + this.updateBody(true) } else { - this.dirty = true; + this.dirty = true } } @@ -411,17 +421,17 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { */ protected updateConvexPolygonPositions() { if (this.isConvex || !this.convexPolygons) { - return; + return } forEach(this.convexPolygons, (polygon: SATPolygon) => { - polygon.pos.x = this.pos.x; - polygon.pos.y = this.pos.y; + polygon.pos.x = this.pos.x + polygon.pos.y = this.pos.y if (polygon.angle !== this.angle) { // Must use setAngle to recalculate the points of the Polygon - polygon.setAngle(this.angle); + polygon.setAngle(this.angle) } - }); + }) } /** @@ -432,44 +442,44 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { (this.typeGroup && this.typeGroup !== BodyGroup.Polygon) || this.points.length < 4 ) { - return []; + return [] } - const points = map(this.calcPoints, mapVectorToArray); + const points = map(this.calcPoints, mapVectorToArray) - return quickDecomp(points); + return quickDecomp(points) } /** * updates convex polygons cache in body */ protected updateConvexPolygons( - convex: DecompPolygon[] = this.getConvex(), + convex: DecompPolygon[] = this.getConvex() ): void { if (this.isConvex) { - return; + return } if (!this.convexPolygons) { - this.convexPolygons = []; + this.convexPolygons = [] } forEach(convex, (points: DecompPolygon, index: number) => { // lazy create if (!this.convexPolygons[index]) { - this.convexPolygons[index] = new SATPolygon(); + this.convexPolygons[index] = new SATPolygon() } - this.convexPolygons[index].pos.x = this.pos.x; - this.convexPolygons[index].pos.y = this.pos.y; - this.convexPolygons[index].angle = this.angle; + this.convexPolygons[index].pos.x = this.pos.x + this.convexPolygons[index].pos.y = this.pos.y + this.convexPolygons[index].angle = this.angle this.convexPolygons[index].setPoints( - ensurePolygonPoints(map(points, mapArrayToVector)), - ); - }); + ensurePolygonPoints(map(points, mapArrayToVector)) + ) + }) // trim array length - this.convexPolygons.length = convex.length; + this.convexPolygons.length = convex.length } /** @@ -477,9 +487,9 @@ export class Polygon extends SATPolygon implements BBox, BodyProps { */ protected updateIsConvex(): void { // all other types other than polygon are always convex - const convex = this.getConvex(); + const convex = this.getConvex() // everything with empty array or one element array - this.isConvex = convex.length <= 1; - this.updateConvexPolygons(convex); + this.isConvex = convex.length <= 1 + this.updateConvexPolygons(convex) } } diff --git a/src/demo/tank.js b/src/demo/tank.js index 8f7bd1be..8e21b917 100644 --- a/src/demo/tank.js +++ b/src/demo/tank.js @@ -230,7 +230,7 @@ class Tank { return this.physics.createPolygon( { x: this.scaleX(x), y: this.scaleY(y) }, scaledPoints, - { angle }, + { angle, isStatic: true }, ); } diff --git a/src/index.spec.js b/src/index.spec.js index 93888b74..7168fe16 100644 --- a/src/index.spec.js +++ b/src/index.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - describe("GIVEN Index", () => { it("THEN requiring it doesnt throw exception", () => { const req = () => require("../src"); diff --git a/src/index.ts b/src/index.ts index 19201261..e94c3329 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,10 @@ -export * from "./model"; -export * from "./bodies/circle"; -export * from "./bodies/ellipse"; -export * from "./bodies/polygon"; -export * from "./bodies/box"; -export * from "./bodies/point"; -export * from "./bodies/line"; -export * from "./system"; -export * from "./utils"; -export * from "./intersect"; +export * from "./model" +export * from "./bodies/circle" +export * from "./bodies/ellipse" +export * from "./bodies/polygon" +export * from "./bodies/box" +export * from "./bodies/point" +export * from "./bodies/line" +export * from "./system" +export * from "./utils" +export * from "./intersect" diff --git a/src/intersect.ts b/src/intersect.ts index 37e6f42c..849c4351 100644 --- a/src/intersect.ts +++ b/src/intersect.ts @@ -1,53 +1,53 @@ -import { pointInCircle, pointInPolygon as pointInConvexPolygon } from "sat"; +import { Body, BodyGroup, SATPolygon, SATVector, Vector } from "./model" +import { every, forEach, map, some } from "./optimized" +import { pointInCircle, pointInPolygon as pointInConvexPolygon } from "sat" -import { Circle } from "./bodies/circle"; -import { Line } from "./bodies/line"; -import { Point } from "./bodies/point"; -import { Polygon } from "./bodies/polygon"; -import { Body, BodyGroup, SATPolygon, SATVector, Vector } from "./model"; -import { every, forEach, map, some } from "./optimized"; +import { Circle } from "./bodies/circle" +import { Line } from "./bodies/line" +import { Point } from "./bodies/point" +import { Polygon } from "./bodies/polygon" /** * replace body with array of related convex polygons */ export function ensureConvex( - body: TBody, + body: TBody ): (TBody | SATPolygon)[] { if (body.isConvex || body.typeGroup !== BodyGroup.Polygon) { - return [body]; + return [body] } - return body.convexPolygons; + return body.convexPolygons } export function polygonInCircle( polygon: Polygon, - circle: Pick, + circle: Pick ): boolean { - return every(polygon.calcPoints, (p) => + return every(polygon.calcPoints,p => pointInCircle( { x: p.x + polygon.pos.x, y: p.y + polygon.pos.y } as SATVector, - circle, - ), - ); + circle + ) + ) } export function pointInPolygon(point: Vector, polygon: Polygon): boolean { - return some(ensureConvex(polygon), (convex) => - pointInConvexPolygon(point as SATVector, convex), - ); + return some(ensureConvex(polygon),convex => + pointInConvexPolygon(point as SATVector, convex) + ) } export function polygonInPolygon( polygonA: Polygon, - polygonB: Polygon, + polygonB: Polygon ): boolean { - return every(polygonA.calcPoints, (point) => + return every(polygonA.calcPoints,point => pointInPolygon( { x: point.x + polygonA.pos.x, y: point.y + polygonA.pos.y }, - polygonB, - ), - ); + polygonB + ) + ) } /** @@ -55,13 +55,13 @@ export function polygonInPolygon( */ export function pointOnCircle( point: Vector, - circle: Pick, + circle: Pick ): boolean { return ( (point.x - circle.pos.x) * (point.x - circle.pos.x) + (point.y - circle.pos.y) * (point.y - circle.pos.y) === circle.r * circle.r - ); + ) } /** @@ -69,17 +69,17 @@ export function pointOnCircle( */ export function circleInCircle( bodyA: Pick, - bodyB: Pick, + bodyB: Pick ) { - const x1 = bodyA.pos.x; - const y1 = bodyA.pos.y; - const x2 = bodyB.pos.x; - const y2 = bodyB.pos.y; - const r1 = bodyA.r; - const r2 = bodyB.r; - const distSq = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); - - return distSq + r2 === r1 || distSq + r2 < r1; + const x1 = bodyA.pos.x + const y1 = bodyA.pos.y + const x2 = bodyB.pos.x + const y2 = bodyB.pos.y + const r1 = bodyA.r + const r2 = bodyB.r + const distSq = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) + + return distSq + r2 === r1 || distSq + r2 < r1 } /** @@ -87,31 +87,31 @@ export function circleInCircle( */ export function circleInPolygon( circle: Pick, - polygon: Polygon, + polygon: Polygon ): boolean { // Circle with radius 0 isn't a circle if (circle.r === 0) { - return false; + return false } // If the center of the circle is not within the polygon, // then the circle may overlap, but it'll never be "contained" // so return false if (!pointInPolygon(circle.pos, polygon)) { - return false; + return false } // Necessary add polygon pos to points const points = map(polygon.calcPoints, ({ x, y }: SATVector) => ({ x: x + polygon.pos.x, - y: y + polygon.pos.y, - })) as SATVector[]; + y: y + polygon.pos.y + })) as SATVector[] // If the center of the circle is within the polygon, // the circle is not outside of the polygon completely. // so return false. - if (some(points, (point) => pointInCircle(point, circle))) { - return false; + if (some(points,point => pointInCircle(point, circle))) { + return false } // If any line-segment of the polygon intersects the circle, @@ -121,15 +121,15 @@ export function circleInPolygon( some(points, (end, index) => { const start: Vector = index ? points[index - 1] - : points[points.length - 1]; + : points[points.length - 1] - return intersectLineCircle({ start, end }, circle).length > 0; + return intersectLineCircle({ start, end }, circle).length > 0 }) ) { - return false; + return false } - return true; + return true } /** @@ -137,36 +137,35 @@ export function circleInPolygon( */ export function circleOutsidePolygon( circle: Pick, - polygon: Polygon, + polygon: Polygon ): boolean { // Circle with radius 0 isn't a circle if (circle.r === 0) { - return false; + return false } // If the center of the circle is within the polygon, // the circle is not outside of the polygon completely. // so return false. if (pointInPolygon(circle.pos, polygon)) { - return false; + return false } // Necessary add polygon pos to points const points = map(polygon.calcPoints, ({ x, y }: SATVector) => ({ x: x + polygon.pos.x, - y: y + polygon.pos.y, - })) as SATVector[]; + y: y + polygon.pos.y + })) as SATVector[] // If the center of the circle is within the polygon, // the circle is not outside of the polygon completely. // so return false. if ( some( - points, - (point) => pointInCircle(point, circle) || pointOnCircle(point, circle), + points,point => pointInCircle(point, circle) || pointOnCircle(point, circle) ) ) { - return false; + return false } // If any line-segment of the polygon intersects the circle, @@ -176,15 +175,15 @@ export function circleOutsidePolygon( some(points, (end, index) => { const start: Vector = index ? points[index - 1] - : points[points.length - 1]; + : points[points.length - 1] - return intersectLineCircle({ start, end }, circle).length > 0; + return intersectLineCircle({ start, end }, circle).length > 0 }) ) { - return false; + return false } - return true; + return true } /** @@ -192,44 +191,44 @@ export function circleOutsidePolygon( */ export function intersectLineCircle( line: Pick, - { pos, r }: Pick, + { pos, r }: Pick ): Vector[] { - const v1 = { x: line.end.x - line.start.x, y: line.end.y - line.start.y }; - const v2 = { x: line.start.x - pos.x, y: line.start.y - pos.y }; - const b = (v1.x * v2.x + v1.y * v2.y) * -2; - const c = (v1.x * v1.x + v1.y * v1.y) * 2; - const d = Math.sqrt(b * b - (v2.x * v2.x + v2.y * v2.y - r * r) * c * 2); + const v1 = { x: line.end.x - line.start.x, y: line.end.y - line.start.y } + const v2 = { x: line.start.x - pos.x, y: line.start.y - pos.y } + const b = (v1.x * v2.x + v1.y * v2.y) * -2 + const c = (v1.x * v1.x + v1.y * v1.y) * 2 + const d = Math.sqrt(b * b - (v2.x * v2.x + v2.y * v2.y - r * r) * c * 2) if (isNaN(d)) { // no intercept - return []; + return [] } - const u1 = (b - d) / c; // these represent the unit distance of point one and two on the line - const u2 = (b + d) / c; - const results: Vector[] = []; // return array + const u1 = (b - d) / c // these represent the unit distance of point one and two on the line + const u2 = (b + d) / c + const results: Vector[] = [] // return array if (u1 <= 1 && u1 >= 0) { // add point if on the line segment - results.push({ x: line.start.x + v1.x * u1, y: line.start.y + v1.y * u1 }); + results.push({ x: line.start.x + v1.x * u1, y: line.start.y + v1.y * u1 }) } if (u2 <= 1 && u2 >= 0) { // second add point if on the line segment - results.push({ x: line.start.x + v1.x * u2, y: line.start.y + v1.y * u2 }); + results.push({ x: line.start.x + v1.x * u2, y: line.start.y + v1.y * u2 }) } - return results; + return results } /** * helper for intersectLineLineFast */ function isTurn(point1: Vector, point2: Vector, point3: Vector) { - const A = (point3.x - point1.x) * (point2.y - point1.y); - const B = (point2.x - point1.x) * (point3.y - point1.y); + const A = (point3.x - point1.x) * (point2.y - point1.y) + const B = (point2.x - point1.x) * (point3.y - point1.y) - return A > B + Number.EPSILON ? 1 : A + Number.EPSILON < B ? -1 : 0; + return A > B + Number.EPSILON ? 1 : A + Number.EPSILON < B ? -1 : 0 } /** @@ -238,14 +237,14 @@ function isTurn(point1: Vector, point2: Vector, point3: Vector) { */ export function intersectLineLineFast( line1: Pick, - line2: Pick, + line2: Pick ): boolean { return ( isTurn(line1.start, line2.start, line2.end) !== isTurn(line1.end, line2.start, line2.end) && isTurn(line1.start, line1.end, line2.start) !== isTurn(line1.start, line1.end, line2.end) - ); + ) } /** @@ -254,54 +253,54 @@ export function intersectLineLineFast( */ export function intersectLineLine( line1: Pick, - line2: Pick, + line2: Pick ): Vector | null { - const dX: number = line1.end.x - line1.start.x; - const dY: number = line1.end.y - line1.start.y; + const dX: number = line1.end.x - line1.start.x + const dY: number = line1.end.y - line1.start.y const determinant: number = - dX * (line2.end.y - line2.start.y) - (line2.end.x - line2.start.x) * dY; + dX * (line2.end.y - line2.start.y) - (line2.end.x - line2.start.x) * dY if (determinant === 0) { - return null; + return null } const lambda: number = ((line2.end.y - line2.start.y) * (line2.end.x - line1.start.x) + (line2.start.x - line2.end.x) * (line2.end.y - line1.start.y)) / - determinant; + determinant const gamma: number = ((line1.start.y - line1.end.y) * (line2.end.x - line1.start.x) + dX * (line2.end.y - line1.start.y)) / - determinant; + determinant // check if there is an intersection if (!(lambda >= 0 && lambda <= 1) || !(gamma >= 0 && gamma <= 1)) { - return null; + return null } - return { x: line1.start.x + lambda * dX, y: line1.start.y + lambda * dY }; + return { x: line1.start.x + lambda * dX, y: line1.start.y + lambda * dY } } export function intersectLinePolygon(line: Line, polygon: Polygon): Vector[] { - const results: Vector[] = []; + const results: Vector[] = [] forEach(polygon.calcPoints, (to: Vector, index: number) => { const from: Vector = index ? polygon.calcPoints[index - 1] - : polygon.calcPoints[polygon.calcPoints.length - 1]; + : polygon.calcPoints[polygon.calcPoints.length - 1] const side = { start: { x: from.x + polygon.pos.x, y: from.y + polygon.pos.y }, - end: { x: to.x + polygon.pos.x, y: to.y + polygon.pos.y }, - }; + end: { x: to.x + polygon.pos.x, y: to.y + polygon.pos.y } + } - const hit = intersectLineLine(line, side); + const hit = intersectLineLine(line, side) if (hit) { - results.push(hit); + results.push(hit) } - }); + }) - return results; + return results } diff --git a/src/model.ts b/src/model.ts index e20c956a..1a0f8499 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1,28 +1,37 @@ -import { BBox, default as RBush } from "rbush"; import { Circle as SATCircle, Polygon as SATPolygon, Response, - Vector as SATVector, -} from "sat"; + Vector as SATVector +} from "sat" -import { System } from "./system"; -import { Box } from "./bodies/box"; -import { Circle } from "./bodies/circle"; -import { Ellipse } from "./bodies/ellipse"; -import { Line } from "./bodies/line"; -import { Point } from "./bodies/point"; -import { Polygon } from "./bodies/polygon"; +import { System } from "./system" +import { Box } from "./bodies/box" +import { Circle } from "./bodies/circle" +import { Ellipse } from "./bodies/ellipse" +import { Line } from "./bodies/line" +import { Point } from "./bodies/point" +import { Polygon } from "./bodies/polygon" + +// version 4.0.0 1=1 copy +import RBush from "./rbush" export { Polygon as DecompPolygon, Point as DecompPoint, - isSimple, -} from "poly-decomp-es"; + isSimple +} from "poly-decomp-es" + +export interface BBox { + minX: number + minY: number + maxX: number + maxY: number +} -export { RBush, BBox, Response, SATVector, SATPolygon, SATCircle }; +export { RBush, Response, SATVector, SATPolygon, SATCircle } -export type CollisionCallback = (response: Response) => boolean | void; +export type CollisionCallback = (response: Response) => boolean | void /** * types @@ -33,7 +42,7 @@ export enum BodyType { Polygon = "Polygon", Box = "Box", Line = "Line", - Point = "Point", + Point = "Point" } /** @@ -45,7 +54,7 @@ export enum BodyGroup { Polygon = 0b00001000, Box = 0b00000100, Line = 0b00000010, - Point = 0b00000001, + Point = 0b00000001 } /** @@ -53,20 +62,20 @@ export enum BodyGroup { */ export type Leaf = TBody & { children?: Leaf[]; -}; +} /** * rbush data */ export interface ChildrenData { - children: Leaf[]; + children: Leaf[] } /** * for use of private function of sat.js */ export interface Data { - data: ChildrenData; + data: ChildrenData } /** @@ -76,69 +85,69 @@ export interface BodyOptions { /** * system.separate() doesn't move this body */ - isStatic?: boolean; + isStatic?: boolean /** * system.separate() doesn't trigger collision of this body */ - isTrigger?: boolean; + isTrigger?: boolean /** * is body offset centered for rotation purpouses */ - isCentered?: boolean; + isCentered?: boolean /** * body angle in radians use deg2rad to convert */ - angle?: number; + angle?: number /** * BHV padding for bounding box, preventing costly updates */ - padding?: number; + padding?: number /** * group for collision filtering */ - group?: number; + group?: number } /** * system.raycast(from, to) result */ export interface RaycastHit { - point: Vector; - body: TBody; + point: Vector + body: TBody } /** * potential vector */ export interface PotentialVector { - x?: number; - y?: number; + x?: number + y?: number } /** * x, y vector */ export interface Vector extends PotentialVector { - x: number; - y: number; + x: number + y: number } /** * for use of private function of sat.js */ export interface GetAABBAsBox { - getAABBAsBox(): { pos: Vector; w: number; h: number }; + getAABBAsBox(): { pos: Vector; w: number; h: number } } /** * generic body union type */ -export type Body = Point | Line | Ellipse | Circle | Box | Polygon; +export type Body = Point | Line | Ellipse | Circle | Box | Polygon /** * each body contains those regardless of type @@ -147,96 +156,101 @@ export interface BodyProps extends Required { /** * type of body */ - readonly type: BodyType; + readonly type: BodyType /** * faster for comparision, inner, type of body as number */ - readonly typeGroup: BodyGroup; + readonly typeGroup: BodyGroup /** * flag to show is it a convex body or non convex polygon */ - isConvex: boolean; + isConvex: boolean /** * bounding box cache, without padding */ - bbox: BBox; + bbox: BBox /** * each body may have offset from center */ - offset: SATVector; + offset: SATVector /** * collisions system reference */ - system?: System; + system?: System /** * was the body modified and needs update in the next checkCollision */ - dirty: boolean; + dirty: boolean /** * scale getter (x) */ - get scaleX(): number; + get scaleX(): number /** * scale getter (y = x for Circle) */ - get scaleY(): number; + get scaleY(): number + + /** + * update position BY MOVING FORWARD IN ANGLE DIRECTION + */ + move(speed: number, updateNow?: boolean): Circle | SATPolygon /** - * update position, and cached convexes positions + * update position BY TELEPORTING */ - setPosition(x: number, y: number, update?: boolean): Circle | SATPolygon; + setPosition(x: number, y: number, updateNow?: boolean): Circle | SATPolygon /** * for setting scale */ - setScale(x: number, y: number, update?: boolean): Circle | SATPolygon; + setScale(x: number, y: number, updateNow?: boolean): Circle | SATPolygon /** * for setting angle */ - setAngle(angle: number, update?: boolean): Circle | SATPolygon; + setAngle(angle: number, updateNow?: boolean): Circle | SATPolygon /** * for setting offset from center */ - setOffset(offset: Vector, update?: boolean): Circle | SATPolygon; + setOffset(offset: Vector, updateNow?: boolean): Circle | SATPolygon /** * draw the bounding box */ - drawBVH(context: CanvasRenderingContext2D): void; + drawBVH(context: CanvasRenderingContext2D): void /** * draw the collider */ - draw(context: CanvasRenderingContext2D): void; + draw(context: CanvasRenderingContext2D): void /** * return bounding box without padding */ - getAABBAsBBox(): BBox; + getAABBAsBBox(): BBox } export type SATTest< T extends {} = Circle | Polygon | SATPolygon, Y extends {} = Circle | Polygon | SATPolygon, -> = (bodyA: T, bodyB: Y, response: Response) => boolean; +> = (bodyA: T, bodyB: Y, response: Response) => boolean export type InTest = ( bodyA: TBody, - bodyB: TBody, -) => boolean; + bodyB: TBody +) => boolean export type TraverseFunction = ( child: Leaf, children: Leaf[], - index: number, -) => boolean | void; + index: number +) => boolean | void diff --git a/src/optimized.ts b/src/optimized.ts index 8f1b7f82..7c21c2d4 100644 --- a/src/optimized.ts +++ b/src/optimized.ts @@ -5,12 +5,12 @@ */ export const forEach = ( array: T[], - callback: (item: T, index: number) => void, + callback: (item: T, index: number) => void ): void => { for (let i = 0, l = array.length; i < l; i++) { - callback(array[i], i); + callback(array[i], i) } -}; +} /** * 20-90% faster than built-in Array.some function. @@ -19,16 +19,16 @@ export const forEach = ( */ export const some = ( array: T[], - callback: (item: T, index: number) => unknown, + callback: (item: T, index: number) => unknown ): boolean => { for (let i = 0, l = array.length; i < l; i++) { if (callback(array[i], i)) { - return true; + return true } } - return false; -}; + return false +} /** * 20-40% faster than built-in Array.every function. @@ -37,16 +37,16 @@ export const some = ( */ export const every = ( array: T[], - callback: (item: T, index: number) => unknown, + callback: (item: T, index: number) => unknown ): boolean => { for (let i = 0, l = array.length; i < l; i++) { if (!callback(array[i], i)) { - return false; + return false } } - return true; -}; + return true +} /** * 20-60% faster than built-in Array.filter function. @@ -55,20 +55,20 @@ export const every = ( */ export const filter = ( array: T[], - callback: (item: T, index: number) => unknown, + callback: (item: T, index: number) => unknown ): T[] => { - const output: T[] = []; + const output: T[] = [] for (let i = 0, l = array.length; i < l; i++) { - const item = array[i]; + const item = array[i] if (callback(item, i)) { - output.push(item); + output.push(item) } } - return output; -}; + return output +} /** * 20-70% faster than built-in Array.map @@ -77,14 +77,14 @@ export const filter = ( */ export const map = ( array: T[], - callback: (item: T, index: number) => Y, + callback: (item: T, index: number) => Y ): Y[] => { - const l = array.length; - const output = new Array(l); + const l = array.length + const output = new Array(l) for (let i = 0; i < l; i++) { - output[i] = callback(array[i], i); + output[i] = callback(array[i], i) } - return output; -}; + return output +} diff --git a/src/rbush.js b/src/rbush.js new file mode 100644 index 00000000..7a23e51f --- /dev/null +++ b/src/rbush.js @@ -0,0 +1,512 @@ +import quickselect from 'quickselect'; + +export default class RBush { + constructor(maxEntries = 9) { + // max entries in a node is 9 by default; min node fill is 40% for best performance + this._maxEntries = Math.max(4, maxEntries); + this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); + this.clear(); + } + + all() { + return this._all(this.data, []); + } + + search(bbox) { + let node = this.data; + const result = []; + + if (!intersects(bbox, node)) return result; + + const toBBox = this.toBBox; + const nodesToSearch = []; + + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? toBBox(child) : child; + + if (intersects(bbox, childBBox)) { + if (node.leaf) result.push(child); + else if (contains(bbox, childBBox)) this._all(child, result); + else nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + + return result; + } + + collides(bbox) { + let node = this.data; + + if (!intersects(bbox, node)) return false; + + const nodesToSearch = []; + while (node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const childBBox = node.leaf ? this.toBBox(child) : child; + + if (intersects(bbox, childBBox)) { + if (node.leaf || contains(bbox, childBBox)) return true; + nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + + return false; + } + + load(data) { + if (!(data && data.length)) return this; + + if (data.length < this._minEntries) { + for (let i = 0; i < data.length; i++) { + this.insert(data[i]); + } + return this; + } + + // recursively build the tree with the given data from scratch using OMT algorithm + let node = this._build(data.slice(), 0, data.length - 1, 0); + + if (!this.data.children.length) { + // save as is if tree is empty + this.data = node; + + } else if (this.data.height === node.height) { + // split root if trees have the same height + this._splitRoot(this.data, node); + + } else { + if (this.data.height < node.height) { + // swap trees if inserted one is bigger + const tmpNode = this.data; + this.data = node; + node = tmpNode; + } + + // insert the small tree into the large tree at appropriate level + this._insert(node, this.data.height - node.height - 1, true); + } + + return this; + } + + insert(item) { + if (item) this._insert(item, this.data.height - 1); + return this; + } + + clear() { + this.data = createNode([]); + return this; + } + + remove(item, equalsFn) { + if (!item) return this; + + let node = this.data; + const bbox = this.toBBox(item); + const path = []; + const indexes = []; + let i, parent, goingUp; + + // depth-first iterative tree traversal + while (node || path.length) { + + if (!node) { // go up + node = path.pop(); + parent = path[path.length - 1]; + i = indexes.pop(); + goingUp = true; + } + + if (node.leaf) { // check current node + const index = findItem(item, node.children, equalsFn); + + if (index !== -1) { + // item found, remove the item and condense tree upwards + node.children.splice(index, 1); + path.push(node); + this._condense(path); + return this; + } + } + + if (!goingUp && !node.leaf && contains(node, bbox)) { // go down + path.push(node); + indexes.push(i); + i = 0; + parent = node; + node = node.children[0]; + + } else if (parent) { // go right + i++; + node = parent.children[i]; + goingUp = false; + + } else node = null; // nothing found + } + + return this; + } + + toBBox(item) { return item; } + + compareMinX(a, b) { return a.minX - b.minX; } + compareMinY(a, b) { return a.minY - b.minY; } + + toJSON() { return this.data; } + + fromJSON(data) { + this.data = data; + return this; + } + + _all(node, result) { + const nodesToSearch = []; + while (node) { + if (node.leaf) result.push(...node.children); + else nodesToSearch.push(...node.children); + + node = nodesToSearch.pop(); + } + return result; + } + + _build(items, left, right, height) { + + const N = right - left + 1; + let M = this._maxEntries; + let node; + + if (N <= M) { + // reached leaf level; return leaf + node = createNode(items.slice(left, right + 1)); + calcBBox(node, this.toBBox); + return node; + } + + if (!height) { + // target height of the bulk-loaded tree + height = Math.ceil(Math.log(N) / Math.log(M)); + + // target number of root entries to maximize storage utilization + M = Math.ceil(N / Math.pow(M, height - 1)); + } + + node = createNode([]); + node.leaf = false; + node.height = height; + + // split the items into M mostly square tiles + + const N2 = Math.ceil(N / M); + const N1 = N2 * Math.ceil(Math.sqrt(M)); + + multiSelect(items, left, right, N1, this.compareMinX); + + for (let i = left; i <= right; i += N1) { + + const right2 = Math.min(i + N1 - 1, right); + + multiSelect(items, i, right2, N2, this.compareMinY); + + for (let j = i; j <= right2; j += N2) { + + const right3 = Math.min(j + N2 - 1, right2); + + // pack each entry recursively + node.children.push(this._build(items, j, right3, height - 1)); + } + } + + calcBBox(node, this.toBBox); + + return node; + } + + _chooseSubtree(bbox, node, level, path) { + while (true) { + path.push(node); + + if (node.leaf || path.length - 1 === level) break; + + let minArea = Infinity; + let minEnlargement = Infinity; + let targetNode; + + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + const area = bboxArea(child); + const enlargement = enlargedArea(bbox, child) - area; + + // choose entry with the least area enlargement + if (enlargement < minEnlargement) { + minEnlargement = enlargement; + minArea = area < minArea ? area : minArea; + targetNode = child; + + } else if (enlargement === minEnlargement) { + // otherwise choose one with the smallest area + if (area < minArea) { + minArea = area; + targetNode = child; + } + } + } + + node = targetNode || node.children[0]; + } + + return node; + } + + _insert(item, level, isNode) { + const bbox = isNode ? item : this.toBBox(item); + const insertPath = []; + + // find the best node for accommodating the item, saving all nodes along the path too + const node = this._chooseSubtree(bbox, this.data, level, insertPath); + + // put the item into the node + node.children.push(item); + extend(node, bbox); + + // split on node overflow; propagate upwards if necessary + while (level >= 0) { + if (insertPath[level].children.length > this._maxEntries) { + this._split(insertPath, level); + level--; + } else break; + } + + // adjust bboxes along the insertion path + this._adjustParentBBoxes(bbox, insertPath, level); + } + + // split overflowed node into two + _split(insertPath, level) { + const node = insertPath[level]; + const M = node.children.length; + const m = this._minEntries; + + this._chooseSplitAxis(node, m, M); + + const splitIndex = this._chooseSplitIndex(node, m, M); + + const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex)); + newNode.height = node.height; + newNode.leaf = node.leaf; + + calcBBox(node, this.toBBox); + calcBBox(newNode, this.toBBox); + + if (level) insertPath[level - 1].children.push(newNode); + else this._splitRoot(node, newNode); + } + + _splitRoot(node, newNode) { + // split root node + this.data = createNode([node, newNode]); + this.data.height = node.height + 1; + this.data.leaf = false; + calcBBox(this.data, this.toBBox); + } + + _chooseSplitIndex(node, m, M) { + let index; + let minOverlap = Infinity; + let minArea = Infinity; + + for (let i = m; i <= M - m; i++) { + const bbox1 = distBBox(node, 0, i, this.toBBox); + const bbox2 = distBBox(node, i, M, this.toBBox); + + const overlap = intersectionArea(bbox1, bbox2); + const area = bboxArea(bbox1) + bboxArea(bbox2); + + // choose distribution with minimum overlap + if (overlap < minOverlap) { + minOverlap = overlap; + index = i; + + minArea = area < minArea ? area : minArea; + + } else if (overlap === minOverlap) { + // otherwise choose distribution with minimum area + if (area < minArea) { + minArea = area; + index = i; + } + } + } + + return index || M - m; + } + + // sorts node children by the best axis for split + _chooseSplitAxis(node, m, M) { + const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX; + const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY; + const xMargin = this._allDistMargin(node, m, M, compareMinX); + const yMargin = this._allDistMargin(node, m, M, compareMinY); + + // if total distributions margin value is minimal for x, sort by minX, + // otherwise it's already sorted by minY + if (xMargin < yMargin) node.children.sort(compareMinX); + } + + // total margin of all possible split distributions where each node is at least m full + _allDistMargin(node, m, M, compare) { + node.children.sort(compare); + + const toBBox = this.toBBox; + const leftBBox = distBBox(node, 0, m, toBBox); + const rightBBox = distBBox(node, M - m, M, toBBox); + let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox); + + for (let i = m; i < M - m; i++) { + const child = node.children[i]; + extend(leftBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(leftBBox); + } + + for (let i = M - m - 1; i >= m; i--) { + const child = node.children[i]; + extend(rightBBox, node.leaf ? toBBox(child) : child); + margin += bboxMargin(rightBBox); + } + + return margin; + } + + _adjustParentBBoxes(bbox, path, level) { + // adjust bboxes along the given tree path + for (let i = level; i >= 0; i--) { + extend(path[i], bbox); + } + } + + _condense(path) { + // go through the path, removing empty nodes and updating bboxes + for (let i = path.length - 1, siblings; i >= 0; i--) { + if (path[i].children.length === 0) { + if (i > 0) { + siblings = path[i - 1].children; + siblings.splice(siblings.indexOf(path[i]), 1); + + } else this.clear(); + + } else calcBBox(path[i], this.toBBox); + } + } +} + +function findItem(item, items, equalsFn) { + if (!equalsFn) return items.indexOf(item); + + for (let i = 0; i < items.length; i++) { + if (equalsFn(item, items[i])) return i; + } + return -1; +} + +// calculate node's bbox from bboxes of its children +function calcBBox(node, toBBox) { + distBBox(node, 0, node.children.length, toBBox, node); +} + +// min bounding rectangle of node children from k to p-1 +function distBBox(node, k, p, toBBox, destNode) { + if (!destNode) destNode = createNode(null); + destNode.minX = Infinity; + destNode.minY = Infinity; + destNode.maxX = -Infinity; + destNode.maxY = -Infinity; + + for (let i = k; i < p; i++) { + const child = node.children[i]; + extend(destNode, node.leaf ? toBBox(child) : child); + } + + return destNode; +} + +function extend(a, b) { + a.minX = Math.min(a.minX, b.minX); + a.minY = Math.min(a.minY, b.minY); + a.maxX = Math.max(a.maxX, b.maxX); + a.maxY = Math.max(a.maxY, b.maxY); + return a; +} + +function compareNodeMinX(a, b) { return a.minX - b.minX; } +function compareNodeMinY(a, b) { return a.minY - b.minY; } + +function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); } +function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); } + +function enlargedArea(a, b) { + return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * + (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY)); +} + +function intersectionArea(a, b) { + const minX = Math.max(a.minX, b.minX); + const minY = Math.max(a.minY, b.minY); + const maxX = Math.min(a.maxX, b.maxX); + const maxY = Math.min(a.maxY, b.maxY); + + return Math.max(0, maxX - minX) * + Math.max(0, maxY - minY); +} + +function contains(a, b) { + return a.minX <= b.minX && + a.minY <= b.minY && + b.maxX <= a.maxX && + b.maxY <= a.maxY; +} + +function intersects(a, b) { + return b.minX <= a.maxX && + b.minY <= a.maxY && + b.maxX >= a.minX && + b.maxY >= a.minY; +} + +function createNode(children) { + return { + children, + height: 1, + leaf: true, + minX: Infinity, + minY: Infinity, + maxX: -Infinity, + maxY: -Infinity + }; +} + +// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; +// combines selection algorithm with binary divide & conquer approach + +function multiSelect(arr, left, right, n, compare) { + const stack = [left, right]; + + while (stack.length) { + right = stack.pop(); + left = stack.pop(); + + if (right - left <= n) continue; + + const mid = left + Math.ceil((right - left) / n / 2) * n; + quickselect(arr, mid, left, right, compare); + + stack.push(left, mid, mid, right); + } +} diff --git a/src/system.spec.js b/src/system.spec.js index 284eb311..cb6a41c5 100644 --- a/src/system.spec.js +++ b/src/system.spec.js @@ -1,5 +1,3 @@ -require("pixi-shim"); - const expectToBeNear = (value, check, tolerance = 1) => { expect(value).toBeGreaterThan(check - tolerance); expect(value).toBeLessThan(check + tolerance); diff --git a/src/system.ts b/src/system.ts index 6ec57e2b..65391826 100644 --- a/src/system.ts +++ b/src/system.ts @@ -1,31 +1,31 @@ -import { BaseSystem } from "./base-system"; -import { Line } from "./bodies/line"; -import { - ensureConvex, - intersectLineCircle, - intersectLinePolygon, -} from "./intersect"; import { BBox, Body, BodyGroup, - BodyType, CollisionCallback, RBush, RaycastHit, Response, SATVector, - Vector, -} from "./model"; -import { forEach, some } from "./optimized"; + Vector +} from "./model" import { canInteract, checkAInB, distance, getSATTest, notIntersectAABB, - returnTrue, -} from "./utils"; + returnTrue +} from "./utils" +import { + ensureConvex, + intersectLineCircle, + intersectLinePolygon +} from "./intersect" +import { forEach, some } from "./optimized" + +import { BaseSystem } from "./base-system" +import { Line } from "./bodies/line" /** * collision system @@ -34,23 +34,23 @@ export class System extends BaseSystem { /** * the last collision result */ - response: Response = new Response(); + response: Response = new Response() /** * for raycasting */ - protected ray!: Line; + protected ray!: Line /** * re-insert body into collision tree and update its bbox * every body can be part of only one system */ - insert(body: TBody): RBush { - const insertResult = super.insert(body); + insert(body: TBody): this { + const insertResult = super.insert(body) // set system for later body.system.updateBody(body) - body.system = this; + body.system = this - return insertResult; + return insertResult } /** @@ -58,8 +58,8 @@ export class System extends BaseSystem { */ separate(): void { forEach(this.all(), (body: TBody) => { - this.separateBody(body); - }); + this.separateBody(body) + }) } /** @@ -67,19 +67,19 @@ export class System extends BaseSystem { */ separateBody(body: TBody): void { if (body.isStatic || body.isTrigger) { - return; + return } - const offsets = { x: 0, y: 0 }; + const offsets = { x: 0, y: 0 } const addOffsets = ({ overlapV: { x, y } }: Response) => { - offsets.x += x; - offsets.y += y; - }; + offsets.x += x + offsets.y += y + } - this.checkOne(body, addOffsets); + this.checkOne(body, addOffsets) if (offsets.x || offsets.y) { - body.setPosition(body.x - offsets.x, body.y - offsets.y); + body.setPosition(body.x - offsets.x, body.y - offsets.y) } } @@ -89,24 +89,24 @@ export class System extends BaseSystem { checkOne( body: TBody, callback: CollisionCallback = returnTrue, - response = this.response, + response = this.response ): boolean { // no need to check static body collision if (body.isStatic) { - return false; + return false } - const bodies = this.search(body); + const bodies = this.search(body) const checkCollision = (candidate: TBody) => { if ( candidate !== body && this.checkCollision(body, candidate, response) ) { - return callback(response); + return callback(response) } - }; + } - return some(bodies, checkCollision); + return some(bodies, checkCollision) } /** @@ -115,13 +115,13 @@ export class System extends BaseSystem { checkArea( area: BBox, callback: CollisionCallback = returnTrue, - response = this.response, + response = this.response ): boolean { const checkOne = (body: TBody) => { - return this.checkOne(body, callback, response); - }; + return this.checkOne(body, callback, response) + } - return some(this.search(area), checkOne); + return some(this.search(area), checkOne) } /** @@ -129,13 +129,13 @@ export class System extends BaseSystem { */ checkAll( callback: CollisionCallback = returnTrue, - response = this.response, + response = this.response ): boolean { const checkOne = (body: TBody) => { - return this.checkOne(body, callback, response); - }; + return this.checkOne(body, callback, response) + } - return some(this.all(), checkOne); + return some(this.all(), checkOne) } /** @@ -144,10 +144,10 @@ export class System extends BaseSystem { checkCollision( bodyA: TBody, bodyB: TBody, - response = this.response, + response = this.response ): boolean { - const { bbox: bboxA } = bodyA; - const { bbox: bboxB } = bodyB; + const { bbox: bboxA } = bodyA + const { bbox: bboxB } = bodyB // assess the bodies real aabb without padding if ( !canInteract(bodyA, bodyB) || @@ -155,54 +155,54 @@ export class System extends BaseSystem { !bboxB || notIntersectAABB(bboxA, bboxB) ) { - return false; + return false } - const sat = getSATTest(bodyA, bodyB); + const sat = getSATTest(bodyA, bodyB) // 99% of cases if (bodyA.isConvex && bodyB.isConvex) { // always first clear response - response.clear(); + response.clear() - return sat(bodyA, bodyB, response); + return sat(bodyA, bodyB, response) } // more complex (non convex) cases - const convexBodiesA = ensureConvex(bodyA); - const convexBodiesB = ensureConvex(bodyB); + const convexBodiesA = ensureConvex(bodyA) + const convexBodiesB = ensureConvex(bodyB) - let overlapX = 0; - let overlapY = 0; - let collided = false; + let overlapX = 0 + let overlapY = 0 + let collided = false - forEach(convexBodiesA, (convexBodyA) => { - forEach(convexBodiesB, (convexBodyB) => { + forEach(convexBodiesA,convexBodyA => { + forEach(convexBodiesB,convexBodyB => { // always first clear response - response.clear(); + response.clear() if (sat(convexBodyA, convexBodyB, response)) { - collided = true; - overlapX += response.overlapV.x; - overlapY += response.overlapV.y; + collided = true + overlapX += response.overlapV.x + overlapY += response.overlapV.y } - }); - }); + }) + }) if (collided) { - const vector = new SATVector(overlapX, overlapY); - - response.a = bodyA; - response.b = bodyB; - response.overlapV.x = overlapX; - response.overlapV.y = overlapY; - response.overlapN = vector.normalize(); - response.overlap = vector.len(); - response.aInB = checkAInB(bodyA, bodyB); - response.bInA = checkAInB(bodyB, bodyA); + const vector = new SATVector(overlapX, overlapY) + + response.a = bodyA + response.b = bodyB + response.overlapV.x = overlapX + response.overlapV.y = overlapY + response.overlapN = vector.normalize() + response.overlap = vector.len() + response.aInB = checkAInB(bodyA, bodyB) + response.bInA = checkAInB(bodyB, bodyA) } - return collided; + return collided } /** @@ -211,42 +211,42 @@ export class System extends BaseSystem { raycast( start: Vector, end: Vector, - allow: (body: TBody, ray: TBody) => boolean = returnTrue, + allow: (body: TBody, ray: TBody) => boolean = returnTrue ): RaycastHit | null { - let minDistance = Infinity; - let result: RaycastHit | null = null; + let minDistance = Infinity + let result: RaycastHit | null = null if (!this.ray) { - this.ray = new Line(start, end, { isTrigger: true }); + this.ray = new Line(start, end, { isTrigger: true }) } else { - this.ray.start = start; - this.ray.end = end; + this.ray.start = start + this.ray.end = end } - this.insert(this.ray as TBody); + this.insert(this.ray as TBody) this.checkOne(this.ray as TBody, ({ b: body }) => { if (!allow(body, this.ray as TBody)) { - return false; + return false } const points: Vector[] = body.typeGroup === BodyGroup.Circle ? intersectLineCircle(this.ray, body) - : intersectLinePolygon(this.ray, body); + : intersectLinePolygon(this.ray, body) forEach(points, (point: Vector) => { - const pointDistance: number = distance(start, point); + const pointDistance: number = distance(start, point) if (pointDistance < minDistance) { - minDistance = pointDistance; - result = { point, body }; + minDistance = pointDistance + result = { point, body } } - }); - }); + }) + }) - this.remove(this.ray as TBody); + this.remove(this.ray as TBody) - return result; + return result } } diff --git a/src/types.d.ts b/src/types.d.ts index b8befe46..e7d9e06d 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,5 +1,5 @@ declare module "random-seed" { - export function create(name: string): { random(): number }; + export function create(name: string): { random(): number } } -declare module "pixi-shim"; +declare module "pixi-shim" diff --git a/src/utils.ts b/src/utils.ts index 889595ef..ff4707bd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,22 +1,5 @@ -import { Point as DecompPoint } from "poly-decomp-es"; -import { BBox } from "rbush"; -import { - Response, - testCircleCircle, - testCirclePolygon, - testPolygonCircle, - testPolygonPolygon, - Vector as SATVector, -} from "sat"; - -import { Polygon } from "./bodies/polygon"; -import { - circleInCircle, - circleInPolygon, - polygonInCircle, - polygonInPolygon, -} from "./intersect"; import { + BBox, Body, BodyGroup, BodyOptions, @@ -25,9 +8,26 @@ import { PotentialVector, SATPolygon, SATTest, - Vector, -} from "./model"; -import { forEach, map } from "./optimized"; + Vector +} from "./model" +import { + Response, + Vector as SATVector, + testCircleCircle, + testCirclePolygon, + testPolygonCircle, + testPolygonPolygon +} from "sat" +import { + circleInCircle, + circleInPolygon, + polygonInCircle, + polygonInPolygon +} from "./intersect" +import { forEach, map } from "./optimized" + +import { Point as DecompPoint } from "poly-decomp-es" +import { Polygon } from "./bodies/polygon" /* helpers for faster getSATTest() and checkAInB() */ @@ -39,46 +39,46 @@ const testMap = { inCircleCircle: circleInCircle, inCirclePolygon: circleInPolygon, inPolygonCircle: polygonInCircle, - inPolygonPolygon: polygonInPolygon, -}; + inPolygonPolygon: polygonInPolygon +} function createMap( bodyType: BodyType.Circle | BodyType.Polygon, - testType: "sat" | "in", + testType: "sat" | "in" ): Record { return Object.values(BodyType).reduce( - (result, type) => ({ + (result: Record, type: BodyType) => ({ ...result, [type]: type === BodyType.Circle ? testMap[`${testType}${bodyType}Circle`] - : testMap[`${testType}${bodyType}Polygon`], + : testMap[`${testType}${bodyType}Polygon`] }), - {} as Record, - ); + {} as Record + ) } -const circleSATFunctions = createMap(BodyType.Circle, "sat"); -const circleInFunctions = createMap(BodyType.Circle, "in"); -const polygonSATFunctions = createMap(BodyType.Polygon, "sat"); -const polygonInFunctions = createMap(BodyType.Polygon, "in"); +const circleSATFunctions = createMap(BodyType.Circle, "sat") +const circleInFunctions = createMap(BodyType.Circle, "in") +const polygonSATFunctions = createMap(BodyType.Polygon, "sat") +const polygonInFunctions = createMap(BodyType.Polygon, "in") -export const DEG2RAD = Math.PI / 180; +export const DEG2RAD = Math.PI / 180 -export const RAD2DEG = 180 / Math.PI; +export const RAD2DEG = 180 / Math.PI /** * convert from degrees to radians */ export function deg2rad(degrees: number) { - return degrees * DEG2RAD; + return degrees * DEG2RAD } /** * convert from radians to degrees */ export function rad2deg(radians: number) { - return radians * RAD2DEG; + return radians * RAD2DEG } /** @@ -87,21 +87,21 @@ export function rad2deg(radians: number) { export function createEllipse( radiusX: number, radiusY: number = radiusX, - step = 1, + step = 1 ): SATVector[] { - const steps: number = Math.PI * Math.hypot(radiusX, radiusY) * 2; - const length: number = Math.max(8, Math.ceil(steps / Math.max(1, step))); - const ellipse: SATVector[] = []; + const steps: number = Math.PI * Math.hypot(radiusX, radiusY) * 2 + const length: number = Math.max(8, Math.ceil(steps / Math.max(1, step))) + const ellipse: SATVector[] = [] for (let index = 0; index < length; index++) { - const value: number = (index / length) * 2 * Math.PI; - const x: number = Math.cos(value) * radiusX; - const y: number = Math.sin(value) * radiusY; + const value: number = (index / length) * 2 * Math.PI + const x: number = Math.cos(value) * radiusX + const y: number = Math.sin(value) * radiusY - ellipse.push(new SATVector(x, y)); + ellipse.push(new SATVector(x, y)) } - return ellipse; + return ellipse } /** @@ -112,8 +112,8 @@ export function createBox(width: number, height: number): SATVector[] { new SATVector(0, 0), new SATVector(width, 0), new SATVector(width, height), - new SATVector(0, height), - ]; + new SATVector(0, height) + ] } /** @@ -122,71 +122,71 @@ export function createBox(width: number, height: number): SATVector[] { export function ensureVectorPoint(point: PotentialVector = {}): SATVector { return point instanceof SATVector ? point - : new SATVector(point.x || 0, point.y || 0); + : new SATVector(point.x || 0, point.y || 0) } /** * ensure Vector points (for polygon) in counter-clockwise order */ export function ensurePolygonPoints( - points: PotentialVector[] = [], + points: PotentialVector[] = [] ): SATVector[] { - const polygonPoints: SATVector[] = map(points, ensureVectorPoint); + const polygonPoints: SATVector[] = map(points, ensureVectorPoint) - return clockwise(polygonPoints) ? polygonPoints.reverse() : polygonPoints; + return clockwise(polygonPoints) ? polygonPoints.reverse() : polygonPoints } /** * get distance between two Vector points */ export function distance(bodyA: Vector, bodyB: Vector): number { - const xDiff = bodyA.x - bodyB.x; - const yDiff = bodyA.y - bodyB.y; + const xDiff = bodyA.x - bodyB.x + const yDiff = bodyA.y - bodyB.y - return Math.hypot(xDiff, yDiff); + return Math.hypot(xDiff, yDiff) } /** * check [is clockwise] direction of polygon */ export function clockwise(points: Vector[]): boolean { - const length = points.length; - let sum = 0; + const length = points.length + let sum = 0 forEach(points, (v1, index) => { - const v2 = points[(index + 1) % length]; + const v2 = points[(index + 1) % length] - sum += (v2.x - v1.x) * (v2.y + v1.y); - }); + sum += (v2.x - v1.x) * (v2.y + v1.y) + }) - return sum > 0; + return sum > 0 } /** * used for all types of bodies in constructor */ export function extendBody(body: Body, options: BodyOptions = {}): void { - body.isStatic = !!options.isStatic; - body.isTrigger = !!options.isTrigger; - body.padding = options.padding || 0; - body.group = typeof options.group === "number" ? options.group : 0x7fffffff; + body.isStatic = !!options.isStatic + body.isTrigger = !!options.isTrigger + body.padding = options.padding || 0 + body.group = typeof options.group === "number" ? options.group : 0x7FFFFFFF if (body.typeGroup !== BodyGroup.Circle) { - body.isCentered = options.isCentered || false; + body.isCentered = options.isCentered || false } - body.setAngle(options.angle || 0); + body.setAngle(options.angle || 0) } /** * check if body moved outside of its padding */ export function bodyMoved(body: Body): boolean { - const { bbox, minX, minY, maxX, maxY } = body; + const { bbox, minX, minY, maxX, maxY } = body return ( bbox.minX < minX || bbox.minY < minY || bbox.maxX > maxX || bbox.maxY > maxY - ); + ) } /** @@ -198,14 +198,14 @@ export function notIntersectAABB(bodyA: BBox, bodyB: BBox): boolean { bodyB.minY > bodyA.maxY || bodyB.maxX < bodyA.minX || bodyB.maxY < bodyA.minY - ); + ) } /** * checks if two boxes intersect */ export function intersectAABB(bodyA: BBox, bodyB: BBox): boolean { - return !notIntersectAABB(bodyA, bodyB); + return !notIntersectAABB(bodyA, bodyB) } /** @@ -213,9 +213,9 @@ export function intersectAABB(bodyA: BBox, bodyB: BBox): boolean { */ export function canInteract(bodyA: Body, bodyB: Body): boolean { return ( - ((bodyA.group >> 16) & (bodyB.group & 0xffff) && - (bodyB.group >> 16) & (bodyA.group & 0xffff)) !== 0 - ); + ((bodyA.group >> 16) & (bodyB.group & 0xFFFF) && + (bodyB.group >> 16) & (bodyA.group & 0xFFFF)) !== 0 + ) } /** @@ -225,43 +225,43 @@ export function checkAInB(bodyA: Body, bodyB: Body): boolean { const check = bodyA.typeGroup === BodyGroup.Circle ? circleInFunctions - : polygonInFunctions; + : polygonInFunctions - return check[bodyB.type](bodyA, bodyB); + return check[bodyB.type](bodyA, bodyB) } /** * clone sat vector points array into vector points array */ export function clonePointsArray(points: SATVector[]): Vector[] { - return map(points, ({ x, y }: Vector) => ({ x, y })); + return map(points, ({ x, y }: Vector) => ({ x, y })) } /** * change format from SAT.js to poly-decomp */ export function mapVectorToArray( - { x, y }: Vector = { x: 0, y: 0 }, + { x, y }: Vector = { x: 0, y: 0 } ): DecompPoint { - return [x, y]; + return [x, y] } /** * change format from poly-decomp to SAT.js */ export function mapArrayToVector([x, y]: DecompPoint = [0, 0]): Vector { - return { x, y }; + return { x, y } } /** * given 2 bodies calculate vector of bounce assuming equal mass and they are circles */ export function getBounceDirection(body: Vector, collider: Vector): SATVector { - const v2 = new SATVector(collider.x - body.x, collider.y - body.y); - const v1 = new SATVector(body.x - collider.x, body.y - collider.y); - const len = v1.dot(v2.normalize()) * 2; + const v2 = new SATVector(collider.x - body.x, collider.y - body.y) + const v1 = new SATVector(body.x - collider.x, body.y - collider.y) + const len = v1.dot(v2.normalize()) * 2 - return new SATVector(v2.x * len - v1.x, v2.y * len - v1.y).normalize(); + return new SATVector(v2.x * len - v1.x, v2.y * len - v1.y).normalize() } /** @@ -271,9 +271,9 @@ export function getSATTest(bodyA: Body, bodyB: Body): SATTest { const check = bodyA.typeGroup === BodyGroup.Circle ? circleSATFunctions - : polygonSATFunctions; + : polygonSATFunctions - return check[bodyB.type]; + return check[bodyB.type] } /** @@ -286,25 +286,25 @@ export function dashLineTo( toX: number, toY: number, dash = 2, - gap = 4, + gap = 4 ): void { - const xDiff = toX - fromX; - const yDiff = toY - fromY; - const arc = Math.atan2(yDiff, xDiff); - const offsetX = Math.cos(arc); - const offsetY = Math.sin(arc); + const xDiff = toX - fromX + const yDiff = toY - fromY + const arc = Math.atan2(yDiff, xDiff) + const offsetX = Math.cos(arc) + const offsetY = Math.sin(arc) - let posX = fromX; - let posY = fromY; - let dist = Math.hypot(xDiff, yDiff); + let posX = fromX + let posY = fromY + let dist = Math.hypot(xDiff, yDiff) while (dist > 0) { - const step = Math.min(dist, dash); - context.moveTo(posX, posY); - context.lineTo(posX + offsetX * step, posY + offsetY * step); - posX += offsetX * (dash + gap); - posY += offsetY * (dash + gap); - dist -= dash + gap; + const step = Math.min(dist, dash) + context.moveTo(posX, posY) + context.lineTo(posX + offsetX * step, posY + offsetY * step) + posX += offsetX * (dash + gap) + posY += offsetY * (dash + gap) + dist -= dash + gap } } @@ -315,31 +315,31 @@ export function drawPolygon( context: CanvasRenderingContext2D, { pos, - calcPoints, + calcPoints }: Pick & { pos: Vector }, - isTrigger = false, + isTrigger = false ): void { - const lastPoint = calcPoints[calcPoints.length - 1]; - const fromX = pos.x + lastPoint.x; - const fromY = pos.y + lastPoint.y; + const lastPoint = calcPoints[calcPoints.length - 1] + const fromX = pos.x + lastPoint.x + const fromY = pos.y + lastPoint.y if (calcPoints.length === 1) { - context.arc(fromX, fromY, 1, 0, Math.PI * 2); + context.arc(fromX, fromY, 1, 0, Math.PI * 2) } else { - context.moveTo(fromX, fromY); + context.moveTo(fromX, fromY) } forEach(calcPoints, (point, index) => { - const toX = pos.x + point.x; - const toY = pos.y + point.y; + const toX = pos.x + point.x + const toY = pos.y + point.y if (isTrigger) { - const prev = calcPoints[index - 1] || lastPoint; - dashLineTo(context, pos.x + prev.x, pos.y + prev.y, toX, toY); + const prev = calcPoints[index - 1] || lastPoint + dashLineTo(context, pos.x + prev.x, pos.y + prev.y, toX, toY) } else { - context.lineTo(toX, toY); + context.lineTo(toX, toY) } - }); + }) } /** @@ -348,46 +348,46 @@ export function drawPolygon( export function drawBVH(context: CanvasRenderingContext2D, body: Body) { drawPolygon(context, { pos: { x: body.minX, y: body.minY }, - calcPoints: createBox(body.maxX - body.minX, body.maxY - body.minY), - }); + calcPoints: createBox(body.maxX - body.minX, body.maxY - body.minY) + }) } /** * clone response object returning new response with previous ones values */ export function cloneResponse(response: Response) { - const clone = new Response(); - const { a, b, overlap, overlapN, overlapV, aInB, bInA } = response; - clone.a = a; - clone.b = b; - clone.overlap = overlap; - clone.overlapN = overlapN.clone(); - clone.overlapV = overlapV.clone(); - clone.aInB = aInB; - clone.bInA = bInA; - - return clone; + const clone = new Response() + const { a, b, overlap, overlapN, overlapV, aInB, bInA } = response + clone.a = a + clone.b = b + clone.overlap = overlap + clone.overlapN = overlapN.clone() + clone.overlapV = overlapV.clone() + clone.aInB = aInB + clone.bInA = bInA + + return clone } /** * dummy fn used as default, for optimization */ export function returnTrue() { - return true; + return true } /** * for groups */ export function getGroup(group: number): number { - return Math.max(0, Math.min(group, 0x7fffffff)); + return Math.max(0, Math.min(group, 0x7FFFFFFF)) } /** * binary string to decimal number */ export function bin2dec(binary: string): number { - return Number(`0b${binary}`.replace(/\s/g, "")); + return Number(`0b${binary}`.replace(/\s/g, "")) } /** @@ -396,7 +396,7 @@ export function bin2dec(binary: string): number { * @param input - number or binary string */ export function ensureNumber(input: number | string): number { - return typeof input === "number" ? input : bin2dec(input); + return typeof input === "number" ? input : bin2dec(input) } /** @@ -407,7 +407,16 @@ export function ensureNumber(input: number | string): number { */ export function groupBits( category: number | string, - mask: number | string = category, + mask: number | string = category ) { - return (ensureNumber(category) << 16) | ensureNumber(mask); + return (ensureNumber(category) << 16) | ensureNumber(mask) +} + +export function move(body: Body, speed = 1, updateNow = true) { + if (!speed) { + return + } + const moveX = Math.cos(body.angle) * speed + const moveY = Math.sin(body.angle) * speed + body.setPosition(body.x + moveX, body.y + moveY, updateNow) } diff --git a/tsconfig.json b/tsconfig.json index 22f09923..b116a7ed 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "lib": ["es2017", "dom"], + "lib": ["ES2015", "ES2017.Object", "DOM"], "experimentalDecorators": true, "esModuleInterop": true, "strict": true, diff --git a/yarn.lock b/yarn.lock index f3041811..343dae63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,156 +10,159 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== dependencies: - "@babel/highlight" "^7.24.2" + "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.23.5": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.1.tgz#31c1f66435f2a9c329bb5716a6d6186c516c3742" - integrity sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA== +"@babel/compat-data@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.8.tgz#f9196455334c38d059ac8b1a16a51decda9d30d3" + integrity sha512-c4IM7OTg6k1Q+AJ153e2mc2QVTezTwnb4VzquwcyiEzGnW0Kedv4do/TrkU98qPeC5LNiMt/QXwIjzYXLBpyZg== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.3.tgz#568864247ea10fbd4eff04dda1e05f9e2ea985c3" - integrity sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ== + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.8.tgz#c24f83985214f599cee5fc26d393d9ab320342f4" + integrity sha512-6AWcmZC/MZCO0yKys4uhg5NlxL0ESF3K6IAaoQ+xSXvPyPyxNWRafP+GDbI88Oh68O7QkJgmEtedWPM9U0pZNg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.1" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.1" - "@babel/parser" "^7.24.1" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.24.8" + "@babel/helper-compilation-targets" "^7.24.8" + "@babel/helper-module-transforms" "^7.24.8" + "@babel/helpers" "^7.24.8" + "@babel/parser" "^7.24.8" + "@babel/template" "^7.24.7" + "@babel/traverse" "^7.24.8" + "@babel/types" "^7.24.8" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.1", "@babel/generator@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.1.tgz#e67e06f68568a4ebf194d1c6014235344f0476d0" - integrity sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A== +"@babel/generator@^7.24.8", "@babel/generator@^7.7.2": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.8.tgz#1802d6ac4d77a9199c75ae3eb6a08336e5d1d39a" + integrity sha512-47DG+6F5SzOi0uEvK4wMShmn5yY0mVjVJoWTphdY2B4Rx9wHgjK7Yhtr0ru6nE+sn0v38mzrWOlah0p/YlHHOQ== dependencies: - "@babel/types" "^7.24.0" + "@babel/types" "^7.24.8" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz#b607c3161cd9d1744977d4f97139572fe778c271" + integrity sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.24.8" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.22.15": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== - dependencies: - "@babel/types" "^7.24.0" - -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" - integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" - integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helpers@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.1.tgz#183e44714b9eba36c3038e442516587b1e0a1a94" - integrity sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg== - dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" - -"@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" +"@babel/helper-environment-visitor@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" + integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-function-name@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" + integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-hoist-variables@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" + integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-module-transforms@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.8.tgz#b1f2df4f96f3465b0d035b697ec86cb51ff348fe" + integrity sha512-m4vWKVqvkVAWLXfHCCfff2luJj86U+J0/x+0N3ArG/tP0Fq7zky2dYwMbtPmkc/oulkkbjdL3uWzuoBwQ8R00Q== + dependencies: + "@babel/helper-environment-visitor" "^7.24.7" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== + +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-split-export-declaration@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" + integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== + +"@babel/helpers@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.8.tgz#2820d64d5d6686cca8789dd15b074cd862795873" + integrity sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.8" + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" - integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.7", "@babel/parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.8.tgz#58a4dbbcad7eb1d48930524a3fd93d93e9084c6f" + integrity sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -197,11 +200,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" - integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" + integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -253,44 +256,44 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" - integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - -"@babel/traverse@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" - integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== - dependencies: - "@babel/code-frame" "^7.24.1" - "@babel/generator" "^7.24.1" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.1" - "@babel/types" "^7.24.0" + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c" + integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/template@^7.24.7", "@babel/template@^7.3.3": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" + integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.8.tgz#6c14ed5232b7549df3371d820fbd9abfcd7dfab7" + integrity sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.24.8" + "@babel/helper-environment-visitor" "^7.24.7" + "@babel/helper-function-name" "^7.24.7" + "@babel/helper-hoist-variables" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" + "@babel/parser" "^7.24.8" + "@babel/types" "^7.24.8" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.3.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.3.3": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.8.tgz#d51ffa9043b17d36622efa44e861a49e69e130a8" + integrity sha512-SkSBEHwwJRU52QEVZBmMBnE5Ux2/6WU1grdYyOhpbCNxbmJrDuDCphBzKZSO3taf0zztp+qkWlymE5tVL5l0TA== dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -298,6 +301,13 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" @@ -532,7 +542,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== @@ -551,9 +561,17 @@ "@jridgewell/trace-mapping" "^0.3.25" "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" @@ -563,10 +581,30 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jsonjoy.com/base64@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.2.tgz#cf8ea9dcb849b81c95f14fc0aaa151c6b54d2578" + integrity sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA== + +"@jsonjoy.com/json-pack@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz#ab59c642a2e5368e8bcfd815d817143d4f3035d0" + integrity sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg== + dependencies: + "@jsonjoy.com/base64" "^1.1.1" + "@jsonjoy.com/util" "^1.1.2" + hyperdyperid "^1.2.0" + thingies "^1.20.0" + +"@jsonjoy.com/util@^1.1.2": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.2.0.tgz#0fe9a92de72308c566ebcebe8b5a3f01d3149df2" + integrity sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg== + "@leichtgewicht/ip-codec@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" - integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + version "2.0.5" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" + integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== "@mapbox/node-pre-gyp@^1.0.0": version "1.0.11" @@ -593,6 +631,13 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@shikijs/core@1.10.3": + version "1.10.3" + resolved "https://registry.yarnpkg.com/@shikijs/core/-/core-1.10.3.tgz#f01763b36f08ad3d2ef46cea7e61858d9d9947d6" + integrity sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg== + dependencies: + "@types/hast" "^3.0.4" + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -612,6 +657,26 @@ dependencies: "@sinonjs/commons" "^3.0.0" +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@types/babel__core@^7.1.14": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" @@ -639,9 +704,9 @@ "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd" - integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" @@ -684,9 +749,9 @@ "@types/estree" "*" "@types/eslint@*": - version "8.56.6" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.6.tgz#d5dc16cac025d313ee101108ba5714ea10eb3ed0" - integrity sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A== + version "8.56.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.10.tgz#eb2370a73bf04a901eeba8f22595c7ee0f7eb58d" + integrity sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -697,9 +762,9 @@ integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": - version "4.17.43" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz#10d8444be560cb789c4735aea5eac6e5af45df54" - integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + version "4.19.5" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6" + integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg== dependencies: "@types/node" "*" "@types/qs" "*" @@ -723,6 +788,13 @@ dependencies: "@types/node" "*" +"@types/hast@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" + integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== + dependencies: + "@types/unist" "*" + "@types/html-minifier-terser@^6.0.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" @@ -764,11 +836,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== -"@types/mime@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45" - integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw== - "@types/mime@^1": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" @@ -781,24 +848,17 @@ dependencies: "@types/node" "*" -"@types/node@*": - version "20.11.30" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f" - integrity sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw== - dependencies: - undici-types "~5.26.4" - -"@types/node@^20.12.12": - version "20.12.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" - integrity sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw== +"@types/node@*", "@types/node@^20.14.10": + version "20.14.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a" + integrity sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ== dependencies: undici-types "~5.26.4" "@types/qs@*": - version "6.9.14" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.14.tgz#169e142bfe493895287bee382af6039795e9b75b" - integrity sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA== + version "6.9.15" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== "@types/range-parser@*": version "1.2.7" @@ -836,13 +896,13 @@ "@types/express" "*" "@types/serve-static@*", "@types/serve-static@^1.15.5": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033" - integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ== + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" - "@types/mime" "*" "@types/node" "*" + "@types/send" "*" "@types/sockjs@^0.3.36": version "0.3.36" @@ -856,10 +916,15 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== +"@types/unist@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20" + integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ== + "@types/ws@^8.5.10": - version "8.5.10" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" - integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== + version "8.5.11" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.11.tgz#90ad17b3df7719ce3e6bc32f83ff954d38656508" + integrity sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w== dependencies: "@types/node" "*" @@ -1034,15 +1099,22 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + +acorn-walk@^8.1.1: + version "8.3.3" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" + integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== + dependencies: + acorn "^8.11.0" -acorn@^8.7.1, acorn@^8.8.2: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== agent-base@6: version "6.0.2" @@ -1052,9 +1124,9 @@ agent-base@6: debug "4" agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" - integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== dependencies: debug "^4.3.4" @@ -1088,14 +1160,14 @@ ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.9.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: - fast-deep-equal "^3.1.1" + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.2.2" ansi-escapes@^4.2.1: version "4.3.2" @@ -1119,11 +1191,6 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-sequence-parser@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz#e0aa1cdcbc8f8bb0b5bca625aac41f5f056973cf" - integrity sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1169,6 +1236,11 @@ are-we-there-yet@^2.0.0: delegates "^1.0.0" readable-stream "^3.6.0" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -1176,11 +1248,21 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +async@^3.2.3: + version "3.2.5" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1307,22 +1389,22 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" -browserslist@^4.21.10, browserslist@^4.22.2: - version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.21.10, browserslist@^4.23.1: + version "4.23.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed" + integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" + caniuse-lite "^1.0.30001640" + electron-to-chromium "^1.4.820" node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + update-browserslist-db "^1.1.0" bs-logger@0.x: version "0.2.6" @@ -1399,12 +1481,12 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001587: - version "1.0.30001600" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz#93a3ee17a35aa6a9f0c6ef1b2ab49507d1ab9079" - integrity sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ== +caniuse-lite@^1.0.30001640: + version "1.0.30001642" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz#6aa6610eb24067c246d30c57f055a9d0a7f8d05f" + integrity sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA== -canvas@^2: +canvas@2.11.2, canvas@^2: version "2.11.2" resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860" integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== @@ -1422,7 +1504,7 @@ chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1472,9 +1554,9 @@ chownr@^2.0.0: integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== ci-info@^3.2.0: version "3.9.0" @@ -1482,9 +1564,9 @@ ci-info@^3.2.0: integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" - integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + version "1.3.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== clean-css@^5.2.2: version "5.3.3" @@ -1657,6 +1739,11 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -1705,9 +1792,9 @@ debug@2.6.9: ms "2.0.0" debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== dependencies: ms "2.1.2" @@ -1724,9 +1811,9 @@ decompress-response@^4.2.0: mimic-response "^2.0.0" dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deepmerge@^4.2.2: version "4.3.1" @@ -1879,10 +1966,17 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.668: - version "1.4.715" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz#bb16bcf2a3537962fccfa746b5c98c5f7404ff46" - integrity sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg== +ejs@^3.0.0: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + +electron-to-chromium@^1.4.820: + version "1.4.827" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz#76068ed1c71dd3963e1befc8ae815004b2da6a02" + integrity sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ== emittery@^0.13.1: version "0.13.1" @@ -1904,10 +1998,10 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -enhanced-resolve@^5.0.0, enhanced-resolve@^5.16.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz#65ec88778083056cb32487faa9aef82ed0864787" - integrity sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA== +enhanced-resolve@^5.0.0, enhanced-resolve@^5.17.0: + version "5.17.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz#d037603789dd9555b89aaec7eb78845c49089bc5" + integrity sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -1923,9 +2017,9 @@ entities@^4.4.0: integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== envinfo@^7.7.3: - version "7.11.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.1.tgz#2ffef77591057081b0129a8fd8cf6118da1b94e1" - integrity sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg== + version "7.13.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.13.0.tgz#81fbb81e5da35d74e814941aeab7c325a606fb31" + integrity sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q== error-ex@^1.3.1: version "1.3.2" @@ -1947,11 +2041,11 @@ es-errors@^1.3.0: integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-module-lexer@^1.2.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.2.tgz#ba1a62255ff9b41023aaf9bd08c016a5f1a3fef3" - integrity sha512-7nOqkomXZEaxUDJw21XZNtRk739QvrPSoZoRtbsEfcii00vdzZUh6zh1CQwHhrib8MdEtJfv5rJiGeb4KuV/vw== + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -escalade@^3.1.1: +escalade@^3.1.1, escalade@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== @@ -2110,6 +2204,11 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-sta resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" @@ -2129,10 +2228,17 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -2168,9 +2274,9 @@ follow-redirects@^1.0.0: integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + version "3.2.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" + integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -2275,15 +2381,16 @@ glob-to-regexp@^0.4.1: integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== glob@^10.3.7: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: version "7.2.3" @@ -2351,7 +2458,7 @@ has-unicode@^2.0.1: resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -2492,9 +2599,9 @@ https-proxy-agent@^5.0.0: debug "4" https-proxy-agent@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168" - integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== dependencies: agent-base "^7.0.2" debug "4" @@ -2509,6 +2616,11 @@ husky@^9.0.11: resolved "https://registry.yarnpkg.com/husky/-/husky-9.0.11.tgz#fc91df4c756050de41b3e478b2158b87c1e79af9" integrity sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw== +hyperdyperid@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" + integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -2565,9 +2677,9 @@ ipaddr.js@1.9.1: integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" - integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== is-arrayish@^0.2.1: version "0.2.1" @@ -2582,11 +2694,11 @@ is-binary-path@~2.1.0: binary-extensions "^2.0.0" is-core-module@^2.13.0: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + version "2.14.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" + integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" is-docker@^3.0.0: version "3.0.0" @@ -2693,9 +2805,9 @@ istanbul-lib-instrument@^5.0.4: semver "^6.3.0" istanbul-lib-instrument@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz#91655936cf7380e4e473383081e38478b69993b1" - integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== dependencies: "@babel/core" "^7.23.9" "@babel/parser" "^7.23.9" @@ -2729,15 +2841,25 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" - integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jake@^10.8.5: + version "10.9.1" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.1.tgz#8dc96b7fcc41cb19aa502af506da4e1d56f5e62b" + integrity sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -3180,11 +3302,6 @@ json5@^2.2.2, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" - integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== - kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -3196,9 +3313,9 @@ kleur@^3.0.3: integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== launch-editor@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.1.tgz#f259c9ef95cbc9425620bbbd14b468fcdb4ffe3c" - integrity sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw== + version "2.8.0" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.8.0.tgz#7255d90bdba414448e2138faa770a74f28451305" + integrity sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA== dependencies: picocolors "^1.0.0" shell-quote "^1.8.1" @@ -3213,6 +3330,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== + dependencies: + uc.micro "^2.0.0" + loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -3242,6 +3366,11 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -3249,18 +3378,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -"lru-cache@^9.1.1 || ^10.0.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== - lunr@^2.3.9: version "2.3.9" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" @@ -3280,7 +3397,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x: +make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -3292,10 +3409,22 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -marked@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" - integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== +markdown-it@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.0" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" + +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== media-typer@0.3.0: version "0.3.0" @@ -3303,10 +3432,13 @@ media-typer@0.3.0: integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== memfs@^4.6.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.8.0.tgz#0ea1ecb137219883c2e7c5139f4fa109935f7e39" - integrity sha512-fcs7trFxZlOMadmTw5nyfOwS3il9pr3y+6xzLfXNwmuR/D0i4wz6rJURxArAbcJDGalbpbMvQ/IFI0NojRZgRg== + version "4.9.3" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.9.3.tgz#41a3218065fe3911d9eba836250c8f4e43f816bc" + integrity sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA== dependencies: + "@jsonjoy.com/json-pack" "^1.0.3" + "@jsonjoy.com/util" "^1.1.2" + tree-dump "^1.0.1" tslib "^2.0.0" merge-descriptors@1.0.1: @@ -3325,18 +3457,23 @@ methods@~1.1.2: integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": +mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@^2.1.35, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" @@ -3364,17 +3501,24 @@ minimalistic-assert@^1.0.0: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.1, minimatch@^9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.4, minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" @@ -3395,10 +3539,10 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== minizlib@^2.1.1: version "2.1.2" @@ -3444,9 +3588,9 @@ multicast-dns@^7.2.5: thunky "^1.0.2" nan@^2.17.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" - integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== natural-compare@^1.4.0: version "1.4.0" @@ -3530,9 +3674,9 @@ nth-check@^2.0.1: boolbase "^1.0.0" nwsapi@^2.2.7: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + version "2.2.12" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" + integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== object-assign@^4.1.1: version "4.1.1" @@ -3540,9 +3684,9 @@ object-assign@^4.1.1: integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" @@ -3620,6 +3764,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + param-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" @@ -3678,12 +3827,12 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - lru-cache "^9.1.1 || ^10.0.0" + lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@0.1.7: @@ -3691,10 +3840,10 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -3729,10 +3878,10 @@ poly-decomp-es@^0.4.2: resolved "https://registry.yarnpkg.com/poly-decomp-es/-/poly-decomp-es-0.4.2.tgz#2b874984e6f1d0efa3a27d0b13bbf18904a58156" integrity sha512-akjZkaTeyfECMNkMqv0g9gFiU2HjpZ5ubJA/aczw1ILdgWQbv1OPwCi05/9JbY2GnGpjm9k85Jdbd/j/p/lg/g== -prettier@^3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" - integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== pretty-error@^4.0.0: version "4.0.0" @@ -3777,6 +3926,11 @@ psl@^1.1.33: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -3833,17 +3987,17 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -rbush@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf" - integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w== +rbush@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/rbush/-/rbush-4.0.0.tgz#0536f105aa9d6dc8c0f2be6363a09d474b41cad6" + integrity sha512-F5xw+166FYDZI6jEcz+sWEHL5/J+du3kQWkwqWrPKb6iVoLPZh+2KhTS4OoYqrw1v/RO1xQe6WsLwBvrUAlvXw== dependencies: quickselect "^2.0.0" react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== readable-stream@^2.0.1: version "2.3.8" @@ -3951,16 +4105,9 @@ rimraf@^3.0.2: glob "^7.1.3" rimraf@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" - integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== - dependencies: - glob "^10.3.7" - -rimraf@^5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.7.tgz#27bddf202e7d89cb2e0381656380d1734a854a74" - integrity sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg== + version "5.0.9" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.9.tgz#c3baa1b886eadc2ec7981a06a593c3d01134ffe9" + integrity sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA== dependencies: glob "^10.3.7" @@ -4034,11 +4181,9 @@ selfsigned@^2.4.1: node-forge "^1" semver@^5.3.0, semver@^6.0.0, semver@^6.3.0, semver@^6.3.1, semver@^7.3.4, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== send@0.18.0: version "0.18.0" @@ -4140,15 +4285,13 @@ shell-quote@^1.8.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -shiki@^0.14.7: - version "0.14.7" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.7.tgz#c3c9e1853e9737845f1d2ef81b31bcfb07056d4e" - integrity sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg== +shiki@^1.9.1: + version "1.10.3" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-1.10.3.tgz#2276fb21a07043b28c5b16001e6a04fef99dbb8f" + integrity sha512-eneCLncGuvPdTutJuLyUGS8QNPAVFO5Trvld2wgEq1e002mwctAhJKeMGWtWVXOIEzmlcLRqcgPSorR6AVzOmQ== dependencies: - ansi-sequence-parser "^1.1.0" - jsonc-parser "^3.2.0" - vscode-oniguruma "^1.7.0" - vscode-textmate "^8.0.0" + "@shikijs/core" "1.10.3" + "@types/hast" "^3.0.4" side-channel@^1.0.4: version "1.0.6" @@ -4403,9 +4546,9 @@ terser-webpack-plugin@^5.3.10: terser "^5.26.0" terser@^5.10.0, terser@^5.14.2, terser@^5.26.0: - version "5.29.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.29.2.tgz#c17d573ce1da1b30f21a877bffd5655dd86fdb35" - integrity sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw== + version "5.31.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.2.tgz#b5ca188107b706084dca82f988089fa6102eba11" + integrity sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -4421,6 +4564,11 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +thingies@^1.20.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1" + integrity sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g== + thunky@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" @@ -4454,9 +4602,9 @@ toidentifier@1.0.1: integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== tough-cookie@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" punycode "^2.1.1" @@ -4475,12 +4623,18 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -ts-jest@^29.1.3: - version "29.1.3" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.3.tgz#2bab16ba5ab0f4896684985f9618acc2cf1197e9" - integrity sha512-6L9qz3ginTd1NKhOxmkP0qU3FyKjj5CPoY+anszfVn6Pmv/RIKzhiMCsH7Yb7UvJR9I2A64rm4zQl531s2F1iw== +tree-dump@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.0.2.tgz#c460d5921caeb197bde71d0e9a7b479848c5b8ac" + integrity sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ== + +ts-jest@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.2.tgz#0d2387bb04d39174b20a05172a968f258aedff4d" + integrity sha512-sSW7OooaKT34AAngP6k1VS669a0HdLxkQZnlC7T76sckGCokXFnvJ3yRlQZGRTAoV5K19HfSgCiSwWOSIfcYlg== dependencies: bs-logger "0.x" + ejs "^3.0.0" fast-json-stable-stringify "2.x" jest-util "^29.0.0" json5 "^2.2.3" @@ -4500,15 +4654,34 @@ ts-loader@^9.5.1: semver "^7.3.4" source-map "^0.7.4" +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + tslib@^1.13.0, tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.0, tslib@^2.0.3: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== tslint@^6.1.3: version "6.1.3" @@ -4554,20 +4727,26 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typedoc@^0.25.13: - version "0.25.13" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.13.tgz#9a98819e3b2d155a6d78589b46fa4c03768f0922" - integrity sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ== +typedoc@^0.26.4: + version "0.26.4" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.26.4.tgz#7e83047369a29a710d429dac20996680cae9a314" + integrity sha512-FlW6HpvULDKgc3rK04V+nbFyXogPV88hurarDPOjuuB5HAwuAlrCMQ5NeH7Zt68a/ikOKu6Z/0hFXAeC9xPccQ== dependencies: lunr "^2.3.9" - marked "^4.3.0" - minimatch "^9.0.3" - shiki "^0.14.7" + markdown-it "^14.1.0" + minimatch "^9.0.5" + shiki "^1.9.1" + yaml "^2.4.5" + +typescript@^5: + version "5.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" + integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== -typescript@^4: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== undici-types@~5.26.4: version "5.26.5" @@ -4584,13 +4763,13 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.1.2" + picocolors "^1.0.1" uri-js@^4.2.2: version "4.4.1" @@ -4627,10 +4806,15 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + v8-to-istanbul@^9.0.1: - version "9.2.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" - integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" @@ -4641,16 +4825,6 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -vscode-oniguruma@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" - integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== - -vscode-textmate@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" - integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== - w3c-xmlserializer@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" @@ -4710,9 +4884,9 @@ webpack-cli@^5.1.4: webpack-merge "^5.7.3" webpack-dev-middleware@^7.1.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-7.1.1.tgz#29aefd73720a03889e1c5c8dd7e552c4d333d572" - integrity sha512-NmRVq4AvRQs66dFWyDR4GsFDJggtSi2Yn38MXLk0nffgF9n/AIP4TFBg2TQKYaRAN4sHuKOTiz9BnNCENDLEVA== + version "7.2.1" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz#2af00538b6e4eda05f5afdd5d711dbebc05958f7" + integrity sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA== dependencies: colorette "^2.0.10" memfs "^4.6.0" @@ -4771,10 +4945,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.91.0: - version "5.91.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9" - integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw== +webpack@^5.93.0: + version "5.93.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" + integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.5" @@ -4782,10 +4956,10 @@ webpack@^5.91.0: "@webassemblyjs/wasm-edit" "^1.12.1" "@webassemblyjs/wasm-parser" "^1.12.1" acorn "^8.7.1" - acorn-import-assertions "^1.9.0" + acorn-import-attributes "^1.9.5" browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.16.0" + enhanced-resolve "^5.17.0" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" @@ -4894,9 +5068,9 @@ write-file-atomic@^4.0.2: signal-exit "^3.0.7" ws@^8.16.0: - version "8.16.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" - integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== xml-name-validator@^5.0.0: version "5.0.0" @@ -4923,6 +5097,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^2.4.5: + version "2.4.5" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e" + integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg== + yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" @@ -4941,6 +5120,11 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"