每个扇区可以表示为(x,y,r,a,d),其中x,y是位置,r是半径,d是方向,a是角度。鉴于这两个循环扇区的信息,如何确定它们是否相互重叠? 有没有有效的算法来解决它?谢谢!
答案 0 :(得分:8)
我知道有一种非常快捷的方法来折扣这种可能性,因为我以前用它来进行圆碰撞。
计算两个中心之间的距离,然后,如果它大于半径之和,则不会发生碰撞。为了提高效率,不要使用平方根,只需直接处理平方值:
if (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) > (r1 + r2) * (r1 + r2):
# No chance of collision.
为圆圈细分工作会有点困难。
您选择的方法取决于您需要的准确程度。如果您正在进行实际数学运算,则可能需要高精度。但是,例如,如果你正在为电脑游戏这样的事情做这件事,那么足够接近可能就足够了。
如果是这种情况,我会考虑将弧线转换为一系列直线(其数量可能取决于a
,弧线的“扩散” - 你可能会得到用一条弧线散开一段弧度,但180度不能很好。
直线碰撞检测是一种更为人熟知的方法,尽管你必须处理比较次数可能会迅速增加的事实。
如果您不想使用线段,那么这是您要遵循的流程。它使用圆形碰撞算法找出整圆的零点,一点或两点碰撞,然后检查这些点是否在两个弧内。
首先,运行上面的检查以检测不可能发生碰撞的情况。如果圆圈之间不可能发生碰撞,那么弧线也不会发生碰撞。
其次,检查圆圈是否有单个碰撞点。如果出现这种情况:
(x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) == (r1 + r2) * (r1 + r2)
当然,在合适的误差范围内。我们现在都应该知道,比较相等的浮点数应该使用某种delta比较。
如果是这种情况,你有一点要检查,你可以很容易地发现这一点。这是从r1
到(x1,y1)
的直线上的点(x2,y2)
单位,或者将其视为沿该线移动一些分数:
(x1 + (x2-x1) * (r1+r2) / r1, y1 + (y2-y1) * (r1+r2) / r1)
否则,有两点需要检查,您可以使用this one之类的问题的答案来确定这两点是什么。
一旦你有一些碰撞点,它就是much simpler method来确定这些点是否在弧上,记住候选点需要在两个弧上他们碰撞,而不只是碰撞。
答案 1 :(得分:4)
有两个步骤。首先要弄清楚这两个中心是否足够接近以允许碰撞,这可以通过将它们之间的距离与它们的半径之和进行比较来完成:
if (((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) > ((r1 + r2) * (r1 + r2)))
// No collision.
然后你需要检查中心之间的线是否落在由各种角度定义的弧内:
float angle1to2 = Math.atan2(y2 - y1, x2 - x1);
if (angle1to2 < (d1 - a1/2) || angle1to2 > (d1 + a1/2))
// No collision
float angle2to1 = angle1to2 + Math.PI;
if (angle2to1 < (d2 - a2/2) || angle2to1 > (d2 + a2/2))
// No collision
如果您通过这些检查而没有排除碰撞的可能性,那么您已成功检测到碰撞。
警告:此代码根本未经过测试。特别是,atan2
调用可能需要一些调整,具体取决于您的坐标系。
编辑:刚刚意识到这错过了一个重要的角落情况,其中弧线并非“指向”彼此但仍然重叠。将反复思考并返回...
答案 2 :(得分:1)
由于我们有圆形扇区,因此如果您实时执行此操作,则角度和方向无关紧要。以下内容仅适用于整圆扇区,或两个扇区彼此指向的情况。
您可以按照以下步骤操作:
1)找出每个扇区之间的距离, 2)将半径减去该距离, 3)如果结果是否定的,则两个扇区之间都存在冲突。否则,它与碰撞的距离。
例如,我们有两个扇区,两个扇区的半径为50。它们的中心点之间的距离是80.减去80-50-50 = -20,所以你知道距离有20个单位。否则,如果距离为500,500-50-50 = 400,则为正值,现在您知道这两个扇区相距400个单位。
现在,如果圆圈太近,比如相距1个单位,1-50-50 = -99,这意味着它们几乎完全重叠。
对于您在评论中指定的真正分段循环扇区,您应该使用paxdiablos或Macs答案。