point_table = (pixel_size) => {
let data = {};
let bucket = (x, y) => `${Math.floor(x / pixel_size)},${Math.floor(y / pixel_size)}`;
let int_bucket_min_dist = (x, y, bucketx, buckety) => {
let round_toward = (value, toward) => value > toward
? (Math.floor(value) > toward ? Math.floor(value) : toward)
: (Math.ceil(value) < toward ? Math.ceil(value) : toward);
let zero_stop = (value) => value < 0 ? 0 : value;
let x_dist = zero_stop(Math.abs(x - round_toward(bucketx + .5, x)));
let y_dist = zero_stop(Math.abs(y - round_toward(buckety + .5, y)));
return dist([0,0], [x_dist, y_dist]);
};
let buckets_in = (_x, _y, _r) => {
let r = _r / pixel_size;
let x = _x / pixel_size;
let y = _y / pixel_size;
let buckets = [];
let start_bucket = [Math.floor(x), Math.floor(y)];
let iter_limit = Math.ceil(r + 1);
for (let ox = -iter_limit; ox < iter_limit + 1; ox++) {
for (let oy = -iter_limit; oy < iter_limit; oy++) {
let o = add(start_bucket, [ox, oy]);
if (int_bucket_min_dist(x, y, o[0], o[1]) <= r) {
buckets.push(o);
}
}
}
return buckets;
};
return {
within: (origin, r) => {
let [x, y] = origin;
return buckets_in(x, y, r)
.map(([bx, by]) => data[bucket(bx * pixel_size, by * pixel_size)])
.filter(pts => pts !== undefined)
.flat()
.filter(pt => dist([x, y], pt) <= r);
},
add: (pt) => {
let [x, y] = pt;
let b = bucket(x, y);
if (data[b] === undefined) {
data[b] = [];
}
data[b].push(pt);
}
};
}