Skip to content

Commit 162f6da

Browse files
author
Chris Hallberg
committed
Use squared distance for kNearest. Clean up syntax.
1 parent ccffb4e commit 162f6da

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

quadtree.js

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ class Point {
1111
this.userData = data;
1212
}
1313

14-
// Pythagorus: a^2 = b^2 + c^2
15-
distanceFrom(other) {
14+
// Skips Math.sqrt for faster comparisons
15+
sqDistanceFrom(other) {
1616
const dx = other.x - this.x;
1717
const dy = other.y - this.y;
18-
return Math.sqrt(dx * dx + dy * dy);
18+
19+
return dx * dx + dy * dy;
20+
}
21+
22+
// Pythagorus: a^2 = b^2 + c^2
23+
distanceFrom(other) {
24+
return Math.sqrt(this.sqDistanceFrom(other));
1925
}
2026
}
2127

@@ -80,11 +86,17 @@ class Rectangle {
8086
);
8187
}
8288

83-
distanceFrom(point) {
89+
// Skips Math.sqrt for faster comparisons
90+
sqDistanceFrom(point) {
8491
const dx = this.xDistanceFrom(point);
8592
const dy = this.yDistanceFrom(point);
8693

87-
return Math.sqrt(dx * dx + dy * dy);
94+
return dx * dx + dy * dy;
95+
}
96+
97+
// Pythagorus: a^2 = b^2 + c^2
98+
distanceFrom(point) {
99+
return Math.sqrt(this.sqDistanceFrom(point));
88100
}
89101
}
90102

@@ -327,41 +339,42 @@ class QuadTree {
327339
throw TypeError("Method 'closest' needs a point");
328340
}
329341

330-
return this.kNearest(searchPoint, maxCount, maxDistance, 0, 0).found;
342+
return this.kNearest(searchPoint, maxCount, maxDistance ** 2, 0, 0).found;
331343
}
332344

333-
kNearest(searchPoint, maxCount, maxDistance, furthestDistance, foundSoFar) {
345+
kNearest(searchPoint, maxCount, sqMaxDist, furthestSqDist, foundSoFar) {
334346
let found = [];
335347

336-
this.children.sort((a, b) => a.boundary.distanceFrom(searchPoint) - b.boundary.distanceFrom(searchPoint))
348+
this.children.sort((a, b) => a.boundary.sqDistanceFrom(searchPoint) - b.boundary.sqDistanceFrom(searchPoint))
337349
.forEach((child) => {
338-
const distance = child.boundary.distanceFrom(searchPoint);
339-
if (distance > maxDistance) {
350+
const sqDist = child.boundary.sqDistanceFrom(searchPoint);
351+
if (sqDist > sqMaxDist) {
340352
return;
341-
} else if (foundSoFar < maxCount || distance < furthestDistance) {
342-
const result = child.kNearest(searchPoint, maxCount, maxDistance, furthestDistance, foundSoFar);
353+
} else if (foundSoFar < maxCount || sqDist < furthestSqDist) {
354+
const result = child.kNearest(searchPoint, maxCount, sqMaxDist, furthestSqDist, foundSoFar);
343355
const childPoints = result.found;
344356
found = found.concat(childPoints);
345357
foundSoFar += childPoints.length;
346-
furthestDistance = result.furthestDistance;
358+
furthestSqDist = result.furthestSqDist;
347359
}
348360
});
349361

350-
this.points.sort((a, b) => a.distanceFrom(searchPoint) - b.distanceFrom(searchPoint))
362+
this.points
363+
.sort((a, b) => a.sqDistanceFrom(searchPoint) - b.sqDistanceFrom(searchPoint))
351364
.forEach((p) => {
352-
const distance = p.distanceFrom(searchPoint);
353-
if (distance > maxDistance) {
365+
const sqDist = p.sqDistanceFrom(searchPoint);
366+
if (sqDist > sqMaxDist) {
354367
return;
355-
} else if (foundSoFar < maxCount || distance < furthestDistance) {
368+
} else if (foundSoFar < maxCount || sqDist < furthestSqDist) {
356369
found.push(p);
357-
furthestDistance = Math.max(distance, furthestDistance);
370+
furthestSqDist = Math.max(sqDist, furthestSqDist);
358371
foundSoFar++;
359372
}
360373
});
361374

362375
return {
363-
found: found.sort((a, b) => a.distanceFrom(searchPoint) - b.distanceFrom(searchPoint)).slice(0, maxCount),
364-
furthestDistance
376+
found: found.sort((a, b) => a.sqDistanceFrom(searchPoint) - b.sqDistanceFrom(searchPoint)).slice(0, maxCount),
377+
furthestDistance: furthestSqDist ** 2,
365378
};
366379
}
367380

@@ -380,12 +393,16 @@ class QuadTree {
380393
let right = Math.max(this.boundary.right, other.boundary.right);
381394
let top = Math.min(this.boundary.top, other.boundary.top);
382395
let bottom = Math.max(this.boundary.bottom, other.boundary.bottom);
396+
383397
let height = bottom - top;
384398
let width = right - left;
399+
385400
let midX = left + width / 2;
386401
let midY = top + height / 2;
402+
387403
let boundary = new Rectangle(midX, midY, width, height);
388404
let result = new QuadTree(boundary, capacity);
405+
389406
this.forEach(point => result.insert(point));
390407
other.forEach(point => result.insert(point));
391408

0 commit comments

Comments
 (0)