两个弧之间的相交部分?(弧 = 一对角度之间的距离)

3
我正在寻找一种计算两个弧之间相交部分的方法。我需要使用它来确定一个弧在圆形右半部分上的视觉度数和左半部分上的视觉度数。我考虑创建一个右侧半弧,并将其与实际弧相交。但是,解决这个问题需要太多时间,所以我想在这里问问 - 有人一定做过这件事。
编辑: 很抱歉,之前的插图是在我处理角度时头重脚轻提供的。我将再次尝试解释:
在此链接http://i.stack.imgur.com/QSu2D.png中,您可以看到我将该弧切成两半,弧的右侧部分包含135度,左侧部分包含90度。
该弧从-180开始,结束于45(如果归一化,则从180开始,结束于405)。
我已经成功创建了以下代码,以计算右侧部分和左侧部分所包含的弧度量:
f1 = (angle2>270.0f?270.0f:angle2) - (angle1<90.0f?90.0f:angle1);
if (f1 < 0.0f) f1 = 0.0f;
f2 = (angle2>640.0f?640.0f:angle2) - (angle1<450.0f?450.0f:angle1);
if (f2 < 0.0f) f2 = 0.0f;
f3 = (angle2>90.0f?90.0f:angle2) - angle1;
if (f3<0.0f) f3=0.0f;
f4 = (angle2>450.0f?450.0f:angle2) - (angle1<270.0f?270.0f:angle1); 
if (f4<0.0f) f4=0.0f;

在将角度标准化为非负数后,它可以很好地工作,但当然需要在小于360时开始。 然后f1 + f2给出了左半部分的总和,f3 + f4给出了右半部分的总和。 它也没有考虑弧被定义为超过360的情况,这可能是一个“错误”的情况。
但是,这似乎更像是一种“解决方法”,而不是正确的数学解决方案。 我正在寻找更优雅的解决方案,它应该基于两个弧之间的“交集”(因为数学没有“边”,它不是视觉的);
谢谢!

一张图能更好地说明你的意思。 - freespace
你的图像左侧部分肯定包含90度吧? - High Performance Mark
是的,我有点困惑。我会修复它 :-) - daniel.gindi
你使用的坐标系是什么?如何描述一个弧线?“从-180度开始,以135度顺时针结束”无论如何旋转都不能正确描述该图像。 - Beta
我已经编辑过了,以使其更加清晰。谢谢! - daniel.gindi
2个回答

2
我认为这个方法可行,但我还没有进行全面测试。你有两个弧,每个弧都有一个起始角和一个终止角。我将按照你所做的方式,以顺时针从北方开始测量角度,但是与数学家们一样,也可以轻松地按逆时针从东方开始测量弧度。

首先“标准化”你的弧,即将它们中的所有角度减少到[0,360)范围内,因此取出360度的倍数并使所有角度为正。确保每个弧的终止角位于起始角的顺时针方向。

接下来,选择其中一个弧的起始角,无论哪个都无所谓。将您拥有的所有角度(4个)按数字顺序排序。如果任何角度的数字小于您选择的起始角,则将360度添加到它们中。

重新按升序排列角度。您选择的起始角将是新列表中的第一个元素。从您已经选择的起始角开始,列表中的下一个角是什么?

1)如果它是同一弧的停止角,则没有重叠或该弧完全包含在另一个弧中。做个记录并找到下一个角。如果下一个角是另一个弧的起始角,则没有重叠,您可以停止;如果它是另一个弧的停止角,则重叠包含第一个弧的全部。停止

2)如果它是另一个弧的起始角,则重叠从那个角度开始。记下这个角度。您的扫描遇到的下一个角必须是停止角,并且重叠在那里结束。停止。

3)如果它是另一个弧的终止角,则重叠包括第一个弧的起始角和该角之间的角度。停止。

这并不特别优雅,并且过于依赖条件语句,但它应该可行,并且相对容易转换为您喜欢的编程语言。

看吧,根本没有三角学!

编辑

这是一种更“数学”的方法,因为你似乎有这个需求。

对于(-pi,pi]中的角度theta,双曲正弦函数(通常称为sinh)将角度映射到实线上的一个区间,该区间在(近似)(-11.5,11.5]内。与arcsinarccos不同,该函数的反函数在同一区间上也是单值的。按照以下步骤进行:

1)如果一个弧包含0,则将其分成2个弧,(start,0)(0,stop)。现在您在实线上有2、3或4个间隔。

2) 计算这些区间的交集并将其从线性测量转换回角度测量。现在您已经获得了两个弧的交点。


这似乎对于一个交集来说太麻烦了,不是吗? 也许我错了,但肯定有一种数学方法(而且更短)。我想你从来没有写过那么多代码来求两个矩形的交集... 那么为什么弧线会有所不同呢? 感谢您的努力,我非常感激! - daniel.gindi
哇!这个简单易懂的想法真是太棒了!谢谢! - daniel.gindi

2
这个测试可以用一行代码来恢复。即使已经有了一个好的答案,让我来介绍我的答案。
假设第一个弧是 A:(a0,a1),第二个弧是 B:(b0,b1)。我假设角度值是唯一的,即在范围 [0°,360°[[0,2*pi[]-pi,pi] 内(范围本身不重要,我们将看到为什么)。我将取范围 ]-pi,pi] 作为所有角度的范围。
为了详细解释这种方法,我首先设计了一个关于R中区间交集的测试。因此,我们有 a1>=a0b1>=b0。按照实数区间的相同符号,我计算以下数量:
S = (b0-a1)*(b1-a0)

如果 S>0,则两个线段不重叠,否则它们的交集不为空。很容易看出为什么这个公式有效。如果 S>0,我们有两种情况:
  • b0>a1 意味着 b1>a0,因此没有交集:a0=<a1<b0=<b1

  • b1<a0 意味着 b0<b1,因此没有交集:b0=<b1<a0=<a1

所以我们有一个单一的数学表达式,在 R 中表现良好。
现在我将其扩展到圆形域 ]-pi,pi] 上。假设 a0<a1b0<b1 不再成立:例如,一条弧可以从 pi/2-pi/2,这是左半圆。因此,我计算以下数量:
S = (b0-a1)*(b1-a0)*H(a1-a0)*H(b1-b0)

其中H是由H(x)=-1 if x<0 else H(x)=1定义的阶跃函数。

同样,如果S>0,则弧A和B之间没有交点。有16种情况需要探讨,这里不再赘述...但在纸上很容易解决:)

备注: S的值并不重要,只有项的符号才重要。这个公式的美妙之处在于它不受你所取范围的影响。此外,您可以将其重写为逻辑测试:

T := (b0>a1)^(b1>a0)^(a1>=a0)^(b1>=b0)

其中^表示逻辑异或


编辑

唉,这个公式存在一个显而易见的失败情况... 所以我在这里进行了修正。我意识到有一种情况,即两个弧的交点可以是两个弧,例如当-pi<a0<b1<b0<a1<pi时。

纠正这个问题的解决方案是引入第二个测试:如果角度之和大于2*pi,则弧线一定相交。

因此,公式变成了:

T := (a1+b1-a0-b0+2*pi*((b1<b0)+(a1<a0))<2*pi) | ((b0>a1)^(b1>a0)^(a1>=a0)^(b1>=b0))

好的,这个版本虽然不如之前的优雅,但是现在是正确的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接