我正在尝试编写一种方法来计算两个圆是否重叠。我想出了以下内容,我只是想知道是否有可能进一步优化。
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;
}
答案 0 :(得分:21)
嗯。就数学而言,这看起来非常好。关于如何使Java方面更快更简洁的一些小问题:
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.Float
和float
执行相同的操作。)
答案 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);