概要

円1: 中心\((x_1, y_1)\) 半径\(r_1\) と 円2: 中心\((x_2, y_2)\) 半径\(r_2\) の2つの円がなす共通接線の接点を求める。

今回は円1の方の共通内接線(最大2本)と共通外接線(最大2本)の接点を計算する。

具体的計算

2つの円の中心間の距離を\(r_0\)とし、 \(d_x = x_2 - x_1\), \(d_y = y_2 - y_1\) とした時、接点を

  • \(\displaystyle \left( \begin{array}{c} x_1 \\ y_2 \end{array} \right) + \frac{r_1}{r_0} R(\theta) \left( \begin{array}{c} d_x \\ d_y \end{array} \right)\)

として考える (\(R(\theta)\)は\(2 \times 2\)の回転行列)

この時、

  • 共通内接線の場合は \(\displaystyle |\cos \theta| = \frac{|r_1 - r_2|}{r_0}\)

  • 共通外接線の場合は \(\displaystyle |\cos \theta| = \frac{r_1 + r_2}{r_0}\)

を満たす。(実際に図を書いてみると確認できる)

この時 \(|\cos \theta| > 1\) の場合は接線が存在しない。また、\(|\cos \theta| = 1\) の場合は接線が1本のみ存在する。

実装

AOJ: "CGL_7_G: Circles - Common Tangent"で提出した実装のPython3版

x1, y1, r1 = map(int, input().split())
x2, y2, r2 = map(int, input().split())

from math import sqrt

def solve(x1, y1, r1, x2, y2, r2):
    result = []
    xd = x2 - x1; yd = y2 - y1

    rr0 = xd**2 + yd**2
    if (r1 - r2)**2 <= rr0:
        # 共通外接線
        cv = r1 - r2
        if rr0 == (r1 - r2)**2:
            # 円が内接する場合 => 共通外接線は1本
            result.append((x1 + r1*cv*xd/rr0, y1 + r1*cv*yd/rr0))
        else:
            sv = sqrt(rr0 - cv**2)
            # (x1, y1) + r1/r0*R(±θ)(x2 - x1, y2 - y1)
            result.append((x1 + r1*(cv*xd - sv*yd)/rr0, y1 + r1*(sv*xd + cv*yd)/rr0))
            result.append((x1 + r1*(cv*xd + sv*yd)/rr0, y1 + r1*(-sv*xd + cv*yd)/rr0))
    if (r1 + r2)**2 <= rr0:
        # 共通内接線
        cv = r1 + r2
        if rr0 == (r1 + r2)**2:
            # 円が外接する場合 => 共通内接線は1本
            result.append((x1 + r1*cv*xd/rr0, y1 + r1*cv*yd/rr0))
        else:
            sv = sqrt(rr0 - cv**2)
            # (x1, y1) + r1/r0*R(±θ)(x2 - x1, y2 - y1)
            result.append((x1 + r1*(cv*xd - sv*yd)/rr0, y1 + r1*(sv*xd + cv*yd)/rr0))
            result.append((x1 + r1*(cv*xd + sv*yd)/rr0, y1 + r1*(-sv*xd + cv*yd)/rr0))
    return result

result = sorted(solve(x1, y1, r1, x2, y2, r2))
if result:
    print("\n".join("%.08f %.08f" % p for p in result))

Verified

  • AOJ: "CGL_7_G: Circles - Common Tangent": source (Python2, 0.01sec)