11.06_圆圆关系

圆圆关系

问题描述

圆圆关系处理平面上两个圆之间的基本关系,包括相交判断、交点计算等。常用于碰撞检测和几何构造问题。

基本操作

算法思想

  1. 使用圆心距离判断
  2. 基于半径关系判断
  3. 适用于相交和包含判断
  4. 时间复杂度

代码实现

class Solution {
public:
    // 判断两圆位置关系
    // 返回值: -2内含 -1内切 0相交 1外切 2相离
    int circlePosition(const Circle& c1, const Circle& c2) {
        double d = c1.center.distance(c2.center);
        double r1 = c1.radius, r2 = c2.radius;
        
        if (d < abs(r1 - r2) - EPS) return -2;  // 内含
        if (abs(d - abs(r1 - r2)) < EPS) return -1;  // 内切
        if (d < r1 + r2 + EPS) return 0;  // 相交
        if (abs(d - (r1 + r2)) < EPS) return 1;  // 外切
        return 2;  // 相离
    }
    
    // 计算两圆交点
    vector<Point> circleIntersection(const Circle& c1, const Circle& c2) {
        int pos = circlePosition(c1, c2);
        if (pos < 0 || pos > 1) return {};  // 内含、内切、相离、外切
        
        double d = c1.center.distance(c2.center);
        double r1 = c1.radius, r2 = c2.radius;
        
        // 余弦定理计算角度
        double angle = acos((r1 * r1 + d * d - r2 * r2) / (2 * r1 * d));
        Point v = (c2.center - c1.center).normalize() * r1;
        
        return {
            c1.center + v.rotate(angle),
            c1.center + v.rotate(-angle)
        };
    }
    
    // 计算两圆公共面积
    double commonArea(const Circle& c1, const Circle& c2) {
        int pos = circlePosition(c1, c2);
        if (pos == -2) {  // 内含
            double r = min(c1.radius, c2.radius);
            return M_PI * r * r;
        }
        if (pos >= 1) return 0;  // 外切或相离
        
        double d = c1.center.distance(c2.center);
        double r1 = c1.radius, r2 = c2.radius;
        
        // 余弦定理计算角度
        double angle1 = acos((r1 * r1 + d * d - r2 * r2) / (2 * r1 * d));
        double angle2 = acos((r2 * r2 + d * d - r1 * r1) / (2 * r2 * d));
        
        // 扇形面积减去三角形面积
        return r1 * r1 * angle1 + r2 * r2 * angle2 - 
               d * r1 * sin(angle1);
    }
};
class Solution {
    static final double EPS = 1e-10;
    static final double PI = Math.PI;
    
    // 判断两圆位置关系
    // 返回值: -2内含 -1内切 0相交 1外切 2相离
    public int circlePosition(Circle c1, Circle c2) {
        double d = c1.center.distance(c2.center);
        double r1 = c1.radius, r2 = c2.radius;
        
        if (d < Math.abs(r1 - r2) - EPS) return -2;  // 内含
        if (Math.abs(d - Math.abs(r1 - r2)) < EPS) return -1;  // 内切
        if (d < r1 + r2 + EPS) return 0;  // 相交
        if (Math.abs(d - (r1 + r2)) < EPS) return 1;  // 外切
        return 2;  // 相离
    }
    
    // 计算两圆交点
    public List<Point> circleIntersection(Circle c1, Circle c2) {
        int pos = circlePosition(c1, c2);
        if (pos < 0 || pos > 1) return new ArrayList<>();
        
        double d = c1.center.distance(c2.center);
        double r1 = c1.radius, r2 = c2.radius;
        
        // 余弦定理计算角度
        double angle = Math.acos((r1 * r1 + d * d - r2 * r2) / (2 * r1 * d));
        Point v = c2.center.subtract(c1.center).normalize().multiply(r1);
        
        return Arrays.asList(
            c1.center.add(v.rotate(angle)),
            c1.center.add(v.rotate(-angle))
        );
    }
    
    // 计算两圆公共面积
    public double commonArea(Circle c1, Circle c2) {
        int pos = circlePosition(c1, c2);
        if (pos == -2) {  // 内含
            double r = Math.min(c1.radius, c2.radius);
            return PI * r * r;
        }
        if (pos >= 1) return 0;  // 外切或相离
        
        double d = c1.center.distance(c2.center);
        double r1 = c1.radius, r2 = c2.radius;
        
        // 余弦定理计算角度
        double angle1 = Math.acos((r1 * r1 + d * d - r2 * r2) / (2 * r1 * d));
        double angle2 = Math.acos((r2 * r2 + d * d - r1 * r1) / (2 * r2 * d));
        
        // 扇形面积减去三角形面积
        return r1 * r1 * angle1 + r2 * r2 * angle2 - 
               d * r1 * Math.sin(angle1);
    }
}
class Solution:
    def __init__(self):
        self.EPS = 1e-10
        self.PI = math.pi
    
    # 判断两圆位置关系
    # 返回值: -2内含 -1内切 0相交 1外切 2相离
    def circle_position(self, c1: Circle, c2: Circle) -> int:
        d = c1.center.distance(c2.center)
        r1, r2 = c1.radius, c2.radius
        
        if d < abs(r1 - r2) - self.EPS:
            return -2  # 内含
        if abs(d - abs(r1 - r2)) < self.EPS:
            return -1  # 内切
        if d < r1 + r2 + self.EPS:
            return 0  # 相交
        if abs(d - (r1 + r2)) < self.EPS:
            return 1  # 外切
        return 2  # 相离
    
    # 计算两圆交点
    def circle_intersection(self, c1: Circle, c2: Circle) -> List[Point]:
        pos = self.circle_position(c1, c2)
        if pos < 0 or pos > 1:
            return []
        
        d = c1.center.distance(c2.center)
        r1, r2 = c1.radius, c2.radius
        
        # 余弦定理计算角度
        angle = math.acos((r1 * r1 + d * d - r2 * r2) / (2 * r1 * d))
        v = (c2.center - c1.center).normalize() * r1
        
        return [
            c1.center + v.rotate(angle),
            c1.center + v.rotate(-angle)
        ]
    
    # 计算两圆公共面积
    def common_area(self, c1: Circle, c2: Circle) -> float:
        pos = self.circle_position(c1, c2)
        if pos == -2:  # 内含
            r = min(c1.radius, c2.radius)
            return self.PI * r * r
        if pos >= 1:
            return 0  # 外切或相离
        
        d = c1.center.distance(c2.center)
        r1, r2 = c1.radius, c2.radius
        
        # 余弦定理计算角度
        angle1 = math.acos((r1 * r1 + d * d - r2 * r2) / (2 * r1 * d))
        angle2 = math.acos((r2 * r2 + d * d - r1 * r1) / (2 * r2 * d))
        
        # 扇形面积减去三角形面积
        return r1 * r1 * angle1 + r2 * r2 * angle2 - \
               d * r1 * math.sin(angle1)

时间复杂度分析

操作 时间复杂度 空间复杂度
位置关系判断
交点计算
公共面积计算
包含判断

应用场景

  1. 碰撞检测
  2. 几何构造
  3. 区域判断
  4. 面积计算
  5. 相交判断

注意事项

  1. 浮点数精度
  2. 特殊情况处理
  3. 相切判断
  4. 内含判断
  5. 数值稳定性

常见变形

  1. 圆的包含关系
class Solution {
public:
    // 判断圆c1是否完全包含圆c2
    bool circleContains(const Circle& c1, const Circle& c2) {
        double d = c1.center.distance(c2.center);
        return d <= c1.radius - c2.radius + EPS;
    }
    
    // 计算多个圆的并集面积
    double unionArea(vector<Circle>& circles) {
        int n = circles.size();
        if (n == 0) return 0;
        
        double area = 0;
        for (int i = 0; i < (1 << n); i++) {
            double common = 0;
            int cnt = 0;
            Circle c;
            bool valid = true;
            
            for (int j = 0; j < n; j++) {
                if (i & (1 << j)) {
                    if (cnt == 0) {
                        c = circles[j];
                    } else {
                        common += commonArea(c, circles[j]);
                    }
                    cnt++;
                }
            }
            
            if (cnt > 0) {
                if (cnt % 2 == 1) {
                    area += c.area() - common;
                } else {
                    area -= common;
                }
            }
        }
        
        return area;
    }
};
class Solution {
    // 判断圆c1是否完全包含圆c2
    public boolean circleContains(Circle c1, Circle c2) {
        double d = c1.center.distance(c2.center);
        return d <= c1.radius - c2.radius + EPS;
    }
    
    // 计算多个圆的并集面积
    public double unionArea(Circle[] circles) {
        int n = circles.length;
        if (n == 0) return 0;
        
        double area = 0;
        for (int i = 0; i < (1 << n); i++) {
            double common = 0;
            int cnt = 0;
            Circle c = null;
            boolean valid = true;
            
            for (int j = 0; j < n; j++) {
                if ((i & (1 << j)) != 0) {
                    if (cnt == 0) {
                        c = circles[j];
                    } else {
                        common += commonArea(c, circles[j]);
                    }
                    cnt++;
                }
            }
            
            if (cnt > 0) {
                if (cnt % 2 == 1) {
                    area += c.area() - common;
                } else {
                    area -= common;
                }
            }
        }
        
        return area;
    }
}
class Solution:
    # 判断圆c1是否完全包含圆c2
    def circle_contains(self, c1: Circle, c2: Circle) -> bool:
        d = c1.center.distance(c2.center)
        return d <= c1.radius - c2.radius + self.EPS
    
    # 计算多个圆的并集面积
    def union_area(self, circles: List[Circle]) -> float:
        n = len(circles)
        if n == 0:
            return 0
        
        area = 0
        for i in range(1 << n):
            common = 0
            cnt = 0
            c = None
            valid = True
            
            for j in range(n):
                if i & (1 << j):
                    if cnt == 0:
                        c = circles[j]
                    else:
                        common += self.common_area(c, circles[j])
                    cnt += 1
            
            if cnt > 0:
                if cnt % 2 == 1:
                    area += c.area() - common
                else:
                    area -= common
        
        return area
  1. 圆的相交集合
class Solution {
public:
    // 计算多个圆的交集面积
    double intersectionArea(vector<Circle>& circles) {
        int n = circles.size();
        if (n == 0) return 0;
        
        // 检查是否存在交集
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (circlePosition(circles[i], circles[j]) > 0) {
                    return 0;  // 存在不相交的圆
                }
            }
        }
        
        // 找到最小包含圆
        double area = circles[0].area();
        for (int i = 1; i < n; i++) {
            area = min(area, commonArea(circles[0], circles[i]));
        }
        
        return area;
    }
};
class Solution {
    // 计算多个圆的交集面积
    public double intersectionArea(Circle[] circles) {
        int n = circles.length;
        if (n == 0) return 0;
        
        // 检查是否存在交集
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (circlePosition(circles[i], circles[j]) > 0) {
                    return 0;  // 存在不相交的圆
                }
            }
        }
        
        // 找到最小包含圆
        double area = circles[0].area();
        for (int i = 1; i < n; i++) {
            area = Math.min(area, commonArea(circles[0], circles[i]));
        }
        
        return area;
    }
}
class Solution:
    # 计算多个圆的交集面积
    def intersection_area(self, circles: List[Circle]) -> float:
        n = len(circles)
        if n == 0:
            return 0
        
        # 检查是否存在交集
        for i in range(n):
            for j in range(i + 1, n):
                if self.circle_position(circles[i], circles[j]) > 0:
                    return 0  # 存在不相交的圆
        
        # 找到最小包含圆
        area = circles[0].area()
        for i in range(1, n):
            area = min(area, self.common_area(circles[0], circles[i]))
        
        return area
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务