简体   繁体   English

两圆相交面积

[英]Area of Intersection between Two Circles

Given two circles:给定两个圆圈:

  • C1 at ( x1 , y1 ) with radius1 C1 在 ( x1 , y1 ) radius1
  • C2 at ( x2 , y2 ) with radius2 C2 在 ( x2 , y2 ) 处, radius2

How do you calculate the area of their intersection?你如何计算它们相交的面积? All standard math functions ( sin , cos , etc.) are available, of course.当然,所有标准数学函数( sincos等)都可用。

Okay, using the Wolfram link and Misnomer's cue to look at equation 14, I have derived the following Java solution using the variables I listed and the distance between the centers (which can trivially be derived from them):好的,使用 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;

Here is a JavaScript function that does exactly what Chris was after:这是一个 JavaScript 函数,它完全符合 Chris 的要求:

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;
}

However, this method will return NaN if one circle is completely inside the other, or they are not touching at all.但是,如果一个圆完全在另一个圆内,或者它们根本不接触,则此方法将返回 NaN。 A slightly different version that doesn't fail in these conditions is as follows:在这些条件下不会失败的略有不同的版本如下:

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;
    }
}

I wrote this function by reading the information found at the Math Forum .我通过阅读数学论坛上的信息编写了这个函数。 I found this clearer than the Wolfram MathWorld explanation.我发现这比Wolfram MathWorld 的解释更清楚。

You might want to check out this analytical solution and apply the formula with your input values.您可能想要查看此解析解并将公式应用到您的输入值中。

Another Formula is given here for when the radii are equal:当半径相等时,这里给出另一个公式:

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

Here is an example in Python.这是 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!!!")

Here here i was making character generation tool, based on circle intersections... you may find it useful.在这里,我正在制作基于圆形交叉点的字符生成工具……您可能会发现它很有用。

with dynamically provided circles:使用动态提供的圆圈:

    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'}
    },

Check FULL fiddle... FIDDLE检查完整的小提琴... FIDDLE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM