快速圆碰撞检测

时间:2009-03-30 13:27:09

标签: java optimization collision-detection performance geometry

我正在尝试编写一种方法来计算两个圆是否重叠。我想出了以下内容,我只是想知道是否有可能进一步优化。

private static boolean isCollision(Point2D p1, float r1, Point2D p2, float r2)
{
    float a,dx, dy;
    a = (r1+r2) * (r1+r2);
    dx = (float) (p1.getX() - p2.getX());
    dy = (float) (p1.getY() - p2.getY());

    if (a > (dx*dx) + (dy*dy))
    {
        return true;
    }
    return false;
}

6 个答案:

答案 0 :(得分:21)

嗯。就数学而言,这看起来非常好。关于如何使Java方面更快更简洁的一些小问题:

  • 如果您使用双打而不是浮点数来获得半径,则不必将双打下投到浮点数。
  • 如果你特别要求Point2D.Double参数,你可以使用他们的x和y公共字段而不是使用getter。
  • 另外,为什么if (foo) { return true; } else { return false; }?只做return foo;

改进版本,然后:

private static boolean isCollision(Point2D.Double p1, double r1, Point2D.Double p2, double r2)
{
    final double a = r1 + r2;
    final double dx = p1.x - p2.x;
    final double dy = p1.y - p2.y;
    return a * a > (dx * dx + dy * dy);
}

(请注意,如果您的代码完全基于浮动,则可以使用Point2D.Floatfloat执行相同的操作。)

答案 1 :(得分:9)

重叠还是交叉?

如果相交,请不要​​忘记圆圈不相交的情况,因为它们在彼此内部。

如果它重叠,我真的不知道你如何进一步优化;你将点距离与半径之和进行比较,使用距离平方来避免取平方根。似乎没有任何脂肪可以修剪。

答案 2 :(得分:6)

您真的需要迎合任何可能的Point2D实施吗?如果您不需要,它将保存虚拟呼叫:

private static boolean isCollisionFloat (Point2D.Float p1, float r1, Point2D.Float p2, float r2)
{
    final float r = r1+r2;
    final float dx = p1.x - p2.x;
    final float dy = p1.y - p2.y;

    return (r*r) > (dx*dx) + (dy*dy);
}
testing 1000x1000 points:
Doing nothing took 6 ms
Doing isCollision passing Point2D.Float took 128 ms
Doing isCollision passing Point2D.Double took 127 ms
Doing isCollisionFloat took 71 ms
Doing isCollisionDouble took 72 ms

如果可以,请选择其中一种,而不是两者兼顾。


perf问题的问题在于你真的必须测量效果,当时有人发布了相同的答案作为不支持的意见。

答案 3 :(得分:3)

我不知道你的情况是否相关,但是如果你想检查你的圈子和其他许多圈子之间的重叠(让我们说成千上万的圈子),你可以尝试在四叉树中组织你的圈子(请参阅http://en.wikipedia.org/wiki/Quadtree)并在四叉树中进行树查找(基于圆的边界矩形)。

答案 4 :(得分:2)

通过计算每个圆的矩形边界并查看它们是否重叠,可以进一步优化您的算法。如果它们不重叠则返回false。这避免了那些矩形边界不重叠的圆(即它们彼此不相近)的乘法。矩形边界计算的加法/减法比乘法便宜。

这是Java 2D使用的模式。见Shape.getBounds()

答案 5 :(得分:1)

它不会让你的代码更快,但我更喜欢:

return a > (dx*dx + dy*dy);