在圆形交叉点中查找专用区域


17

这是给您一个看似具有挑战性的几何难题!

给定一个圆An其他圆B[n],找出包含在A其中的总面积不在的任何圆之内B

您的代码应尽可能短。

输入项

您的输入应包含以下信息:

  • 一个浮点数,表示圆的半径A
  • 浮点数列表,用于表示中的圆半径B
  • 中的圆心列表B。您的程序可能期望中心在极坐标或笛卡尔坐标中。
  • (可选)您可能会收到nB中的圆圈数。此输入不是必需的。

假定圆心A是原点,即点(0, 0)

这是保证没有两个圈子里B是相同的,但保证:1,各界B相交A,各中心B在外面A,或没有两个圆B相交。确保您的解决方案可以处理各种边缘情况。

您可以以任何顺序接收输入,包括文本输入(通过stdin或您的语言的等效语言),函数参数或命令行参数的形式。

如果选择接收文本输入,则输入之间应有一个或两个字符的可打印ASCII分隔符。

输出量

您的程序或函数应输出一个浮点数,该数字代表A不在的任何圆圈内的总面积B。对于所有测试用例,您的答案应至少精确到三个有效数字。

通用规则适用。

您的解决方案不应依赖圆内的采样点来确定面积。

不允许使用自动定位圆的交点,在圆的交点内查找区域或立即解决此问题的内置函数。

测试用例

在每个图像中,圆圈A以蓝色勾勒出轮廓,圆圈B以绿色勾勒出黑色轮廓。应返回的区域以红色填充。

(特别感谢Rainer P.检查我的解决方案)

测试用例1:

A = {x: 0, y: 0, rad: 50}
B[0] = {x: 0, y: 0, rad: 100}

测试用例1

Result: 0.00

测试案例2:

A = {x: 0, y: 0, rad: 100.000000}
B[0] = {x: 100.000000, y: 0.000000, rad: 50.000000}
B[1] = {x: 30.901699, y: -95.105652, rad: 50.000000}
B[2] = {x: -80.901699, y: -58.778525, rad: 50.000000}
B[3] = {x: -80.901699, y: 58.778525, rad: 50.000000}
B[4] = {x: 30.901699, y: 95.105652, rad: 50.000000}

测试用例2

Result: 1.3878e+04

测试案例3:

A = {x: 0, y: 0, rad: 138}
B[0] = {x: 100, y: 0, rad: 100}
B[1] = {x: -50, y: -86, rad: 100} 
B[2] = {x: -93, y: 135, rad: 50}

测试用例3

Result: 1.8969e+04

测试案例4:

A = {x: 0, y: 0, rad: 121.593585}
B[0] = {x: 81.000000, y: 107.000000, rad: 59.841457}
B[1] = {x: -152.000000, y: -147.000000, rad: 50.000000}
B[2] = {x: 43.000000, y: -127.000000, rad: 105.118980}
B[3] = {x: 0.000000, y: -72.000000, rad: 57.870545}
B[4] = {x: -97.000000, y: -81.000000, rad: 98.488578}
B[5] = {x: -72.000000, y: 116.000000, rad: 66.468037}
B[6] = {x: 2.000000, y: 51.000000, rad: 50.000000}

测试用例4

Result: 1.1264e+04

测试案例5:

A = {x: 0, y: 0, rad: 121.605921}
B[0] = {x: 0.000000, y: -293.000000, rad: 250.000000}
B[1] = {x: 0.000000, y: -56.000000, rad: 78.230429}
B[2] = {x: 0.000000, y: -102.000000, rad: 100.000000}

测试案例5

Result: 2.6742e+04

建议阅读:

Fewell,国会议员“三个圆圈的常见重叠区域”。2006年10月。网站。http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf


我想这个解决自己两年前在这方面的工作,同时,根据问题是多么简单的两个圆圈。我最终阅读了您链接的论文,然后决定与Monte Carlo'ing地区一起去。“您的解决方案不应依赖圆圈内的采样点来确定面积。” D:
马丁·恩德

您似乎没有一个测试用例,其中一个圆圈B包含另一个圆圈。可能值得补充。
马丁·恩德

您可以检查第三个测试用例吗?我正在1.8970e+04
LegionMammal978 '16

@MartinBüttner我也偶然遇到了这个问题。我对解决方案不是很满意,但是它似乎可以工作。我会尝试为这种情况做一点测试,谢谢!
BrainSteel

@ LegionMammal978是的,看来情况是错误的。我有以下数据圆之间的交点: B[0] - A intersection: 20653.659515B[1] - A intersection: 20757.824115B[1] - B[0] intersection: 1841.847766B[2] - A intersection: 1289.164541,这将产生18969.69009作为答案。
BrainSteel

Answers:


14

Python 2,631字节

from cmath import*
C=input()
O,R=C[0]
def I(p,r,q,s):
 try:q-=p;d=abs(q*q);x=(r*r-s*s+d)/d/2;return[p+q*(x+z*(r*r/d-x*x)**.5)for z in-1j,1j]
 except:return[]
S=sorted
V=S(i.real for p,r in C for c in C for i in[p-r,p+r]+I(p,r,*c)if-R<=(i-O).real<=R)
A=pi*R*R
for l,r in zip(V,V[1:]):
 H=[]
 for p,t in C:
    try:
     for s in-1,1:a,b=[p.imag+s*(t*t-(p.real-x)**2)**.5for x in l,r];H+=[a+b,a,b,s,t,p],
    except:0
 a,b=H[:2];H=S(H[2:]);n=0;c=a
 for d in H:
    s=d[3];z=.5;H*=d<b
    for q,w,e,_,t,y in(c,min(d,b))*(n-s<(a<d)or[0]*n>H):\
g=phase((l+w*1j-y)/(r+e*1j-y));A-=abs(g-sin(g)).real*t*t/2-z*q*(r-l);z=-z
    n-=s
    if(a<d)*s*n==-1:c=d
print A

换行符后面的内容\便于阅读,不计入分数。

通过STDIN读取输入作为对列表(center, radius),其中center是形式的复数X+Yj。该列表中的第一个圈是一个(其中心不必是在原点),和列表的其余部分是。将结果打印到STDOUT。

Input:  (0+0j, 138),  (100+0j, 100), (-50+-86j, 100), (-93+135j, 50)
Output: 18969.6900901

说明

这是我的(更长,更难看的:P)变体 对马丁·布特纳(MartinBüttner)的“自相交多边形”挑战区域的解决方案。它使用相同的技巧将问题分解为足够小的部分,因此变得更易于管理。

我们找到所有成对的圆之间的相交点(同时考虑AB中的圆),并通过其中的一条垂直线。此外,我们传递与任何圆相切的所有垂直线。我们扔掉一切不相交的线一个,这样所有的其余线路的左,右切线之间一个

图1

我们正在寻找AB中的圆的交集的区域-上图中的暗红色区域。这是我们必须从A中减去以获得结果的面积。

在每对连续的垂直线之间,可以将该区域分解为一组垂直梯形(或三角形或线段,作为梯形的特例),每条腿旁边都有一个“多余的”弧段。我们传递尽可能多的垂直线这一事实保证了边界区域确实没有比这复杂的了,因为否则,在该区域中的两条线之间必须有一个附加的交点,因此也需要一个附加的垂直线。题。

图2

为了找到这些梯形和弧段,对于每对连续的垂直线,我们找到恰好位于这两条线之间的每个圆的弧段(当然,某些圆在给定的一对线之间可能没有弧段) 。)在下图中,考虑两条红色垂直线时,它们是六个(亮和暗)黄色弧段。请注意,由于我们传递了所有与圆弧相切的垂直线,因此,如果圆弧在两条直线之间具有弧段,则它必定与两条直线相交,从而简化了其余算法。

并非所有这些弧都相关;我们只对AB的并集交点边界上的那些感兴趣。为了找到这些,我们从上到下对弧进行排序(请注意,弧可能不会正确地相交,因为这意味着我们正在考虑的弧之间存在另一条垂直线,因此进行讨论很有意义大约在任何其他弧的上方或下方的任意弧上。)

图3

我们依次遍历圆弧,同时保留我们当前位于其中的B个圆的数量n。如果当我们在A内时n从0变为1 ,或者当我们在A的顶弧上而n不为零时,则当前弧对应于梯形的一条边。如果在A内时n从1变为0 ,或者在n的底弧处一个同时ñ如果非零,则当前弧对应于同一梯形的另一边。找到一对弧(上图中的两个明亮的黄色弧)后,我们将计算相应的梯形和两个弧段的面积,并将其添加到要减去的总面积中 A

计算A的面积以及梯形的面积非常简单。每个弧段的面积是相应圆扇形的面积,减去其顶点是弧段的两个端点的三角形的面积以及相应圆的中心。

图4


1
这是我正在考虑的解决方案,除了我可以直接找到位于A但不位于B中的三面弧和梯形来找到目标区域(必须通过从三角形或梯形中减去圆弧段来找到目标区域)。
quintopia'1

@quintopia这可能甚至更短一些,因为它节省了我们计算A面积的需要,并且可能只需要考虑一下n的条件。
2016年

@quintopia OTOH,如果这是A的弧段,则必须考虑到一条腿附近有正弧的可能性,所以谁知道...
Ell

优秀的解决方案。昨晚我的脑子里出现了一个几乎与此完全相同的问题,我真的很想找人解决。您的解决方案比我正在使用的想法更好。
逻辑骑士
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.