核心概述:计算两圆的外公切线(令 r2 取相反数可得内公切线),返回 0/1/2 对切点,含相切与退化判定,时间 O(1)。

Description: Finds the external tangents of two circles, or internal if r2 is negated. Can return 0, 1, or 2 tangents — 0 if one circle contains the other (or overlaps it, in the internal case, or if the circles are the same); 1 if the circles are tangent to each other (in which case .first = .second and the tangent line is perpendicular to the line between the centers). .first and .second give the tangency points at circle 1 and 2 respectively. To find the tangents of a circle with a point set r2 to 0.

展开阐述:

  • 定义与背景

    • 问题:给定圆 (c1, r1)、(c2, r2),求它们的公切线切点对 {(t1, t2)},每对对应一条切线,t1 位于圆1,t2 位于圆2。
    • 能力边界:当两圆同心或内含(对“外公切线”情形),不存在有效公切线;当两圆相切,仅存在一条公切线(返回一对相同的切点)。
    • 接口(据实现):
      • tangents(c1, r1, c2, r2) vector<pair<P,P>>,支持外/内公切线;将 r2 取相反数即可切换外↔内。
      • 特例“点与圆”切线:令 r2=0。
  • 核心算法流程(闭式向量法)

    1. 设 d = c2 − c1,d2 = |d|²,dr = r1 − r2,h2 = d2 − dr²。
    2. 退化与不可行:
      • 若 d2 == 0(同心)或 h2 < 0(外切线下“一圆包含另一圆”,或内切线下“重叠”),无解,返回空。
    3. 构造方向向量:
      • 对 sign ∈ {−1, +1},令 v = (d * dr + d.perp() * sqrt(h2) * sign) / d2。
      • 切点对为:{c1 + v * r1, c2 + v * r2}。
    4. 相切去重:
      • 若 h2 == 0,仅保留其中一对(两条切线重合为一条)。
    5. 返回 0/1/2 对切点。
  • 复杂度与边界条件

    • 复杂度:常数时间 O(1)。
    • 边界:
      • 同心(d2==0):无公切线(无限多条不经过圆的公共法线并非“切线”)。
      • 内含(h2<0):外公切线不存在;对“内公切线”情形也可能无解(当两圆重叠或相同)。
      • 相切(h2==0):仅一条切线,切点对合并为一对。
      • 点与圆:r2=0 时返回过该点的两条切线切点(若几何可行)。
    • 数值稳定性:
      • 使用 double 时 sqrt(h2) 在 h2≈0 可能出现微小负值,可用 eps 上夹:h2 < −eps 视为无解,|h2| ≤ eps 视为相切。
      • d2 作为分母,避免 d2 极小导致数值爆炸;同心情形已提前返回。
  • 实现细节与常见坑

    • d.perp() 表示将向量 d 旋转 90°(方向依实现而定),用以构建两条对称切线的法向分量。
    • 返回为切点对而非切线显式表达式;若需切线方程可将切点与圆心连线之法向得到。
    • “内公切线”通过令 r2 取相反数统一到同一公式,避免另写一套推导。
    • 切点顺序:两圆切点一一对应;遍历 sign 可得到两条(或一条)切线。
  • 变体与扩展

    • 圆与点(r2=0):求过点的圆切线切点。
    • 圆与直线:可用020-几何-圆与直线相交转化或直接投影求切点。
    • 多圆批量切线:可用于构造圆弧可见轮廓或通行走廊的边界线段。
  • 正确性要点与不变式

    • 构造的 v 同时满足到两圆的切向一致性:v 在两圆切点处的切向方向一致,且半径向与切线垂直。
    • h2 的几何意义为“梯形高度平方”,其非负性刻画两圆存在实切线的必要条件。
  • 对比与取舍

    • 与解联立方程(圆方程+切线约束)的代数法相比,向量闭式法更简洁、数值表现更稳健。
    • 与枚举角度的数值解相比,闭式法 O(1) 且精确。

关联节点