Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sisilicon
GitHub Repository: sisilicon/worldedit-be
Path: blob/master/src/library/utils/closestpoint.ts
1784 views
1
import { Vector3 } from "@minecraft/server";
2
import { Vector } from "@notbeer-api";
3
4
// KD-tree helpers for faster nearest center queries
5
class KDNode {
6
public point: Vector3;
7
public axis: 0 | 1 | 2;
8
public left?: KDNode;
9
public right?: KDNode;
10
11
constructor(point: Vector3, axis: 0 | 1 | 2) {
12
this.point = point;
13
this.axis = axis;
14
}
15
16
nearest(target: Vector3) {
17
let bestNode: KDNode | undefined;
18
let bestDist = Infinity;
19
20
function recurse(node?: KDNode) {
21
if (!node) return;
22
const d = squaredDist(node.point, target);
23
if (d < bestDist) {
24
bestDist = d;
25
bestNode = node;
26
}
27
const axisCoord = node.axis === 0 ? target.x - node.point.x : node.axis === 1 ? target.y - node.point.y : target.z - node.point.z;
28
const near = axisCoord <= 0 ? node.left : node.right;
29
const far = axisCoord <= 0 ? node.right : node.left;
30
recurse(near);
31
if (axisCoord * axisCoord < bestDist) recurse(far);
32
}
33
34
recurse(this);
35
return bestNode?.point;
36
}
37
}
38
39
function squaredDist(a: Vector3, b: Vector3) {
40
const dx = a.x - b.x;
41
const dy = a.y - b.y;
42
const dz = a.z - b.z;
43
return dx * dx + dy * dy + dz * dz;
44
}
45
46
function buildKDTree(points: Vector3[], depth = 0): KDNode | undefined {
47
if (!points || points.length === 0) return undefined;
48
const axis = (depth % 3) as 0 | 1 | 2;
49
const pts = points.slice();
50
pts.sort((p, q) => (axis === 0 ? p.x - q.x : axis === 1 ? p.y - q.y : p.z - q.z));
51
const mid = Math.floor(pts.length / 2);
52
const node = new KDNode(pts[mid], axis);
53
node.left = buildKDTree(pts.slice(0, mid), depth + 1);
54
node.right = buildKDTree(pts.slice(mid + 1), depth + 1);
55
return node;
56
}
57
58
export function closestPoint(points: Vector3[]) {
59
if (points.length > 32) {
60
// KD Tree
61
const kdRoot = buildKDTree(points);
62
return (location: Vector3) => {
63
const nearest = kdRoot.nearest(location);
64
return Vector.from(nearest ?? points[0]);
65
};
66
} else {
67
// Linear Search
68
return (location: Vector3) => {
69
const locV = Vector.from(location);
70
let closest = points[0];
71
let minDist = locV.distanceTo(closest);
72
for (let i = 1; i < points.length; i++) {
73
const c = points[i];
74
const d = locV.distanceTo(c);
75
if (d < minDist) {
76
minDist = d;
77
closest = c;
78
}
79
}
80
return Vector.from(closest);
81
};
82
}
83
}
84
85