@gridworkjs/quadtree 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,46 +6,44 @@
6
6
 
7
7
  <p align="center">quadtree spatial index for sparse, uneven point and region data</p>
8
8
 
9
- ## install
9
+ ## Install
10
10
 
11
11
  ```
12
12
  npm install @gridworkjs/quadtree
13
13
  ```
14
14
 
15
- ## usage
15
+ ## Usage
16
+
17
+ A 2D game where entities spawn and despawn dynamically. The quadtree tracks their positions so you can efficiently query who's nearby:
16
18
 
17
19
  ```js
18
20
  import { createQuadtree } from '@gridworkjs/quadtree'
19
21
  import { point, rect, bounds } from '@gridworkjs/core'
20
22
 
21
- // create a quadtree with a bounds accessor
22
- const tree = createQuadtree(item => bounds(item.position))
23
-
24
- // insert items - any shape, the accessor extracts bounds
25
- tree.insert({ id: 1, position: point(10, 20) })
26
- tree.insert({ id: 2, position: point(50, 60) })
27
- tree.insert({ id: 3, position: rect(70, 70, 90, 90) })
23
+ const entities = createQuadtree(e => bounds(e.position))
28
24
 
29
- // search for items intersecting a region
30
- tree.search({ minX: 0, minY: 0, maxX: 55, maxY: 65 })
31
- // => [{ id: 1, ... }, { id: 2, ... }]
25
+ // entities come and go at arbitrary positions
26
+ entities.insert({ name: 'player', position: point(100, 200) })
27
+ const goblin = { name: 'goblin', position: point(120, 210) }
28
+ entities.insert(goblin)
29
+ entities.insert({ name: 'chest', position: point(400, 50) })
30
+ entities.insert({ name: 'trap', position: rect(110, 190, 130, 220) })
32
31
 
33
- // also accepts geometry objects as queries
34
- tree.search(rect(0, 0, 55, 65))
32
+ // who's in the player's field of view?
33
+ entities.search(rect(50, 150, 200, 300))
34
+ // => [player, goblin, trap]
35
35
 
36
- // find nearest neighbors
37
- tree.nearest({ x: 12, y: 22 }, 2)
38
- // => [{ id: 1, ... }, { id: 2, ... }]
36
+ // what's closest to the goblin for it to target?
37
+ entities.nearest({ x: 120, y: 210 }, 2)
38
+ // => [goblin, player]
39
39
 
40
- // remove by identity
41
- tree.remove(item)
42
-
43
- tree.size // number of items
44
- tree.bounds // current root bounds
45
- tree.clear()
40
+ // entity defeated - remove it (by reference)
41
+ entities.remove(goblin)
46
42
  ```
47
43
 
48
- ## options
44
+ Quadtrees handle sparse, uneven data well. Entities can cluster in one corner or spread across the whole map - the tree adapts its subdivision to match.
45
+
46
+ ## Options
49
47
 
50
48
  ```js
51
49
  createQuadtree(accessor, {
@@ -93,6 +91,6 @@ Number of items in the tree.
93
91
 
94
92
  Current root bounds, or `null` if empty and no fixed bounds were set.
95
93
 
96
- ## license
94
+ ## License
97
95
 
98
96
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gridworkjs/quadtree",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "quadtree spatial index for sparse, uneven point and region data",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/quadtree.js CHANGED
@@ -166,6 +166,19 @@ function growToContain(root, target) {
166
166
  return root
167
167
  }
168
168
 
169
+ function validateAccessorBounds(b) {
170
+ if (b === null || typeof b !== 'object') {
171
+ throw new Error('accessor must return a bounds object')
172
+ }
173
+ if (!Number.isFinite(b.minX) || !Number.isFinite(b.minY) ||
174
+ !Number.isFinite(b.maxX) || !Number.isFinite(b.maxY)) {
175
+ throw new Error('accessor returned non-finite bounds')
176
+ }
177
+ if (b.minX > b.maxX || b.minY > b.maxY) {
178
+ throw new Error('accessor returned inverted bounds (minX > maxX or minY > maxY)')
179
+ }
180
+ }
181
+
169
182
  function normalizeBounds(input) {
170
183
  if (input != null && typeof input === 'object' &&
171
184
  'minX' in input && 'minY' in input && 'maxX' in input && 'maxY' in input) {
@@ -263,6 +276,7 @@ export function createQuadtree(accessor, options = {}) {
263
276
 
264
277
  insert(item) {
265
278
  const itemBounds = accessor(item)
279
+ validateAccessorBounds(itemBounds)
266
280
  const entry = { item, bounds: itemBounds }
267
281
 
268
282
  if (!root) {
@@ -286,6 +300,7 @@ export function createQuadtree(accessor, options = {}) {
286
300
  remove(item) {
287
301
  if (!root) return false
288
302
  const itemBounds = accessor(item)
303
+ validateAccessorBounds(itemBounds)
289
304
  const removed = removeEntry(root, item, itemBounds)
290
305
  if (removed) size--
291
306
  return removed