Path: blob/master/src/library/utils/closestpoint.ts
1784 views
import { Vector3 } from "@minecraft/server";1import { Vector } from "@notbeer-api";23// KD-tree helpers for faster nearest center queries4class KDNode {5public point: Vector3;6public axis: 0 | 1 | 2;7public left?: KDNode;8public right?: KDNode;910constructor(point: Vector3, axis: 0 | 1 | 2) {11this.point = point;12this.axis = axis;13}1415nearest(target: Vector3) {16let bestNode: KDNode | undefined;17let bestDist = Infinity;1819function recurse(node?: KDNode) {20if (!node) return;21const d = squaredDist(node.point, target);22if (d < bestDist) {23bestDist = d;24bestNode = node;25}26const axisCoord = node.axis === 0 ? target.x - node.point.x : node.axis === 1 ? target.y - node.point.y : target.z - node.point.z;27const near = axisCoord <= 0 ? node.left : node.right;28const far = axisCoord <= 0 ? node.right : node.left;29recurse(near);30if (axisCoord * axisCoord < bestDist) recurse(far);31}3233recurse(this);34return bestNode?.point;35}36}3738function squaredDist(a: Vector3, b: Vector3) {39const dx = a.x - b.x;40const dy = a.y - b.y;41const dz = a.z - b.z;42return dx * dx + dy * dy + dz * dz;43}4445function buildKDTree(points: Vector3[], depth = 0): KDNode | undefined {46if (!points || points.length === 0) return undefined;47const axis = (depth % 3) as 0 | 1 | 2;48const pts = points.slice();49pts.sort((p, q) => (axis === 0 ? p.x - q.x : axis === 1 ? p.y - q.y : p.z - q.z));50const mid = Math.floor(pts.length / 2);51const node = new KDNode(pts[mid], axis);52node.left = buildKDTree(pts.slice(0, mid), depth + 1);53node.right = buildKDTree(pts.slice(mid + 1), depth + 1);54return node;55}5657export function closestPoint(points: Vector3[]) {58if (points.length > 32) {59// KD Tree60const kdRoot = buildKDTree(points);61return (location: Vector3) => {62const nearest = kdRoot.nearest(location);63return Vector.from(nearest ?? points[0]);64};65} else {66// Linear Search67return (location: Vector3) => {68const locV = Vector.from(location);69let closest = points[0];70let minDist = locV.distanceTo(closest);71for (let i = 1; i < points.length; i++) {72const c = points[i];73const d = locV.distanceTo(c);74if (d < minDist) {75minDist = d;76closest = c;77}78}79return Vector.from(closest);80};81}82}838485