web-dev-qa-db-ja.com

円上の接点を見つけますか?

最初の終点P(x1、y1)を持つ線が与えられた場合、別の終点は不明であり、1つの点(接線)T(x2、y2)のみで半径Rの原点にある円と交差します。ポイントTを取得する方法を知っている人はいますか?前もって感謝します!

13
HanWu

最初の終点P(x1、y1)を持つ線が与えられた場合、別の終点は不明であり、1つの点(接線)T(x2、y2)のみで半径Rの原点にある円と交差します。ポイントTを取得する方法を知っている人はいますか?

他の解決策のいくつかは少しやり過ぎのようです。最も簡単な方法は、これが頂点P、T、およびO(原点)を持つ直角三角形であることに気付くことです。接線は常に半径に対して直角であるため、角度PTOは直角です。

TOの長さは、長さがrであり、原点に頂点があるため、わかります。 OPOがどこにあるかを知っているので、Pを知っています。直角三角形の2つの辺が与えられると、3番目の辺の長さと方向を簡単に見つけることができます。これは宿題なので、残りは読者の練習問題として残しておきます。

                    __...------__    T(x2, y2)                      
               _.-''             -(+)
            ,-'                   |----             
          ,'                     |     ----
        ,'                      |       '  ----
       /                       |         `     ----       
      /                       |           `.       ----   
     /                       |             \           ----
    |                       |               |              ----
    |                      |                 |                  ----
    |                     |                  |                      ----
    |                   (+)---------------------------------------------(+) P (x1,y1)
    |                                        .'        
    |                    O                   |         
     |                                      .'         
      \                                     /          
       \                                  ,'           
        `                                /             
         '.                            ,'              
           '-.                      _,'             
              '-._              _,(+)  T'(x3, y3)                   
                  '`--......---'                       

点T 'も有効な接点であるため、TOには2つの可能な方向があり、2つの合同な三角形があります。

39
John Feminella

必要なのは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) };
16
imbrizi

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;
}
7
Len Li
  1. ベクトルの方向を見つけることができます[〜#〜] dx [〜#〜]ベクトルを回転させると[〜#〜] do [〜#〜]角度によるalpha(角度alphaはasin(len(OX)/ len(DO))として検出されます。これは、単に半径の弧です。斜辺以上)

  2. ベクトルの長さ[〜#〜] dx [〜#〜]は、次のように簡単に見つけることができます。sqrt(len(DO )* len(DO)-len(OX)* len(OX))

  3. ベクトルの方向と長さを考えると[〜#〜] 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番目の接線もあることに注意してください。

Image demonstrating the algo

3
Timur Nuriyasov

これが宿題であることは私にはわかりませんが、直角三角形が定義されているという直感は好きです。それでも、そのソリューションにはいくつかの代数があります。

実行可能と思われる別のアプローチは、問題を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は未定義です。単純な距離とピタゴラスの定理に依存する他のアプローチは、そのイベントに対して堅牢です。

2
user85109

交差する方程式のx、y座標(円の座標と線の座標)を使用します。それがポイントです。

線を引くための終点が1つしかない場合は、上と下の2つの異なる接線があるため、2つの異なる点が得られます。

1
andandandand

私は通常、Mapleソフトウェアを使用してこのような問題を解決します。それらの方程式からCコードを生成することもできます。

enter image description here

出力は次のとおりです。

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を追加する必要があります。また、平方根を取る前に負の値を確認する必要があります。

1
Soonts

別の解決策; dmindreaderよりもエレガントではありませんが、理解しやすいかもしれません。

Tが円上にあり、線OTが線PTに垂直であることを知っています。

それはあなたに

abs(O - T) = R
dotProduct(O - T, P - T) = 0
0
cube