重叠圆的合并区域


107

我最近遇到一个问题,我有四个圆(中点和半径),必须计算这些圆的并集面积。

示例图片:

对于两个圈子来说,这很容易

我可以计算出不在三角形内的每个圆面积的分数,然后计算三角形的面积。

但是,当有两个以上的圆圈时,是否可以使用一种聪明的算法?


15
这是一个非常有趣的问题,我记得在高中几何课上曾见过,但从未找到解决方案。如果您在这里找不到答案,请尝试将其发布在mathoverflow.net上,让数学家对此有所了解:P
Charles Ma

25
有时,真正的程序员需要真正的数学
fa。

1
找出这个问题的答案又如何呢?“我们的销售代表住在这4个地点,每个人为这4个半径的区域提供服务。我们覆盖的国家范围是多少?” 如果您有一个不断变化的销售代表数据库,这将成为编程问题!
克里斯·罗伯茨

5
实际上,这是真正的程序员喜欢考虑的问题。
MAK,

2
@zvolkov:电路板用一种语言描述,该语言可将正方形和圆形向下拖拉并可选地拖动它们。“计算铜面积”。(这可需要计算蚀刻时间,知道是否添加清除艺术品,各种事情。)
DigitalRoss

Answers:


97

在外周上找到所有圆的交点(例如下图的B,D,F,H)。将它们与相应圆的中心连接在一起以形成多边形。圆并集的面积是多边形的面积+由连续相交点和它们之间的圆心定义的圆片的面积。您还需要解决所有漏洞。

圆重叠


17
中心有孔怎么办?
约翰·吉岑

3
您需要从总数中减去孔的中心连接的多边形,并将该多边形的圆切片添加到总数中。
2009年

3
很好,但是我想这将需要很多实现细节来处理所有特殊情况(其他情况下为圆形,无相交,孔,单点接触...)
fa。

1
特殊情况很容易。其他内部的圆由于没有任何周边相交而被丢弃。一点接触实际上是两个零距离的交点。如果中心距离小于半径之和,则可以通过连接零件算法在图形上找到断开的形状,其中连接了两个圆。孔是除面积最大的多边形以外的所有多边形。周边相交是指严格不在任何圆内的所有相交。
蚂蚁阿斯玛09年

4
是的,但是孔的边界也是(小)弧。我仍然认为这需要很多代码才能正常工作。
fa。

32

我敢肯定有一个聪明的算法,但这是一个愚蠢的算法,省去了寻找它的麻烦。

  • 在圆圈周围放一个边界框;
  • 在边界框中生成随机点;
  • 找出随机点是否在圆圈之一内;
  • 通过一些简单的加法和除法计算面积(proportion_of_points_inside * area_of_bounding_box)。

当然是愚蠢的,但是:

  • 您可以根据需要获得尽可能准确的答案,只需获得更多的分数即可;
  • 它适用于您可以计算内部/外部差异的任何形状;
  • 它将完美地并行化,因此您可以使用所有内核。

2
这是可行的,但是像这种基于统一采样的蒙特卡洛方法通常没有最佳的收敛速度。
ShreevatsaR

2
抱歉,尽管我感谢您的努力并且认为您的解决方案“切实可行”,但我认为您的方法非常错误。这是一个应该解决的问题,应该通过数学而不是蛮力解决。在这种问题上浪费精力和核心是浪费和奢侈的。
mafu

5
您是对的,我为自己感到羞耻,但是我拥有一个拥有12,000个核心的集群,我可以负担得起。而且我不知道如何使优雅的数学解决方案扩展到这么多处理器。
高性能Mark

8
蒙特卡洛方法(或任何随机方法)在本质上没有错,只要它能提供所需的准确度并在合理的时间内即可做到。
MAK

@mafutrct,您当然是对的。但是,在数学上容易犯一些小错误。该解决方案提供了一种测试正确性的简单方法。
理查德

18

蚂蚁·阿斯玛(Ants Aasma)的答案给出了基本概念,但我想使其更为具体。看一下下面的五个圆圈以及它们的分解方式。

例

  • 蓝点是圆圈中心。
  • 红点是圆边界交点。
  • 内部具有白色的红点是圆边界的交点,不在任何其他圆中

识别这三种类型的点很容易。现在构造一个图形数据结构,其中节点是内部为白色的蓝点和红点。对于每个圆,在圆心(蓝色圆点)与其交点(内部为白色的红点)的边界之间放置一条边。

这会将圆形并集分解为一组成对不相交并覆盖原始并集(即一个分区)的多边形(蓝色阴影)和圆形饼图(绿色阴影)。由于这里的每个零件都易于计算面积,因此您可以通过将零件的面积相加来计算并集的面积。


我认为我可以很容易地计算出一组红色/白色点,但是我的图论并不是太好:从算法上讲,如何从节点列表+边列表中得出计算区域?
user999305 2015年

1
通过使用一组非重叠三角形而不是多边形可以简化算法。弧(绿色区域)是仅包含一个圆的区域。添加更多的圆时,请扩展多边形的大小。(最后您可能会忘记甚至在谈论多边形)。它使布尔属性和面积也更容易计算。当空心的红点变为实心的红点时,您只需在集合中添加更多三角形,然后调整弧,它就会被越来越多的相交圆“吃掉”。
史蒂夫(Steve)

16

对于与前一个解决方案不同的解决方案,您可以使用四叉树产生具有任意精度的估计。

如果您可以判断正方形是在内部还是外部或与该形状相交,则此方法也适用于任何形状并集。

每个单元格都具有以下状态之一:空,满,部分

该算法包括以低分辨率(例如4个单元标记为空)开始“绘制”四叉树中的圆。每个单元格为:

  • 在至少一个圆圈内,然后将单元格标记为已满,
  • 在所有圆圈之外,将单元格标记为空,
  • 否则将单元格标记为部分。

完成后,您可以计算面积的估计值:完整的单元格给出较低的边界,空白的单元格给出较高的边界,部分单元格给出最大的面积误差。

如果误差对您来说太大,则可以优化部分像元,直到获得正确的精度为止。

我认为这比处理许多特殊情况可能需要的几何方法更容易实现。


3
我的猜测是,这将比蒙特卡洛内/外点算法收敛得更快。
Frank Krueger

这似乎确实易于实现。绝对是建议的最佳蛮力方法。谢谢!
安东·汉森,2009年

这里的蛮力称为挤压定理
fa。

这就是您在区间算术中使用的算法。en.wikipedia.org/wiki/Interval_arithmetic
rjmunro

13

我喜欢2个相交圆的情况下的方法-在更复杂的示例中,我将使用相同方法的细微变化。

它可能会更好地了解泛化大量半重叠圆的算法。

此处的区别在于,我从链接中心开始(因此,在圆心之间有一个顶点,而不是在圆心相交的地方之间有一个顶点),我认为这样可以更好地进行概括。

(实际上,也许蒙特卡洛方法值得)

替代文字
(来源:secretGeek.net


1
我认为对图像进行建议的多边形划分可能是一种很好的方法。有很多细节需要解决以进行编码。它如何处理一个由20个圆组成的链,每个链仅与链中的最后一个和下一个重叠?易于手工找出,但是您的算法是什么?
PeterAllenWebb,2009年

4

如果您想要离散(而不是连续)的答案,则可以执行类似于像素绘制算法的操作。

在网格上绘制圆圈,然后为网格的每个单元格(如果其大部分包含在圆内)着色(即,至少50%的面积在一个圆圈内)。对整个网格执行此操作(该网格跨越圆圈所覆盖的所有区域),然后计算网格中有色单元的数量。


3

嗯,非常有趣的问题。我的方法可能类似于以下内容:

  • 找出一种方法,可以计算出任意数量的圆之间的交集区域,即,如果我有3个圆,则需要能够计算出这些圆之间的交集是什么。“蒙特卡洛”方法将是近似此方法的好方法(http://local.wasp.uwa.edu.au/~pbourke/geometry/circlearea/)。
  • 消除完全包含在另一个较大圆中的所有圆(请看一下半径和两个圆心之间的距离的模数),我认为这不是强制性的。
  • 选择2个圆圈(分别称为A和B),并使用以下公式计算总面积:

(对于任何形状,无论是圆形还是其他形状,都是如此)

area(A∪B) = area(A) + area(B) - area(A∩B)

哪里 A ∪ B意思是A的并集B和A ∩ BA的相交B(您可以从第一步开始计算。

  • 现在继续添加圆并继续计算添加的面积,以求和/减去圆的面积和圆之间的交点的面积。例如,对于3个圆(称为额外的圆C),我们使用以下公式计算区域:

(与上面A替换为的情况相同A∪B

area((A∪B)∪C) = area(A∪B) + area(C) - area((A∪B)∩C)

area(A∪B)我们刚制定出来的,并area((A∪B)∩C)可以发现:

area((A∪B)nC) = area((A∩C)∪(B∩C)) = area(A∩C) + area(A∩B) - area((A∩C)∩(B∩C)) = area(A∩C) + area(A∩B) - area(A∩B∩C)

再次可以从上方找到区域(A∩B∩C)。

棘手的是最后一步-添加的圆圈越多,它变得越复杂。我相信可以用有限的联合来计算交叉点的面积,或者您可以递归地进行求解。

另外,关于使用蒙特卡洛近似计算迭代区域,我相信可以将任意数量的圆的交点减少为这些圆的4个交点,这可以精确计算(不知道如何执行此操作)然而)。

顺便说一句,也许有更好的方法-添加的每个额外的圆的复杂度会显着增加(可能呈指数增长,但我不确定)。


格式如何?也为使用n和u进行交集和并集感到遗憾,这可能是更好的方法……
Justin

1
添加了一些unicode联合(∪)和交集(∩)的符号。希望他们能工作。
Spoike

3

我一直在研究模拟重叠的星场的问题,试图从密集场中的实际磁盘区域估计真实的恒星数,在该区域中较大的明亮恒星可以掩盖较暗的恒星。我也曾希望能够通过严格的形式分析来做到这一点,但无法找到用于该任务的算法。我通过在蓝色背景上将星场生成为绿色磁盘来解决它,其直径由概率算法确定。一个简单的例程可以将它们配对以查看是否存在重叠(将星对变成黄色);然后颜色的像素计数会生成观察到的面积,以与理论面积进行比较。然后,这会为真实计数生成概率曲线。也许是蛮力的,但似乎行得通。(来源:2from.com


2

这是一种在实践中应该易于实现的算法,可以对其进行调整以产生任意小的误差:

  1. 用以同一点为中心的规则多边形近似每个圆
  2. 计算作为近似圆的并集的多边形
  3. 计算合并多边形的面积

步骤2和步骤3可以使用易于计算的标准算法从计算几何中进行。

显然,您为每个近似多边形使用的边数越多,您的答案就越接近精确。您可以使用内切和外切多边形进行近似,以得出确切答案的范围。


2

使用所谓的功率图,可以有效解决此问题。虽然这确实是沉重的数学运算,但我不想立即解决。对于“简单”的解决方案,请查找行扫描算法。这里的基本原理是将图形划分为条带,在其中计算每个条带的面积相对容易。

因此,在包含所有未擦掉的所有圆的图形上,在每个位置绘制一条水平线,该位置是圆的顶部,圆的底部或2个圆的交点。请注意,在这些条带中,您需要计算的所有区域看起来都相同:一个“梯形”,其两侧被圆形线段代替。因此,如果您能算出如何计算这种形状,则只需对所有单个形状进行处理,然后将它们加在一起即可。这种幼稚方法的复杂度为O(N ^ 3),其中N是图中的圆圈数。通过使用一些巧妙的数据结构,可以将此行扫描方法改进为O(N ^ 2 * log(N)),但是除非您确实需要,否则可能不值得麻烦。



1

根据您要解决的问题,它可能足以获得一个上限和下限。上限很容易,只是所有圆的总和。对于下限,您可以选择一个半径,以使所有圆都不重叠。为了更好地找到每个圆的最大半径(不超过实际半径),使其不重叠。删除所有完全重叠的圆(所有这些圆都满足| P_a-P_b | <= r_a)也应该是微不足道的,其中P_a是圆A的中心,P_b是圆B的中心,r_a是A的半径),这样可以同时提高上下限。如果您在任意对上使用对公式,而​​不仅仅是所有圆的总和,则还可以获得更好的上限。可能有一个选择“最佳”的好方法

给定一个上限和下限,您也许可以更好地调整蒙特卡洛方法,但是没有什么特别的主意。另一个选择(同样取决于您的应用程序)是栅格化圆圈并计算像素。它基本上是具有固定分布的蒙特卡洛方法。


0

这可以使用格林定理来解决,其复杂度为n ^ 2log(n)。如果您不熟悉格林定理,并且想了解更多,这里是可汗学院的视频笔记。但是为了我们的问题,我认为我的描述就足够了。

很抱歉,无法链接到照片,因为我无法发布图像。(信誉评分不足)

格林定理的一般方程

如果我把LM这样

健康)状况

那么RHS就是区域R的面积,可以通过求解闭合积分或LHS来获得,这正是我们要做的。

可以将所有并集分解为相交的不相交的圆集

因此,沿逆时针方向的路径积分可以得到该区域的面积,而沿顺时针方向的积分则可以得到该面积的负数。所以

AreaOfUnion =(逆时针方向沿红色弧的积分+顺时针方向沿蓝色弧的积分)

但是很酷的窍门是,如果对于每个圆,如果我们对不在任何其他圆内的弧进行积分,则得到所需的面积,即沿所有红色弧在逆时针方向上进行积分,而沿顺时针方向在所有蓝弧上进行积分。任务完成!!!

即使一个圆不与其他圆相交的情况也可以解决。

这是我的C ++代码的GitHub链接


-1

像素绘制方法(由@Loadmaster建议)在多种方面优于数学解决方案:

  1. 实施简单得多。正如JSFiddle解决方案所展示的,上述问题可以用不到100行代码来解决。(主要是因为从概念上讲它简单得多,并且没有情况或异常可以处理)。
  2. 它很容易适应更一般的问题。只要它可以在2D图形库(即“所有图形!”)中可渲染,就可以使用任何形状(无论其形态如何)—圆形,椭圆形,样条曲线,多边形,您都可以命名。哎呀,甚至位图图像。
  3. 与数学解决方案的〜O [n * n]相比,像素绘制解决方案的复杂度为〜O [n]。这意味着随着形状数量的增加,它的性能会更好。
  4. 谈到性能,您通常会免费获得硬件加速,因为大多数现代2D库(例如,我相信HTML5的画布)会将渲染工作转移到图形加速器上。

像素绘制的一个缺点是解决方案的精度有限。但这可以通过根据情况需要简单地渲染到更大或更小的画布来调整。还要注意,2D渲染代码中的抗锯齿(通常默认情况下处于启用状态)将产生优于像素级别的精度。因此,例如,我认为将100x100的图形渲染到相同尺寸的画布中时,产生的精度应为1 /(100 x 100 x 255)= .000039%的数量级……这可能“足够好”除了最苛刻的问题之外的所有问题。

<p>Area computation of arbitrary figures as done thru pixel-painting, in which a complex shape is drawn into an HTML5 canvas and the area determined by comparing the number of white pixels found in the resulting bitmap.  See javascript source for details.</p>

<canvas id="canvas" width="80" height="100"></canvas>

<p>Area = <span id="result"></span></p>
// Get HTML canvas element (and context) to draw into
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// Lil' circle drawing utility
function circle(x,y,r) {
  ctx.beginPath();
  ctx.arc(x, y, r, 0, Math.PI*2);
  ctx.fill();
}

// Clear canvas (to black)
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// Fill shape (in white)
ctx.fillStyle = 'white';
circle(40, 50, 40);
circle(40, 10, 10);
circle(25, 15, 12);
circle(35, 90, 10);

// Get bitmap data
var id = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixels = id.data; // Flat array of RGBA bytes

// Determine area by counting the white pixels
for (var i = 0, area = 0; i < pixels.length; i += 4) {
  area += pixels[i]; // Red channel (same as green and blue channels)
}

// Normalize by the max white value of 255
area /= 255;

// Output result
document.getElementById('result').innerHTML = area.toFixed(2);

该解决方案无法解决用圆的面积进行数学计算的问题。它错过了OP问题的重点。在处理几何形状时,渲染几何通常仅是成功的一半
Steve
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.