最初の終点P(x1、y1)を持つ線が与えられた場合、別の終点は不明であり、1つの点(接線)T(x2、y2)のみで半径Rの原点にある円と交差します。ポイントTを取得する方法を知っている人はいますか?前もって感謝します!
最初の終点P(x1、y1)を持つ線が与えられた場合、別の終点は不明であり、1つの点(接線)T(x2、y2)のみで半径Rの原点にある円と交差します。ポイントTを取得する方法を知っている人はいますか?
他の解決策のいくつかは少しやり過ぎのようです。最も簡単な方法は、これが頂点P、T、およびO(原点)を持つ直角三角形であることに気付くことです。接線は常に半径に対して直角であるため、角度PTOは直角です。
TO
の長さは、長さがr
であり、原点に頂点があるため、わかります。 OP
とO
がどこにあるかを知っているので、P
を知っています。直角三角形の2つの辺が与えられると、3番目の辺の長さと方向を簡単に見つけることができます。これは宿題なので、残りは読者の練習問題として残しておきます。
__...------__ T(x2, y2)
_.-'' -(+)
,-' |----
,' | ----
,' | ' ----
/ | ` ----
/ | `. ----
/ | \ ----
| | | ----
| | | ----
| | | ----
| (+)---------------------------------------------(+) P (x1,y1)
| .'
| O |
| .'
\ /
\ ,'
` /
'. ,'
'-. _,'
'-._ _,(+) T'(x3, y3)
'`--......---'
点T 'も有効な接点であるため、TO
には2つの可能な方向があり、2つの合同な三角形があります。
必要なのはdmckeeの答えだけですが、コードが必要な場合は、JavascriptとHTMLキャンバスを使用してこの実装を確認してください。
完全な例:http://jsfiddle.net/zxqCw/1/
// find tangents
dx = cx - px;
dy = cy - py;
dd = Math.sqrt(dx * dx + dy * dy);
a = Math.asin(radius / dd);
b = Math.atan2(dy, dx);
t = b - a
ta = { x:radius * Math.sin(t), y:radius * -Math.cos(t) };
t = b + a
tb = { x:radius * -Math.sin(t), y:radius * Math.cos(t) };
R
を円の半径とし、D
を円の外部点から中心までの距離としてD > R
。
接線が作る角度と\alpha
外部点と中心を結ぶ線で、ここで
\alpha = arcsin(R/D)
外部点(P
)と中心(C
)を結ぶ線は、の水平線と角度をなします。
\beta = arctan((C_y - P_y)/(C_x - P_x))
これにより、水平線との接線の角度が次のようになります。
\theta = \beta +/- \alpha
あいまいさに注意してください。
接線セグメントの長さは
L = sqrt(D^2 - R^2)
必要なのはこれだけです。
imbriziの答えは、円の中心が(0,0)であると想定しています。
これはObjectiveCの正解です。
- (NSArray *)pointsTangentToCircleWithCenter:(CGPoint)centerPoint
radius:(CGFloat)radius
outerPoint:(CGPoint)outerPoint {
float dx = centerPoint.x - outerPoint.x;
float dy = centerPoint.y - outerPoint.y;
float dd = sqrt(dx*dx + dy*dy);
float a = asinf(radius / dd);
float b = atan2f(dy, dx);
float t1 = b - a;
CGPoint tangentPoint1 = CGPointMake(centerPoint.x + radius*sinf(t1),
centerPoint.y + radius*-cosf(t1));
float t2 = b + a;
CGPoint tangentPoint2 = CGPointMake(centerPoint.x + radius*-sinf(t2),
centerPoint.y + radius*cosf(t2));
NSArray *points = @[
[NSValue valueWithCGPoint:tangentPoint1],
[NSValue valueWithCGPoint:tangentPoint2]
];
return points;
}
ベクトルの方向を見つけることができます[〜#〜] dx [〜#〜]ベクトルを回転させると[〜#〜] do [〜#〜]角度によるalpha(角度alphaはasin(len(OX)/ len(DO))として検出されます。これは、単に半径の弧です。斜辺以上)
ベクトルの長さ[〜#〜] dx [〜#〜]は、次のように簡単に見つけることができます。sqrt(len(DO )* len(DO)-len(OX)* len(OX))
ベクトルの方向と長さを考えると[〜#〜] dx [〜#〜]、point[ 〜#〜] x [〜#〜]。 1つのアプローチは、[〜#〜] dx [〜#〜]を正規化し、その長さを乗算することです。
auto dist = D.Distance(O); auto side = sqrt(dist*dist - rad*rad) auto line = Vector2D(D, O); line.Rotate(asin(rad / dist)); //get the direction line.Normalize(); //set length to 1 line*=side; //we have the direction, now get length Point2D X = D + line;
P.S. [〜#〜] do [〜#〜]をマイナスalpha回転させることで見つかる2番目の接線もあることに注意してください。
これが宿題であることは私にはわかりませんが、直角三角形が定義されているという直感は好きです。それでも、そのソリューションにはいくつかの代数があります。
実行可能と思われる別のアプローチは、問題を2つの未知数の2つの方程式の解として単純に定義することです。つまり、(0,0)を中心とし、半径Rの円の方程式は次のようになります。
x^2 + y^2 = R^2
点(xt、yt)を通過し、(未知の)傾きSを持つ直線の方程式は次のとおりです。
(y - yt) = S*(x - xt)
交点の2つの方程式のシステムを解きます。 Sの値に応じて、この方程式のペアには0、1、または2つの解があります。また、解が一意になるようにSの値が2つあることがわかります。解を一意にするSの2つの値を解き、交点(xt、yt)を復元します。これが宿題である場合、実際の解決策については詳しく説明しませんが、その部分は自明な代数です。
私のポイントは、この代数的アプローチは、計算幾何学の問題の解決策を見る別の方法であるということです。接点で円と交差する2本の線があり、線が接点で交差する場合、1つの交点があるという点で興味深い点を強調しています。
このアプローチの欠点は、いくつかの問題の特異点が原因で失敗することです。つまり、傾きSの線が垂直の場合、Sは未定義です。単純な距離とピタゴラスの定理に依存する他のアプローチは、そのイベントに対して堅牢です。
交差する方程式のx、y座標(円の座標と線の座標)を使用します。それがポイントです。
線を引くための終点が1つしかない場合は、上と下の2つの異なる接線があるため、2つの異なる点が得られます。
私は通常、Mapleソフトウェアを使用してこのような問題を解決します。それらの方程式からCコードを生成することもできます。
出力は次のとおりです。
t1 = v_x * v_x;
t2 = t1 * t1;
t3 = v_y * v_y;
t6 = sqrt(t1 * t3 - t1 + t2);
t7 = v_y + t6;
t9 = 0.1e1 / (t1 + t3);
t13 = 0.1e1 / v_x;
x1 = -(t7 * t9 * v_y - 0.1e1) * t13;
y1 = t7 * t9;
t16 = (-v_y + t6) * t9;
x2 = -(-t16 * v_y - 0.1e1) * t13;
y2 = -t16;
明らかに、変数にfloatまたはdoubleを追加する必要があります。また、平方根を取る前に負の値を確認する必要があります。
別の解決策; dmindreaderよりもエレガントではありませんが、理解しやすいかもしれません。
点T
が円上にあり、線OT
が線PT
に垂直であることを知っています。
それはあなたに
abs(O - T) = R
dotProduct(O - T, P - T) = 0