diff --git a/dist/demo/demo.js b/dist/demo/demo.js index 1678a7a2..c0bad769 100644 --- a/dist/demo/demo.js +++ b/dist/demo/demo.js @@ -692,75 +692,6 @@ function removeDuplicatePoints(polygon, precision) { -/***/ }), - -/***/ "./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": @@ -3400,7 +3331,7 @@ Object.defineProperty(exports, "SATPolygon", ({ enumerable: true, get: function 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")); +const rbush_1 = __importDefault(__webpack_require__(/*! ./external/rbush */ "./src/external/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; } })); @@ -4809,10 +4740,99 @@ module.exports = Tank; /***/ }), -/***/ "./src/rbush.js": -/*!**********************!*\ - !*** ./src/rbush.js ***! - \**********************/ +/***/ "./src/external/quickselect.js": +/*!*************************************!*\ + !*** ./src/external/quickselect.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 */ }); + +/** + * Rearranges items so that all items in the [left, k] are the smallest. + * The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @template T + * @param {T[]} arr the array to partially sort (in place) + * @param {number} k middle index for partial sorting (as defined above) + * @param {number} [left=0] left index of the range to sort + * @param {number} [right=arr.length-1] right index + * @param {(a: T, b: T) => number} [compare = (a, b) => a - b] compare function + */ +function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) { + + while (right > left) { + if (right - left > 600) { + const n = right - left + 1; + const m = k - left + 1; + const z = Math.log(n); + const s = 0.5 * Math.exp(2 * z / 3); + const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); + const newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); + const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); + quickselect(arr, k, newLeft, newRight, compare); + } + + const t = arr[k]; + let i = left; + /** @type {number} */ + let 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; + } +} + +/** + * @template T + * @param {T[]} arr + * @param {number} i + * @param {number} j + */ +function swap(arr, i, j) { + const tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + +/** + * @template T + * @param {T} a + * @param {T} b + * @returns {number} + */ +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} + + +/***/ }), + +/***/ "./src/external/rbush.js": +/*!*******************************!*\ + !*** ./src/external/rbush.js ***! + \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; @@ -4820,7 +4840,7 @@ __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"); +/* harmony import */ var _quickselect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./quickselect */ "./src/external/quickselect.js"); class RBush { @@ -5328,7 +5348,7 @@ function multiSelect(arr, left, right, n, compare) { 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); + (0,_quickselect__WEBPACK_IMPORTED_MODULE_0__["default"])(arr, mid, left, right, compare); stack.push(left, mid, mid, right); } diff --git a/dist/external/quickselect.d.ts b/dist/external/quickselect.d.ts new file mode 100644 index 00000000..deea91da --- /dev/null +++ b/dist/external/quickselect.d.ts @@ -0,0 +1,12 @@ +/** + * Rearranges items so that all items in the [left, k] are the smallest. + * The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @template T + * @param {T[]} arr the array to partially sort (in place) + * @param {number} k middle index for partial sorting (as defined above) + * @param {number} [left=0] left index of the range to sort + * @param {number} [right=arr.length-1] right index + * @param {(a: T, b: T) => number} [compare = (a, b) => a - b] compare function + */ +export default function quickselect(arr: T[], k: number, left?: number | undefined, right?: number | undefined, compare?: ((a: T, b: T) => number) | undefined): void; diff --git a/dist/external/quickselect.js b/dist/external/quickselect.js new file mode 100644 index 00000000..1ca34c77 --- /dev/null +++ b/dist/external/quickselect.js @@ -0,0 +1,74 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = quickselect; +/** + * Rearranges items so that all items in the [left, k] are the smallest. + * The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @template T + * @param {T[]} arr the array to partially sort (in place) + * @param {number} k middle index for partial sorting (as defined above) + * @param {number} [left=0] left index of the range to sort + * @param {number} [right=arr.length-1] right index + * @param {(a: T, b: T) => number} [compare = (a, b) => a - b] compare function + */ +function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) { + while (right > left) { + if (right - left > 600) { + const n = right - left + 1; + const m = k - left + 1; + const z = Math.log(n); + const s = 0.5 * Math.exp(2 * z / 3); + const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); + const newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); + const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); + quickselect(arr, k, newLeft, newRight, compare); + } + const t = arr[k]; + let i = left; + /** @type {number} */ + let 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; + } +} +/** + * @template T + * @param {T[]} arr + * @param {number} i + * @param {number} j + */ +function swap(arr, i, j) { + const tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} +/** + * @template T + * @param {T} a + * @param {T} b + * @returns {number} + */ +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} diff --git a/dist/rbush.d.ts b/dist/external/rbush.d.ts similarity index 100% rename from dist/rbush.d.ts rename to dist/external/rbush.d.ts diff --git a/dist/rbush.js b/dist/external/rbush.js similarity index 99% rename from dist/rbush.js rename to dist/external/rbush.js index e2e58bf8..34347ef7 100644 --- a/dist/rbush.js +++ b/dist/external/rbush.js @@ -3,7 +3,7 @@ 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")); +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 diff --git a/dist/model.d.ts b/dist/model.d.ts index cbd8df5d..c2cd5063 100644 --- a/dist/model.d.ts +++ b/dist/model.d.ts @@ -6,7 +6,7 @@ import { Ellipse } from "./bodies/ellipse"; import { Line } from "./bodies/line"; import { Point } from "./bodies/point"; import { Polygon } from "./bodies/polygon"; -import RBush from "./rbush"; +import RBush from "./external/rbush"; export { Polygon as DecompPolygon, Point as DecompPoint, isSimple } from "poly-decomp-es"; export interface BBox { minX: number; diff --git a/dist/model.js b/dist/model.js index c5f35be0..c45d6360 100644 --- a/dist/model.js +++ b/dist/model.js @@ -10,7 +10,7 @@ Object.defineProperty(exports, "SATPolygon", { enumerable: true, get: function ( 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")); +const rbush_1 = __importDefault(require("./external/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; } }); diff --git a/docs/classes/RBush.html b/docs/classes/RBush.html index af87d37c..336d118e 100644 --- a/docs/classes/RBush.html +++ b/docs/classes/RBush.html @@ -1,4 +1,4 @@ -RBush | Detect-Collisions

Constructors

constructor +RBush | Detect-Collisions

Constructors

Properties

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[]

+

Constructors

  • Parameters

    • maxEntries: number = 9

    Returns RBush

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

    • 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

  • Returns RBush

  • Parameters

    • bbox: any

    Returns boolean

  • Parameters

    • a: any
    • b: any

    Returns number

  • Parameters

    • a: any
    • b: any

    Returns number

  • Parameters

    • data: any

    Returns RBush

  • Parameters

    • item: any

    Returns RBush

  • Parameters

    • data: any

    Returns RBush

  • Parameters

    • item: any
    • equalsFn: any

    Returns RBush

  • Parameters

    • bbox: any

    Returns any[]

  • Parameters

    • item: any

    Returns any

  • Returns any

diff --git a/docs/classes/System.html b/docs/classes/System.html index 46585742..8eaeac28 100644 --- a/docs/classes/System.html +++ b/docs/classes/System.html @@ -47,13 +47,13 @@ traverse update updateBody -

Constructors

Properties

_maxEntries: number
_minEntries: number
ray: Line

for raycasting

+

Constructors

  • Type Parameters

    Parameters

    • maxEntries: number = 9

    Returns System<TBody>

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 all bodies collisions with callback

    +

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

  • Returns System<TBody>

  • 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

    • context: CanvasRenderingContext2D

    Returns void

  • Parameters

    • data: any

    Returns System<TBody>

  • 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

  • raycast to get collider of ray from start to end

    +

    Parameters

    Returns this

  • Parameters

    • data: any

    Returns System<TBody>

  • remove body aabb from collision tree

    -

    Parameters

    Returns this

  • Parameters

    • bbox: any

    Returns any[]

  • 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 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/demo.js b/docs/demo/demo.js index 1678a7a2..c0bad769 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -692,75 +692,6 @@ function removeDuplicatePoints(polygon, precision) { -/***/ }), - -/***/ "./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": @@ -3400,7 +3331,7 @@ Object.defineProperty(exports, "SATPolygon", ({ enumerable: true, get: function 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")); +const rbush_1 = __importDefault(__webpack_require__(/*! ./external/rbush */ "./src/external/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; } })); @@ -4809,10 +4740,99 @@ module.exports = Tank; /***/ }), -/***/ "./src/rbush.js": -/*!**********************!*\ - !*** ./src/rbush.js ***! - \**********************/ +/***/ "./src/external/quickselect.js": +/*!*************************************!*\ + !*** ./src/external/quickselect.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 */ }); + +/** + * Rearranges items so that all items in the [left, k] are the smallest. + * The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @template T + * @param {T[]} arr the array to partially sort (in place) + * @param {number} k middle index for partial sorting (as defined above) + * @param {number} [left=0] left index of the range to sort + * @param {number} [right=arr.length-1] right index + * @param {(a: T, b: T) => number} [compare = (a, b) => a - b] compare function + */ +function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) { + + while (right > left) { + if (right - left > 600) { + const n = right - left + 1; + const m = k - left + 1; + const z = Math.log(n); + const s = 0.5 * Math.exp(2 * z / 3); + const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); + const newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); + const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); + quickselect(arr, k, newLeft, newRight, compare); + } + + const t = arr[k]; + let i = left; + /** @type {number} */ + let 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; + } +} + +/** + * @template T + * @param {T[]} arr + * @param {number} i + * @param {number} j + */ +function swap(arr, i, j) { + const tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + +/** + * @template T + * @param {T} a + * @param {T} b + * @returns {number} + */ +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} + + +/***/ }), + +/***/ "./src/external/rbush.js": +/*!*******************************!*\ + !*** ./src/external/rbush.js ***! + \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; @@ -4820,7 +4840,7 @@ __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"); +/* harmony import */ var _quickselect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./quickselect */ "./src/external/quickselect.js"); class RBush { @@ -5328,7 +5348,7 @@ function multiSelect(arr, left, right, n, compare) { 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); + (0,_quickselect__WEBPACK_IMPORTED_MODULE_0__["default"])(arr, mid, left, right, compare); stack.push(left, mid, mid, right); } diff --git a/package.json b/package.json index 4f977ea3..975bdb9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "detect-collisions", - "version": "9.9.0", + "version": "9.9.1", "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", @@ -9,7 +9,13 @@ "test": "jest --silent --verbose --forceExit", "dev": "webpack serve --port 4200", "amend": "npm run precommit;git commit -a --am --no-edit", - "prebuild": "rm -rf dist", + "use-latest-quickselect-macos": "sed -i '' -e \"s_'quickselect'_'./quickselect'_g\" src/external/rbush.js", + "use-latest-quickselect-linux": "sed -i -r \"s_'quickselect'_'./quickselect'_g\" src/external/rbush.js", + "use-latest-quickselect": "npm run use-latest-quickselect-macos || npm run use-latest-quickselect-linux", + "copy-rbush": "cp node_modules/rbush/index.js src/external/rbush.js", + "copy-quickselect": "cp node_modules/quickselect/index.js src/external/quickselect.js", + "copy-npm-modules": "npm run copy-rbush && npm run copy-quickselect && npm run use-latest-quickselect", + "prebuild": "rm -rf dist && npm run copy-npm-modules", "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", @@ -76,11 +82,11 @@ "jest": "^29.7.0", "pixi-shim": "^2.5.3", "prettier": "^3.3.3", + "quickselect": "^3.0.0", "random-seed": "^0.3.0", "tinybench": "^2.8.0", "ts-jest": "^29.2.2", "ts-loader": "^9.5.1", - "ts-node": "^10.9.2", "tslint": "^6.1.3", "typedoc": "^0.26.4", "typescript": "^5", diff --git a/src/external/quickselect.js b/src/external/quickselect.js new file mode 100644 index 00000000..64b48249 --- /dev/null +++ b/src/external/quickselect.js @@ -0,0 +1,74 @@ + +/** + * Rearranges items so that all items in the [left, k] are the smallest. + * The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @template T + * @param {T[]} arr the array to partially sort (in place) + * @param {number} k middle index for partial sorting (as defined above) + * @param {number} [left=0] left index of the range to sort + * @param {number} [right=arr.length-1] right index + * @param {(a: T, b: T) => number} [compare = (a, b) => a - b] compare function + */ +export default function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) { + + while (right > left) { + if (right - left > 600) { + const n = right - left + 1; + const m = k - left + 1; + const z = Math.log(n); + const s = 0.5 * Math.exp(2 * z / 3); + const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1); + const newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); + const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); + quickselect(arr, k, newLeft, newRight, compare); + } + + const t = arr[k]; + let i = left; + /** @type {number} */ + let 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; + } +} + +/** + * @template T + * @param {T[]} arr + * @param {number} i + * @param {number} j + */ +function swap(arr, i, j) { + const tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + +/** + * @template T + * @param {T} a + * @param {T} b + * @returns {number} + */ +function defaultCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} diff --git a/src/rbush.js b/src/external/rbush.js similarity index 99% rename from src/rbush.js rename to src/external/rbush.js index 7a23e51f..3a532882 100644 --- a/src/rbush.js +++ b/src/external/rbush.js @@ -1,4 +1,4 @@ -import quickselect from 'quickselect'; +import quickselect from './quickselect'; export default class RBush { constructor(maxEntries = 9) { diff --git a/src/model.ts b/src/model.ts index 1a0f8499..29dce49f 100644 --- a/src/model.ts +++ b/src/model.ts @@ -14,7 +14,7 @@ import { Point } from "./bodies/point" import { Polygon } from "./bodies/polygon" // version 4.0.0 1=1 copy -import RBush from "./rbush" +import RBush from "./external/rbush" export { Polygon as DecompPolygon, diff --git a/yarn.lock b/yarn.lock index 343dae63..48bb0b79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -301,13 +301,6 @@ 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" @@ -542,7 +535,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": +"@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== @@ -565,14 +558,6 @@ 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" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -657,26 +642,6 @@ 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" @@ -1104,14 +1069,7 @@ acorn-import-attributes@^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.11.0, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2: +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== @@ -1236,11 +1194,6 @@ 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" @@ -1739,11 +1692,6 @@ 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" @@ -3397,7 +3345,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x, make-error@^1.1.1: +make-error@1.x: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -3958,6 +3906,11 @@ quickselect@^2.0.0: resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== +quickselect@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-3.0.0.tgz#a37fc953867d56f095a20ac71c6d27063d2de603" + integrity sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g== + random-seed@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/random-seed/-/random-seed-0.3.0.tgz#d945f2e1f38f49e8d58913431b8bf6bb937556cd" @@ -4654,25 +4607,6 @@ 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" @@ -4806,11 +4740,6 @@ 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.3.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" @@ -5120,11 +5049,6 @@ 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"