已知圆外一点,圆心和半径,求过圆外点的直线与圆的切点算法

时间:2022-09-19 09:45:50
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);   //得到旋转角度