每个扇形可以表示为 (x,y,r,a,d),其中 x、y 是位置,r 是半径,d 是方向,a 是角度。给定两个圆形扇形的这些信息,如何确定它们是否重叠?是否有有效的算法解决这个问题?谢谢!
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)
当然,误差范围要合适。我们现在都应该知道,比较浮点数是否相等应该使用某种增量比较。
如果是这样,你只需要检查一个点,就可以轻松找出那个点。它是沿着从 (x1,y1)
到 (x2,y2)
的直线上移动 r1
单位的点,或者看作是沿着那条直线的一定分数移动:
(x1 + (x2-x1) * (r1+r2) / r1, y1 + (y2-y1) * (r1+r2) / r1)
这里有两个步骤。第一步是确定这两个中心点是否足够靠近以允许碰撞,可以通过将它们之间的距离与它们半径之和进行比较来完成:
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
调用可能需要根据您的坐标系统进行一些微调。
编辑:刚刚意识到这个代码漏掉了一个重要的角落情况,即弧不是“指向”彼此但仍然重叠。将考虑这一点并返回...
由于我们有圆形扇区,如果您正在实时执行此操作,则角度和方向并不重要。以下仅适用于完整的圆形扇区,或者如果两个扇区互相指向。
您可以按照以下步骤进行:
1)找到每个扇区之间的距离, 2)从该距离中减去两个半径, 3)如果结果为负数,则两个扇区之间发生了碰撞。否则,这是碰撞距离。
例如,我们有两个扇区,半径均为50个单位。它们中心点之间的距离为80。减去80-50-50 = -20,因此您知道它们之间发生了20个单位的碰撞。
否则,如果距离为500,则500-50-50 = 400,为正值,现在您知道这两个扇区相距400个单位。
现在,如果圆圈太靠近,比如说,相距1个单位,1-50-50 = -99,这意味着它们几乎完全重叠。
对于真正的分段圆形扇区,这是您在评论中指定的内容,您应该使用paxdiablos或Macs的答案。
d
是一个角度(线段的“中心”),而a
是线段的“展开”。从描述来看,d
看起来是一个简单的顺时针/逆时针指示器。 - paxdiablo