两个圆圈之间的交叉区域

时间:2010-11-22 16:48:33

标签: math geometry

给出两个圈子:

  • C1(x1y1)与radius1
  • 的C1
  • C2 {({1}},x2)与y2

你如何计算他们的交叉区域?当然,所有标准数学函数(radius2sin等)都可用。

5 个答案:

答案 0 :(得分:26)

好的,使用Wolfram链接和Misnomer的提示来查看等式14,我使用我列出的变量和中心之间的距离(通常可以从它们中导出)得出以下Java解决方案:

Double r = radius1;
Double R = radius2;
Double d = distance;
if(R < r){
    // swap
    r = radius2;
    R = radius1;
}
Double part1 = r*r*Math.acos((d*d + r*r - R*R)/(2*d*r));
Double part2 = R*R*Math.acos((d*d + R*R - r*r)/(2*d*R));
Double part3 = 0.5*Math.sqrt((-d+r+R)*(d+r-R)*(d-r+R)*(d+r+R));

Double intersectionArea = part1 + part2 - part3;

答案 1 :(得分:22)

这是一个完全符合Chris之后的JavaScript函数:

function areaOfIntersection(x0, y0, r0, x1, y1, r1)
{
  var rr0 = r0 * r0;
  var rr1 = r1 * r1;
  var d = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
  var phi = (Math.acos((rr0 + (d * d) - rr1) / (2 * r0 * d))) * 2;
  var theta = (Math.acos((rr1 + (d * d) - rr0) / (2 * r1 * d))) * 2;
  var area1 = 0.5 * theta * rr1 - 0.5 * rr1 * Math.sin(theta);
  var area2 = 0.5 * phi * rr0 - 0.5 * rr0 * Math.sin(phi);
  return area1 + area2;
}

但是,如果一个圆圈完全位于另一个圆圈内,或者它们根本没有接触,则此方法将返回NaN。在这些条件下不会失败的略有不同的版本如下:

function areaOfIntersection(x0, y0, r0, x1, y1, r1)
{
  var rr0 = r0 * r0;
  var rr1 = r1 * r1;
  var d = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));

  // Circles do not overlap
  if (d > r1 + r0)
  {
    return 0;
  }

  // Circle1 is completely inside circle0
  else if (d <= Math.abs(r0 - r1) && r0 >= r1)
  {
    // Return area of circle1
    return Math.PI * rr1;
  }

  // Circle0 is completely inside circle1
  else if (d <= Math.abs(r0 - r1) && r0 < r1)
  {
    // Return area of circle0
    return Math.PI * rr0;
  }

  // Circles partially overlap
  else
  {
    var phi = (Math.acos((rr0 + (d * d) - rr1) / (2 * r0 * d))) * 2;
    var theta = (Math.acos((rr1 + (d * d) - rr0) / (2 * r1 * d))) * 2;
    var area1 = 0.5 * theta * rr1 - 0.5 * rr1 * Math.sin(theta);
    var area2 = 0.5 * phi * rr0 - 0.5 * rr0 * Math.sin(phi);

    // Return area of intersection
    return area1 + area2;
  }
}

我通过阅读Math Forum中的信息来编写此功能。我发现这比Wolfram MathWorld解释清楚了。

答案 2 :(得分:10)

您可能需要查看此analytical solution并将公式与输入值一起应用。

给出的另一个公式here -

Area = r^2*(q - sin(q))  where q = 2*acos(c/2r),
where c = distance between centers and r is the common radius.

答案 3 :(得分:0)

在这里,我正在基于圆交集制作字符生成工具...您可能会发现它很有用。

具有动态提供的圈子:

    C: {
        C1: {id: 'C1',x:105,y:357,r:100,color:'red'},
        C2: {id: 'C2',x:137,y:281,r:50, color:'lime'},
        C3: {id: 'C3',x:212,y:270,r:75, color:'#00BCD4'}
    },

检查全小提琴... FIDDLE

答案 4 :(得分:0)

这是Python中的示例。

"""Intersection area of two circles"""

import math
from dataclasses import dataclass
from typing import Tuple


@dataclass
class Circle:
    x: float
    y: float
    r: float

    @property
    def coord(self):
        return self.x, self.y


def find_intersection(c1: Circle, c2: Circle) -> float:
    """Finds intersection area of two circles.

    Returns intersection area of two circles otherwise 0
    """

    d = math.dist(c1.coord, c2.coord)
    rad1sqr = c1.r ** 2
    rad2sqr = c2.r ** 2

    if d == 0:
        # the circle centers are the same
        return math.pi * min(c1.r, c2.r) ** 2

    angle1 = (rad1sqr + d ** 2 - rad2sqr) / (2 * c1.r * d)
    angle2 = (rad2sqr + d ** 2 - rad1sqr) / (2 * c2.r * d)

    # check if the circles are overlapping
    if (-1 <= angle1 < 1) or (-1 <= angle2 < 1):
        theta1 = math.acos(angle1) * 2
        theta2 = math.acos(angle2) * 2

        area1 = (0.5 * theta2 * rad2sqr) - (0.5 * rad2sqr * math.sin(theta2))
        area2 = (0.5 * theta1 * rad1sqr) - (0.5 * rad1sqr * math.sin(theta1))

        return area1 + area2
    elif angle1 < -1 or angle2 < -1:
        # Smaller circle is completely inside the largest circle.
        # Intersection area will be area of smaller circle
        # return area(c1_r), area(c2_r)
        return math.pi * min(c1.r, c2.r) ** 2
    return 0


if __name__ == "__main__":

    @dataclass
    class Test:
        data: Tuple[Circle, Circle]
        expected: float

    tests = [
        Test((Circle(2, 4, 2), Circle(3, 9, 3)), 0),
        Test((Circle(0, 0, 2), Circle(-1, 1, 2)), 7.0297),
        Test((Circle(1, 3, 2), Circle(1, 3, 2.19)), 12.5664),
        Test((Circle(0, 0, 2), Circle(-1, 0, 2)), 8.6084),
        Test((Circle(4, 3, 2), Circle(2.5, 3.5, 1.4)), 3.7536),
        Test((Circle(3, 3, 3), Circle(2, 2, 1)), 3.1416)
    ]

    for test in tests:
        result = find_intersection(*test.data)
        assert math.isclose(result, test.expected, rel_tol=1e-4), f"{test=}, {result=}"

    print("PASSED!!!")