圆间隔距离 - 最近邻问题
我有一组在二维平面上具有给定位置和半径的圆。我想确定每个圆是否与任何其他圆相交以及分隔两个圆所需的距离。在我当前的实现下,我只是遍历所有可能的圆圈组合,然后进行计算。不幸的是,这个算法是 O(n^2),速度很慢。
这些圆通常会聚集成组,并且它们将具有相似(但不同)的半径。圆圈数量的最大值大约为 200 左右。该算法不必非常精确,但应该接近。
这是我目前在 JavaScript 中的一个(缓慢的)实现:
// Makes a new circle
var circle = function(x,y,radius) {
return {
x:x,
y:y,
radius:radius
};
};
// These points are not representative of the true data set. I just made them up.
var points = [
circle(3,3,2),
circle(7,5,4),
circle(16,6,4),
circle(17,12,3),
circle(26,20,1)
];
var k = 0,
len = points.length;
for (var i = 0; i < len; i++) {
for (var j = k; j < len; j++) {
if (i !== j) {
var c1 = points[i],
c2 = points[j],
radiiSum = c1.radius+c2.radius,
deltaX = Math.abs(c1.x-c2.x);
if (deltaX < radiiSum) {
var deltaY = Math.abs(c1.y-c2.y);
if (deltaY < radiiSum) {
var distance = Math.sqrt(deltaX*deltaX+deltaY*deltaY);
if (distance < radiiSum) {
var separation = radiiSum - distance;
console.log(c1,c2,separation);
}
}
}
}
}
k++;
}
另外,如果您用简单的英语解释一个好的算法(KD 树?),我将不胜感激:-/
I have a set of circles with given locations and radii on a two dimensional plane. I want to determine for every circle if it is intersecting with any other circle and the distance that is needed to separate the two. Under my current implementation, I just go through all the possible combinations of circles and then do the calculations. Unfortunately, this algorithm is O(n^2), which is slow.
The circles will generally be clustered in groups, and they will have similar (but different) radii. The approximate maximum for the number of circles is around 200. The algorithm does not have to be exact, but it should be close.
Here is a (slow) implementation I currently have in JavaScript:
// Makes a new circle
var circle = function(x,y,radius) {
return {
x:x,
y:y,
radius:radius
};
};
// These points are not representative of the true data set. I just made them up.
var points = [
circle(3,3,2),
circle(7,5,4),
circle(16,6,4),
circle(17,12,3),
circle(26,20,1)
];
var k = 0,
len = points.length;
for (var i = 0; i < len; i++) {
for (var j = k; j < len; j++) {
if (i !== j) {
var c1 = points[i],
c2 = points[j],
radiiSum = c1.radius+c2.radius,
deltaX = Math.abs(c1.x-c2.x);
if (deltaX < radiiSum) {
var deltaY = Math.abs(c1.y-c2.y);
if (deltaY < radiiSum) {
var distance = Math.sqrt(deltaX*deltaX+deltaY*deltaY);
if (distance < radiiSum) {
var separation = radiiSum - distance;
console.log(c1,c2,separation);
}
}
}
}
}
k++;
}
Also, I would appreciate it if you explained a good algorithm (KD Tree?) in plain English :-/
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对于初学者来说,如果您跳过 SQRT 调用,上面的算法将会大大加快。这是最著名的比较距离的简单优化。您还可以预先计算“平方半径”距离,这样就不必重复地重新计算它。
此外,您的某些算法中似乎还存在许多其他小错误。下面是我对如何修复它的看法。
另外,如果你想摆脱 O(N-Squared) 算法,你可以考虑使用 kd-树。构建 KD 树需要一定的前期成本,但其好处是可以更快地搜索最近的邻居。
For starters, your algorithm above will be greatly sped-up if you just skipped the SQRT call. That's the most well known simple optimization for comparing distances. You can also precompute the "squared radius" distance so you don't redundantly recompute it.
Also, there looks to be lots of other little bugs in some of your algorithms. Here's my take on how to fix it below.
Also, if you want to get rid of the O(N-Squared) algorithm, you can look at using a kd-tree. There's an upfront cost of building the KD-Tree but with the benefit of searching for nearest neighbors as much faster.
这篇文章已经休眠很长时间了,但我已经遇到并很好地解决了这个问题,所以将发布,以便其他人不必做同样的头痛。
您可以将最近圆邻居问题视为 kd 树或八叉树中的 3d 点最近邻搜索。将两个圆 A 和 B 之间的距离定义为 当且
仅当圆重叠时,这是一个负数。对于本次讨论,我将假设一个八叉树,但 k=3 的 kd 树是类似的。
在每个圆的八叉树中存储一个三元组 (x,y,r)。
要找到距离目标圆 T 最近的邻居,请使用标准算法:
这里
nst
是对迄今为止找到的距离 T 最近的圆的引用。最初它是空的。稍微棘手的部分是确定 C 是否包含比 nst 更接近 T 的任何点。为此,考虑 C 中唯一点 (x,y,r) 就足够了,该点是 x 和 y 中最接近 T 的欧几里得点,并且具有长方体中包含的 r 范围的最大值。换句话说,长方体表示一组圆,其圆心分布在 x 和 y 方向上的矩形区域上,并且具有一定的半径范围。您要检查的点是代表圆心最接近 T 且半径最大的圆的点。
请注意,T 的半径在算法中根本不起作用。您只关心 T 的中心在任何其他圆内有多远。 (我希望这一点一开始就像现在一样明显......)
This article has been dormant for a long time, but I've run into and solved this problem reasonably well, so will post so that others don't have to do the same head scratching.
You can treat the nearest circle neighbor problem as a 3d point nearest neighbor search in a kd-tree or octree. Define the distance between two circles A and B as
This is a negative quantity iff the circles overlap. For this discussion I'll assume an octree, but a kd-tree with k=3 is similar.
Store a triple (x,y,r) in the octree for each circle.
To find the nearest neighbor to a target circle T, use the standard algorithm:
Here
nst
is a reference to the nearest circle to T found so far. Initially it's null.The slightly tricky part is determining
if C contains any point nearer to T than nst
. For this it is sufficent to consider the unique point (x,y,r) within C that is Euclidean nearest to T in x and y and has the maximum value of the r range contained in the cuboid. In other words, the cuboid represents a set of circles with centers ranging over a rectangular area in x and y and with a range of radii. The point you want to check is the one representing the circle with center closest to T and with largest radius.Note the radius of T plays no part in the algorithm at all. You're only concered with how far inside any other circle the center of T lies. (I wish this had been as obvious at the start as it seems now...)