两圆相交当且仅当|r1−r2|≤d≤r1+r2;其中d为圆心距,需用浮点误差容限eps避免精度问题。

判断两圆是否相交的数学前提
直接算交点前,必须先确认几何上是否存在交点。否则会得到无意义的复数解或空结果。核心是用圆心距 d 和两圆半径 r1、r2 做比较:
– 若 d > r1 + r2:相离,无交点
– 若 d :内含(且不相切),无交点<br>
– 若 <code>d == 0 && r1 == r2:同心圆重合,无穷多交点(退化情况,通常不处理)
– 其余情况:0 个(内切/外切)、1 个(相切)或 2 个(相交)实交点
用向量投影法推导交点坐标的公式
标准解法是把问题平移到以第一个圆心为原点,沿圆心连线方向建立临时坐标系,再反变换回去。关键中间量:
– 计算圆心距:d = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
– 求投影长度:a = (r1*r1 - r2*r2 + d*d) / (2*d)(即从圆1圆心到公共弦中点的距离)
– 求半弦长:h = sqrt(r1*r1 - a*a)(注意:若 r1*r1 - a*a ,说明数值误差或本该无解,应提前返回)<br>
– 单位方向向量:<code>ex_x = (x2-x1)/d, ey_y = (y2-y1)/d
– 垂直单位向量:ey_x = -ey_y, ey_y = ex_x(即逆时针旋转90°)
交点为:(x1 + a<em>ex_x ± h</em>ey_x, y1 + a<em>ex_y ± h</em>ey_y)
C++ 实现时容易出错的细节
– 浮点比较不能用 == 判断相切,要用 abs(d - (r1+r2)) 等容差判断<br>
– <code>d 接近 0 时除零风险:必须先检查 d 再计算 <code>a 和单位向量
– sqrt(r1*r1 - a*a) 的被开方数可能因浮点误差略小于 0,建议用 max(0.0, r1*r1 - a*a) 包裹
– 如果只想要两个交点,但实际是相切(h ≈ 0),返回两个相同点即可,不必特殊分支
– 坐标类型推荐用 double,float 在半径差大或距离远时易失精度
struct Point { double x, y; };
vector<Point> circle_intersection(Point c1, double r1, Point c2, double r2) {
double dx = c2.x - c1.x, dy = c2.y - c1.y;
double d = sqrt(dx*dx + dy*dy);
const double eps = 1e-9;
if (d < eps) return {}; // 同心
if (d > r1 + r2 + eps || d < abs(r1 - r2) - eps) return {};
<pre class='brush:php;toolbar:false;'>double a = (r1*r1 - r2*r2 + d*d) / (2*d);
double h_sq = r1*r1 - a*a;
if (h_sq < 0) h_sq = 0;
double h = sqrt(h_sq);
double ex_x = dx / d, ex_y = dy / d;
double ey_x = -ex_y, ey_y = ex_x;
return {
{c1.x + a*ex_x - h*ey_x, c1.y + a*ex_y - h*ey_y},
{c1.x + a*ex_x + h*ey_x, c1.y + a*ex_y + h*ey_y}
};}
立即学习“C++免费学习笔记(深入)”;
交点计算本身不难,真正花时间的是边界条件的鲁棒性处理——尤其是浮点误差在几何判定中的放大效应,这点比公式本身更值得反复验证。


















