给定两个圆圈:
x1
, y1
) 与 radius1
x2
, y2
) 与 radius2
如何计算它们相交的面积?当然,所有标准数学函数(
sin
、cos
等)都可用。
好吧,使用 Wolfram 链接和错误的提示来查看方程 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;
这是一个 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;
}
但是,如果一个圆完全位于另一个圆内,或者它们根本不接触,则此方法将返回 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;
}
}
我通过阅读在数学论坛找到的信息编写了这个函数。我发现这比 Wolfram MathWorld 的解释更清楚。
这里我正在制作基于圆交叉的角色生成工具......你可能会发现它很有用。
动态提供的圆圈:
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'}
},
检查完整的小提琴... 小提琴
这是一个 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!!!")
答案是在java中使用d的中心和测试用例之间的距离“d”。 希望有帮助! 谢谢1
import java.util.*;
public class FindInDictionary {
public static void main(String[] args){
System.out.println(areaOfIntersection(5,1,3,5,3,4));
}
static double areaOfIntersection(int x0,int y0,int r0,int x1,int y1,int r1){
double PI=3.14;
double d=Math.sqrt(((x1-x0)*(x1-x0))+((y1-y0)*(y1-y0)));//distance between the centers
if(d>r0+r1)//circle are far away from each other ,ie. no intersection
{
return 0;
}
if((d<(r0-r1)) &&(r0>r1)){
return PI*r1*r1;// Smaller circle is completely inside the larger one
}
if((d<=r1-r0) && r1>=r0){
return PI*r0*r0;// Larger circle is completely inside the smaller one
}
if(d==r1+r0)
{
return 0;//both circle just touches the edge of each other without any overlapping
}
double aplha=Math.acos(((r0*r0)+(d*d)-(r1*r1))/(2*r0*d))*2;
double beta=Math.acos(((r1*r1)+(d*d)-(r0*r0))/(2*r1*d))*2;
double aLeftSector=(aplha*r0*r0)/2;
double aLeftTri=0.5*r0*r0*Math.sin(aplha);
double aRightHalfCircle=aLeftSector-aLeftTri;
// aRightHalfCircle=(((r0*r0)/2)*(aplha-Math.sin(aplha))); simplify the formula
double aLeftHalfCircle=(((r1*r1)/2)*(beta-Math.sin(beta)));
return aRightHalfCircle+aLeftHalfCircle;
}
}