两个圆相切当且仅当圆心距等于半径和或半径差的绝对值;需校验半径非负,用平方距离与容差eps避免浮点误差,统一判定外切与内切。

判断两个圆是否相切:核心是距离与半径关系
两个圆在二维平面中相切,本质只有两种情况:外切(两圆在切点处彼此接触但不重叠)和内切(一圆在另一圆内部,仅一点接触)。二者统一的数学条件是:圆心距等于两半径之和(外切)或等于两半径之差的绝对值(内切)。因此,只需计算圆心距离 d,再比对 abs(r1 - r2) 和 r1 + r2 即可。
注意浮点数比较必须用误差容限(EPS),不能直接用 ==。常见错误是忽略内切时大圆小圆顺序无关,必须用 abs(r1 - r2);另一个坑是未处理退化情况(如半径为 0 或负数),建议提前校验。
- 设圆 A 圆心
(x1, y1)、半径r1,圆 B 圆心(x2, y2)、半径r2 - 先做参数检查:
r1 >= 0且r2 >= 0,否则无几何意义 - 计算平方距离避免开方误差和性能损耗:
dx = x1 - x2; dy = y1 - y2; d_sq = dx*dx + dy*dy - 定义容差:
const double EPS = 1e-9;
C++ 实现相切判定函数
推荐封装为布尔函数,返回 true 当且仅当发生外切或内切(不含相交或分离)。关键在于用平方形式避免 sqrt 引入额外误差,并统一用平方容差比较。
bool isTangent(double x1, double y1, double r1,
double x2, double y2, double r2) {
if (r1 <p>这个写法规避了 <code>sqrt</code> 的精度损失和运行开销;<code>eps_sq</code> 对应 <code>1e-9</code> 容差的平方,更稳妥。若输入含大量整数坐标,也可用 <code>long long</code> 算平方距离防溢出。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h3>区分内切与外切:需要额外逻辑</h3><p>如果业务需要知道是哪种相切(比如物理引擎中碰撞响应不同),不能只靠距离相等——需结合圆心距与半径关系进一步判断:</p>
- 外切成立条件:
d_sq == (r1 + r2)²(在容差内) - 内切成立条件:
d_sq == (r1 - r2)²且r1 != r2;若r1 == r2,则内切退化为同心圆不相切(除非d_sq == 0,此时两圆重合,不算相切) - 特别注意:当
r1 == r2且d_sq ,两圆完全重合,不属于相切(几何定义要求“恰好一个公共点”)
所以严格来说,内切还隐含前提:一圆完全在另一圆内部(即 d + min(r1,r2) ),但该条件等价于 <code>d_sq —— 而相切时取等号,因此只要满足内切距离条件且半径不等,即自动满足位置关系。
容易被忽略的边界与精度问题
实际工程中栽跟头的往往不是公式本身,而是这些细节:
-
r1或r2为0:点圆是否与另一圆相切?按标准定义,点圆(半径 0)与圆相切当且仅当点在圆周上,即d_sq == r²;但多数场景应显式排除r == 0,除非业务明确支持 - 使用
float代替double:容差需相应调至1e-5左右,且平方误差放大更快,建议统一用double - 坐标值极大(如
1e15)时,dx*dx可能溢出double;此时应先归一化或用相对误差判断 - 多个圆批量检测时,避免重复计算
dx/dy,可预存向量差
真正麻烦的从来不是“怎么写”,而是“什么算数、什么不算”——比如两个半径极接近的圆,圆心距略小于半径差,数值上可能落在容差带边缘,这时得看你的业务能否接受模糊判定。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










