1. 程式人生 > >已知圓外一點,圓心和半徑,求過圓外點的直線與圓的切點演算法

已知圓外一點,圓心和半徑,求過圓外點的直線與圓的切點演算法

CPoint CalcQieDian(CPoint ptCenter, CPoint ptOutside, double dbRadious) 
{ 
    struct point {double x, y;};
 point E,F,G,H;
 double r=dbRadious;
 //1. 座標平移到圓心ptCenter處,求園外點的新座標E
 E.x= ptOutside.x-ptCenter.x;
 E.y= ptOutside.y-ptCenter.y; //平移變換到E
 
 //2. 求園與OE的交點座標F, 相當於E的縮放變換
 double t= r / sqrt (E.x * E.x + E.y * E.y);  //得到縮放比例
 F.x= E.x * t;   F.y= E.y * t;   //縮放變換到F

 //3. 將E旋轉變換角度a到切點G,其中cos(a)=r/OF=t, 所以a=arccos(t);
 double a=acos(t);   //得到旋轉角度
 G.x=F.x*cos(a) -F.y*sin(a);
 G.y=F.x*sin(a) +F.y*cos(a);    //旋轉變換到G

 //4. 將G平移到原來的座標下得到新座標H
 H.x=G.x+ptCenter.x;
 H.y=G.y+ptCenter.y;             //平移變換到H
    
 //5. 返回H
 return CPoint(int(H.x),int(H.y));
 //6. 實際應用過程中,只要一箇中間變數E,其他F,G,H可以不用。
}

應該說方法有很多種,幾何的,代數的,做的過程中也在紙上運算了好長時間,可能也是這些知識很久沒用了,生疏很多。解出來的公式都比較複雜,無意間在網上找到這個方法,沒經過具體的筆算驗證,但是求出來的結果是我預判範圍的,暫定為計算結果是正確的。在這邊共享下,有需要的童鞋不妨自己驗證一下。

對了,這個函式只能返回一個點,理論上有兩個切點的,只要把15行改成如下:

 double a=-acos(t);   //得到旋轉角度