2つの円の接線を求める
2円の接線のパターン
2つの円に引かれる接線を求めてみましょう。
2円の接線が存在する条件としては、
・片方の円がもう片方の円内部に完全に含まれないこと
となります。
上図の場合は接線存在はしません。当然のことながら、
上図のような同心円もそれに含まれます。
では存在するパターンはどのようなものが考えられるでしょうか。
・2円が重なりあう場合
・2円が離れている場合
が考えられます。以下参照してください。
上図は「2円が重なりあう場合」です。この場合、接線は2種類、接点は4点存在します。
上図は「2円が離れている場合」です。この場合、接線は4種類、接点は8点存在します。
このように図示してみるとわかりやすいのですが、いざプログラムで求めようとすると結構面倒になります。
プログラム
ごちゃごちゃ説明するよりもプログラムで示すほうがいいでしょう。
早速プログラム書いてみます。このプログラムでは浮動小数点演算の例外処理をあえて書いてないので、利用時は注意してください。
また求める接線は、接点群として結果を返します。関数自体の返値は接点数です。
#define GEO_ERR_01 5.0 // 同心円か否かの判定距離 #define GEO_ERR_02 5.0 // 接しているか否かの判定距離 #define FABS(x) ((x) < 0.0 ? -(x) : (x)) typedef struct { double x ; double y ; } FPOINT ; typedef struct { FPOINT pc ; double r ; } FCIRCLE ; //--------------------------------------------------------------------------------------------- // // 円と円の接点を求める(接線) // //--------------------------------------------------------------------------------------------- int geoGetTangentOf2CC( FCIRCLE cc1, // 第1円 FCIRCLE cc2, // 第2円 FPOINT *pt) // 接点群(接線群をなしている) { int ind = 0 ; int loop ; double dx, dy, cr, d1, d2, d3, sn, cs ; double xr[8], yr[8] ; if (cc1.r <= 0.0 || cc2.r <= 0.0) goto ret ; dx = cc2.pc.x - cc1.pc.x ; dy = cc2.pc.y - cc1.pc.y ; cr = sqrt(dx * dx + dy * dy) ; if (cr <= GEO_ERR_01) goto ret ; d1 = cc1.r - cc2.r - cr ; d2 = cc2.r - cc1.r - cr ; d3 = cr - cc1.r - cc2.r ; if ( d1 > GEO_ERR_02 || d2 > GEO_ERR_02) goto ret ; if (FABS(d1) <= GEO_ERR_02 || FABS(d2) <= GEO_ERR_02) goto ret ; if (d3 > GEO_ERR_02) { ind = 8 ; } else { ind = 4 ; } xr[0] = cc1.r * (cc1.r - cc2.r) / cr ; yr[0] = sqrt(cc1.r * cc1.r - xr[0] * xr[0]) ; xr[1] = cc2.r * (cc1.r - cc2.r) / cr ; yr[1] = sqrt(cc2.r * cc2.r - xr[1] * xr[1]) ; xr[1] += cr ; xr[2] = xr[0] ; yr[2] = -yr[0] ; xr[3] = xr[1] ; yr[3] = -yr[1] ; if (ind == 8) { xr[4] = cc1.r * (cc1.r + cc2.r) / cr ; yr[4] = sqrt(cc1.r * cc1.r - xr[4] * xr[4]) ; xr[5] = -cc2.r * (cc1.r + cc2.r) / cr ; yr[5] = -sqrt(cc2.r * cc2.r - xr[5] * xr[5]) ; xr[5] += cr ; xr[6] = xr[4] ; yr[6] = -yr[4] ; xr[7] = xr[5] ; yr[7] = -yr[5] ; } sn = dy / cr ; cs = dx / cr ; for (loop = 0 ; loop < ind ; ++loop) { pt[loop].x = xr[loop] * cs - yr[loop] * sn + cc1.pc.x ; pt[loop].y = xr[loop] * sn + yr[loop] * cs + cc1.pc.y ; } ret:; return ind ; }