【问题标题】:check if two segments on the same circle overlap / intersect检查同一圆上的两个线段是否重叠/相交
【发布时间】:2012-08-02 10:18:40
【问题描述】:

给定同一个圆的两个圆段:A=[a1, a2] 和 B=[b1, b2],其中:

  • a1、a2、b1、b2 值在 -inf 和 +inf 之间的度数
  • a1
  • a2-a1

如何确定这两个圆段是否重叠? (即如果它们至少有一点相交或接触)

例子:

A=[  -45°,    45°]; B=[   10°,   20°] ==> overlap
A=[  -45°,    45°]; B=[   90°,  180°] ==> no overlap
A=[  -45°,    45°]; B=[  180°,  360°] ==> overlap
A=[ -405°,  -315°]; B=[  180°,  360°] ==> overlap
A=[-3600°, -3601°]; B=[ 3601°, 3602°] ==> overlap (touching counts as overlap)
A=[ 3600°,  3601°]; B=[-3601°,-3602°] ==> overlap (touching counts as overlap)
A=[    -1°,    1°]; B=[ 3602°, 3603°] ==> no overlap 

这看起来是一个看似简单的问题,但我无法理解它。 我目前有一个解决方案的基本想法,如果每个部分超过 0°,则将其分成两部分,但我不确定这是否涵盖所有情况,我想知道是否有一个优雅的公式。

【问题讨论】:

  • 如果你没有指定圆的半径或中心,我们是否假设弧在同一个圆上?
  • @HighPerformanceMark 我不认为其他问题是重复的。该问题的答案涉及对数组进行排序和管理相邻段的列表。
  • @Chris 是的,这些段在同一个圆圈上;我在正文中有,但标题可能不清楚,我修改了问题标题以反映这一事实
  • @HighPerformanceMark 我刚刚看到你修改了链接;另一个问题看起来确实相关,认为它们似乎只有 0° 到 360° 之间的角度。答案似乎与我拆分段的基本想法相似,我很想知道这是否确实是解决我的问题的有效解决方案,以及是否有更好的解决方案?

标签: algorithm language-agnostic geometry 2d angle


【解决方案1】:

正如@admaoldak 提到的,首先标准化度数:

a1_norm = a1 % 360
a2_norm = a2 % 360
b1_norm = b1 % 360
b2_norm = b2 % 360

现在检查 b1 是否在 (a1,a2) 内,

def intersect(b, as, ae
    Intersect = False
    If as > ae:
        if b >= as or b <= ae:
            return True
    Else:
        if b>=as and b<=ae:
            return True
    return False

最终答案是:

intersect(b1_norm,a1_norm,a2_norm)||intersect(b2_norm,a1_norm,a2_norm)||
intersect(a1_norm,b1_norm,b2_norm)||intersect(a2_norm,b1_norm,b2_norm)

【讨论】:

  • 谢谢!这是我用的;尽管速度是个问题,但我认为只检查 intersect(b1_norm,a1_norm,a2_norm)||intersect(a1_norm,b1_norm,b2_norm) 就足以涵盖所有情况
  • 那么 A=[ -45°, 45°]; B=[ 180°, 359°] ==> 重叠
  • 注意,对于负数,模数通常不能正确实现(我不了解 python,但大多数 C 系语言都是这种情况)
【解决方案2】:

对于区间 [i.X , i.Y] ,让我们定义归一化 i_norm = normalize(i) 以便:

1. 0 <= i_norm.X < 360
2. i_norm.X <=i_norm.Y

然后我们定义另一个操作 i_slide = slide(i) 以便:

1. i_slide.X = i.X + 360
2. i_slide.Y = i.Y + 360

我们可以证明, 对于您的输入 AB ,如果和仅当:

normalize(A) interval-overlapsnormalize(B)

normalize(A) interval-overlapsslide( normalize(B))

interval-overlaps 的定义方式与 adamoldak 帖子中的“intersection”相同。

normalize()slide()这两个操作都很容易实现。

举个例子:A=[-45°,45°]; B=[10°,20°],我们有

normalize(A) = [315,405] 
normalize(B) = [10,20] 
slide( normalize(B) ) = [370,380]

和 [315,405] interval-overlaps 与 [370,380]

【讨论】:

  • 切换 A 和 B 并且您的示例中断。您需要检查 norm(A) vs norm(B)、slide(norm(A)) vs norm(B) & norm(A) vs slide(norm(B)
【解决方案3】:

我有一个类似的问题,游戏引擎的矩形在循环地图中重叠。我已经考虑了很多,并查看了你们中的一些人的答案。如果你正在寻找性能,这是你能得到的最好的(直到有人证明我错了:P):

#assume the angles are already normalised
def overlap(a1, a2, b1, b2):
  if a2 - a1 + b2 - b1 > 360: #must overlap
    return True
  return (b1 > a2) ^ (b2 > a1) ^ (a2 < a1) ^ (b2 < b1)

优雅。优雅而丑陋。

【讨论】:

    【解决方案4】:

    如何将每个度数标准化为 0-360:

    a1_norm = a1 % 360
    a2_norm = a2 % 360
    b1_norm = b1 % 360
    b2_norm = b2 % 360
    

    然后你只需检查交叉点:

    (a1_norm <= b2_norm) and (a2_norm<= b1_norm) 
    

    【讨论】:

    • A=[-45°,45°]; B=[10°,20°] ==> A=[315°,45°]; B=[10°,20°],那么尽管有重叠,a1_norm > b2_norm
    猜你喜欢
    • 2011-04-19
    • 2017-03-27
    • 2019-01-24
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 2018-12-17
    相关资源
    最近更新 更多