stable
This commit is contained in:
parent
d2e7a80e72
commit
860471f805
13 changed files with 1643 additions and 356 deletions
|
|
@ -31,6 +31,61 @@ export function distanceToNearest(points, x, y, fallback = 999) {
|
|||
return best;
|
||||
}
|
||||
|
||||
export function createPointSpatialIndex(points, cellSize = 12) {
|
||||
const buckets = new Map();
|
||||
const normalized = (points || [])
|
||||
.filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y))
|
||||
.map((p) => ({ ...p, x: Math.round(p.x), y: Math.round(p.y) }));
|
||||
const keyOf = (cx, cy) => `${cx},${cy}`;
|
||||
for (const p of normalized) {
|
||||
const cx = Math.floor(p.x / cellSize);
|
||||
const cy = Math.floor(p.y / cellSize);
|
||||
const key = keyOf(cx, cy);
|
||||
let bucket = buckets.get(key);
|
||||
if (!bucket) {
|
||||
bucket = [];
|
||||
buckets.set(key, bucket);
|
||||
}
|
||||
bucket.push(p);
|
||||
}
|
||||
|
||||
function nearestDistanceSq(x, y, maxDistance = Math.max(MAP_W, MAP_H)) {
|
||||
if (!normalized.length) return maxDistance * maxDistance;
|
||||
const cx = Math.floor(x / cellSize);
|
||||
const cy = Math.floor(y / cellSize);
|
||||
const maxRing = Number.isFinite(maxDistance) ? Math.ceil(maxDistance / cellSize) : Math.ceil(Math.max(MAP_W, MAP_H) / cellSize);
|
||||
let best = maxDistance * maxDistance;
|
||||
for (let ring = 0; ring <= maxRing; ring++) {
|
||||
for (let by = cy - ring; by <= cy + ring; by++) {
|
||||
for (let bx = cx - ring; bx <= cx + ring; bx++) {
|
||||
if (ring > 0 && bx > cx - ring && bx < cx + ring && by > cy - ring && by < cy + ring) continue;
|
||||
const bucket = buckets.get(keyOf(bx, by));
|
||||
if (!bucket) continue;
|
||||
for (const p of bucket) {
|
||||
const dx = p.x - x;
|
||||
const dy = p.y - y;
|
||||
const d2 = dx * dx + dy * dy;
|
||||
if (d2 < best) best = d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
return {
|
||||
points: normalized,
|
||||
hasWithin(x, y, radius) {
|
||||
return nearestDistanceSq(x, y, radius) < radius * radius;
|
||||
},
|
||||
distance(x, y, fallback = 999) {
|
||||
const d2 = nearestDistanceSq(x, y, fallback);
|
||||
return d2 < fallback * fallback ? Math.sqrt(d2) : fallback;
|
||||
},
|
||||
nearestDistanceSq,
|
||||
};
|
||||
}
|
||||
|
||||
export function aStar(start, goal, costAt) {
|
||||
const startIndex = indexOf(start.x, start.y);
|
||||
const goalIndex = indexOf(goal.x, goal.y);
|
||||
|
|
@ -83,15 +138,18 @@ export function aStar(start, goal, costAt) {
|
|||
|
||||
export function influenceFromPaths(paths, radius) {
|
||||
const grid = new Float32Array(SIZE);
|
||||
const r = Math.ceil(radius);
|
||||
const r2 = radius * radius;
|
||||
for (const path of paths) {
|
||||
for (const [x, y] of path) {
|
||||
for (let dy = -radius; dy <= radius; dy++) {
|
||||
for (let dx = -radius; dx <= radius; dx++) {
|
||||
for (let dy = -r; dy <= r; dy++) {
|
||||
for (let dx = -r; dx <= r; dx++) {
|
||||
const nx = x + dx;
|
||||
const ny = y + dy;
|
||||
if (!inside(nx, ny)) continue;
|
||||
const d = Math.hypot(dx, dy);
|
||||
if (d > radius) continue;
|
||||
const d2 = dx * dx + dy * dy;
|
||||
if (d2 > r2) continue;
|
||||
const d = Math.sqrt(d2);
|
||||
const i = indexOf(nx, ny);
|
||||
grid[i] = Math.max(grid[i], 1 / (1 + d));
|
||||
}
|
||||
|
|
@ -239,15 +297,18 @@ export function averagePathField(path, field) {
|
|||
|
||||
export function influenceFromPoints(points, radius, weightFn = () => 1) {
|
||||
const grid = new Float32Array(SIZE);
|
||||
const r = Math.ceil(radius);
|
||||
const r2 = radius * radius;
|
||||
for (const p of points) {
|
||||
const weight = weightFn(p);
|
||||
for (let dy = -radius; dy <= radius; dy++) {
|
||||
for (let dx = -radius; dx <= radius; dx++) {
|
||||
for (let dy = -r; dy <= r; dy++) {
|
||||
for (let dx = -r; dx <= r; dx++) {
|
||||
const nx = p.x + dx;
|
||||
const ny = p.y + dy;
|
||||
if (!inside(nx, ny)) continue;
|
||||
const d = Math.hypot(dx, dy);
|
||||
if (d > radius) continue;
|
||||
const d2 = dx * dx + dy * dy;
|
||||
if (d2 > r2) continue;
|
||||
const d = Math.sqrt(d2);
|
||||
const i = indexOf(nx, ny);
|
||||
grid[i] = Math.max(grid[i], weight / (1 + d));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue