我正在寻找一种高效的算法,用于检查一个点在3D空间中是否靠近另一个点。
sqrt((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2) < radius
这似乎不太快,而且我并不需要如此高的精度。还有其他方法可以做到这一点吗?
sqrt((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2) < radius
这似乎不太快,而且我并不需要如此高的精度。还有其他方法可以做到这一点吗?
将距离平方,去掉对sqrt()
的调用,这样速度更快:
(((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2 < radius * radius
radius * radius
并将其存储为squaredRadius
。abs(x)
比 (x * x)
更快,特别是对于非整数而言,那将是一台不寻常的机器。然而,了解哪个算法更快的一般规则是测试两者并自行判断。 - Drew Dormann如果你可以接受立方距离而不是球形距离,那么一个相当简单的实现方式如下:
Math.Abs(x2-x1) < radius && Math.Abs(y2-y1) < radius && Math.Abs(z2-z1) < radius
如果Math.Abs成为瓶颈,您可以使用自己喜欢的优化方法。
我还应该补充一点,如果其中一个维度通常变化比其他维度小,那么将它放在最后应该会提高性能。例如,如果您主要处理“地面”x-y平面上的对象,则最后检查z轴,因为您应该能够通过使用x和y检查更早地排除碰撞。
如果您不需要高度精确的话,也许可以检查第二个点是否在立方体内(边长为“2a”),而不是球形中心点为第一个点:
|x2-x1|<a && |y2-y1|<a && |z2-z1|<a
由于流水线处理器架构,现在大多数情况下,进行两次FPU计算比进行一次分支更有效率。如果出现分支预测错误,将会导致CPU停滞很长时间。
因此,我宁愿选择计算方式,而不是分支方式。
如果你不需要准确性,可以检查你是否在一个立方体而不是一个球体中。
这里也有一些选择,你可以选择围住球体的立方体(没有假阴性),与球体相同体积的立方体(有一些假阳性和假阴性,但最大误差被最小化),包含在球体内部的立方体(没有假阳性)。
这种技术也很好地扩展到更高的维度。
如果你想获得靠近另一个点的所有点,某种形式的空间索引可能也是合适的(例如kd树)
这个函数计算了立方体距离,如果你要处理很多点,大部分时间它只会执行第一个测试。
close = (abs(x2-x1) < r && abs(y2-y1) < r && abs(z2-z1) < r);
使用 max(abs(x1-x2), abs(y1-y2), abs(z1-z2))
double abs(double)
和 double max(double, double)
使用条件逻辑呢? - MSalters去掉平方根后,如果值变得较大,最好应用对数。