Files
archify-vscode-ext/vendor/archify/renderers/shared/spatial-grid.mjs
T
root-at-skicandClaude Opus 5.5 22815a9940 Archify Diagram Viewer 0.1.0
VS Code extension that previews Archify diagrams from their JSON sources
(live, as you type) and opens rendered Archify HTML in a viewer tab.
Bundles the Archify 3.0.1 renderer and runs it on VS Code's Node runtime.
Adds validation diagnostics, JSON schema help, source-link navigation,
export saving, render-to-file and open-in-browser commands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 12:44:15 +03:00

67 lines
2.4 KiB
JavaScript

/** Uniform spatial grid for "which items can this box reach" queries (#8). */
// A cell box wider than this is not worth walking: the query returns every
// inserted item instead, which stays a superset of what the box reaches.
const DEFAULT_MAX_CELLS = 4096;
export function createSpatialGrid(cellSize, { maxCells = DEFAULT_MAX_CELLS } = {}) {
const buckets = new Map();
const items = [];
// Items whose own box cannot be walked are candidates for every query.
const overflow = [];
const keyOf = (x, y) => x + ':' + y;
const rangeOf = (box) => ({
x0: Math.floor(box.minX / cellSize), x1: Math.floor(box.maxX / cellSize),
y0: Math.floor(box.minY / cellSize), y1: Math.floor(box.maxY / cellSize),
});
// Finite coordinates can still land outside the safe-integer range, where
// incrementing an index no longer advances it; and a legal coordinate can
// name more cells than the grid is worth. Both cases stay out of the buckets
// and are answered by the item list, so they never hang or allocate.
const walkable = (range) => Number.isSafeInteger(range.x0) && Number.isSafeInteger(range.x1)
&& Number.isSafeInteger(range.y0) && Number.isSafeInteger(range.y1)
&& (range.x1 - range.x0 + 1) * (range.y1 - range.y0 + 1) <= maxCells;
return {
insert(box, item) {
items.push(item);
const range = rangeOf(box);
if (!walkable(range)) {
overflow.push(item);
return;
}
for (let x = range.x0; x <= range.x1; x += 1) {
for (let y = range.y0; y <= range.y1; y += 1) {
const key = keyOf(x, y);
let bucket = buckets.get(key);
if (!bucket) { bucket = []; buckets.set(key, bucket); }
bucket.push(item);
}
}
},
query(box) {
const range = rangeOf(box);
if (!walkable(range)) return items.slice();
const seen = new Set();
const found = [];
for (let x = range.x0; x <= range.x1; x += 1) {
for (let y = range.y0; y <= range.y1; y += 1) {
const bucket = buckets.get(keyOf(x, y));
if (!bucket) continue;
for (const item of bucket) {
if (seen.has(item)) continue;
seen.add(item);
found.push(item);
}
}
}
for (const item of overflow) {
if (seen.has(item)) continue;
seen.add(item);
found.push(item);
}
return found;
},
};
}