123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- import {math} from './math.mjs';
- export const spatial_hash_grid = (() => {
- class SpatialHashGrid {
- constructor(bounds, dimensions) {
- const [x, y] = dimensions;
- this._cells = [...Array(x)].map(_ => [...Array(y)].map(_ => (null)));
- this._dimensions = dimensions;
- this._bounds = bounds;
- this._queryIds = 0;
- }
-
- _GetCellIndex(position) {
- const x = math.sat((position[0] - this._bounds[0][0]) / (
- this._bounds[1][0] - this._bounds[0][0]));
- const y = math.sat((position[1] - this._bounds[0][1]) / (
- this._bounds[1][1] - this._bounds[0][1]));
-
- const xIndex = Math.floor(x * (this._dimensions[0] - 1));
- const yIndex = Math.floor(y * (this._dimensions[1] - 1));
-
- return [xIndex, yIndex];
- }
-
- NewClient(position, dimensions) {
- const client = {
- position: position,
- dimensions: dimensions,
- _cells: {
- min: null,
- max: null,
- nodes: null,
- },
- _queryId: -1,
- };
-
- this._Insert(client);
-
- return client;
- }
-
- UpdateClient(client) {
- const [x, y] = client.position;
- const [w, h] = client.dimensions;
-
- const i1 = this._GetCellIndex([x - w / 2, y - h / 2]);
- const i2 = this._GetCellIndex([x + w / 2, y + h / 2]);
-
- if (client._cells.min[0] == i1[0] &&
- client._cells.min[1] == i1[1] &&
- client._cells.max[0] == i2[0] &&
- client._cells.max[1] == i2[1]) {
- return;
- }
-
- this.Remove(client);
- this._Insert(client);
- }
-
- FindNear(position, bounds) {
- const [x, y] = position;
- const [w, h] = bounds;
-
- const i1 = this._GetCellIndex([x - w / 2, y - h / 2]);
- const i2 = this._GetCellIndex([x + w / 2, y + h / 2]);
-
- const clients = [];
- const queryId = this._queryIds++;
-
- for (let x = i1[0], xn = i2[0]; x <= xn; ++x) {
- for (let y = i1[1], yn = i2[1]; y <= yn; ++y) {
- let head = this._cells[x][y];
-
- while (head) {
- const v = head.client;
- head = head.next;
-
- if (v._queryId != queryId) {
- v._queryId = queryId;
- clients.push(v);
- }
- }
- }
- }
- return clients;
- }
-
- _Insert(client) {
- const [x, y] = client.position;
- const [w, h] = client.dimensions;
-
- const i1 = this._GetCellIndex([x - w / 2, y - h / 2]);
- const i2 = this._GetCellIndex([x + w / 2, y + h / 2]);
-
- const nodes = [];
-
- for (let x = i1[0], xn = i2[0]; x <= xn; ++x) {
- nodes.push([]);
-
- for (let y = i1[1], yn = i2[1]; y <= yn; ++y) {
- const xi = x - i1[0];
-
- const head = {
- next: null,
- prev: null,
- client: client,
- };
-
- nodes[xi].push(head);
-
- head.next = this._cells[x][y];
- if (this._cells[x][y]) {
- this._cells[x][y].prev = head;
- }
-
- this._cells[x][y] = head;
- }
- }
-
- client._cells.min = i1;
- client._cells.max = i2;
- client._cells.nodes = nodes;
- }
-
- Remove(client) {
- const i1 = client._cells.min;
- const i2 = client._cells.max;
-
- for (let x = i1[0], xn = i2[0]; x <= xn; ++x) {
- for (let y = i1[1], yn = i2[1]; y <= yn; ++y) {
- const xi = x - i1[0];
- const yi = y - i1[1];
- const node = client._cells.nodes[xi][yi];
-
- if (node.next) {
- node.next.prev = node.prev;
- }
- if (node.prev) {
- node.prev.next = node.next;
- }
-
- if (!node.prev) {
- this._cells[x][y] = node.next;
- }
- }
- }
-
- client._cells.min = null;
- client._cells.max = null;
- client._cells.nodes = null;
- }
- }
- return {
- SpatialHashGrid: SpatialHashGrid,
- };
- })();
|