137°

夹点getGripPoints/捕捉点getOsnapPoints

已知圆外一点,以及圆心半径,求圆的切点:

方法1:

(b-y/a-x)*(n-y/m-x)=-1
(a-x)平方+(b-y)平方=r平方
联立方程组求解

方法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可以不用。
}

方法3:

int _tmain(int argc, _TCHAR* argv[])
{
double m = 2, n = 0;
double a = 0, b = 0;
double r = 1;

cout << "请输入圆心座标:";
cin >> a >> b;
cout << "请输入半径:";
cin >> r;
cout << "请输入点座标:";
cin >> m >> n;
// 点到圆心距离的平方
double d2 = ( m - a ) * ( m - a ) + ( n - b ) * ( n - b );
// 点到圆心距离
double d = sqrt( d2 );
// 半径的平方
double r2 = r * r;
if ( d2 < r2 )
{
cout << "点在圆内,无切点" << endl;
}
else if ( d2 == r2 )
{
cout << "点在圆上,切点为给定点:(" << m <<
", " << n << ")" << endl;
}
else
{
// 点到切点距离
double l = sqrt( d2 - r2 );
// 点->圆心的单位向量
double x0 = ( a - m ) / d;
double y0 = ( b - n ) / d;
// 计算切线与点心连线的夹角
double f = asin( r / d );
// 向正反两个方向旋转单位向量
double x1 = x0 * cos( f ) - y0 * sin( f );
double y1 = x0 * sin( f ) + y0 * cos( f );
double x2 = x0 * cos( -f ) - y0 * sin( -f );
double y2 = x0 * sin( -f ) + y0 * cos( -f );
// 得到新座标
x1 = ( x1 + m ) * l;
y1 = ( y1 + n ) * l;
x2 = ( x2 + m ) * l;
y2 = ( y2 + n ) * l;
cout << "点在圆外,切点有两个:(" << x1 << ", "
<< y1 << ")和(" << x2 << ", " << y2 << ")" << endl;
}

system( "pause" );
return 0;
}

方法4:

struct vect
{
	double dbX;
	double dbY;

	vect() {}

	vect(double x, double y)
	{
		dbX = x;
		dbY = y;
	}

	double len()
	{
		return sqrt(dbX*dbX + dbY * dbY);
	}

	vect rotate1(double cosF, double sinF)
	{
		double dbVectorLen = len();
		double sinA = dbY / dbVectorLen;
		double cosA = dbX / dbVectorLen;
		vect result;
		result.dbX = dbVectorLen * ((cosA * cosF) - (sinA * sinF));
		result.dbY = dbVectorLen * ((cosA * sinF) + (sinA * cosF));
		return result;
	}

	vect rotate2(double cosF, double sinF)
	{
		double dbVectorLen = len();
		double sinA = dbY / dbVectorLen;
		double cosA = dbX / dbVectorLen;
		vect result;
		result.dbX = (dbX* cosF) - (dbY * sinF);
		result.dbY = (dbX * sinF) + (dbY * cosF);
		return result;
	}

	//把vector变成指定长度的向量
	void Normalize(double dbLen)
	{
		if (dbLen <= 0) return;
		double dbVectorLen = len();
		if (dbVectorLen == 0)return;
		dbX = dbX * dbLen / dbVectorLen;
		dbY = dbY * dbLen / dbVectorLen;
	}
	
};

struct Point
{
	double x;
	double y;
};

// 圆心x  外点 半径  切点p1 切点p 2
void GetVector(double dbCenterX, double dbCenterY, double dbOutX, double dbOutY, double rad, Point& p1, Point& p2)
{
	//圆心o 到外点p 切点q 其中oq的长度为半径的长度
	vect op(dbOutX - dbCenterX, dbOutY - dbCenterY);
	double opLen = op.len();
	double pqLen = sqrt((opLen * opLen) - (rad * rad));	//算出切线长度

	//算出夹角 qop 这个夹角可以为正负
	double cosA = rad / opLen;
	double sinA = pqLen / opLen;

	//长度变为半径的向量
	op.Normalize(rad);
	//
	auto res1 = op.rotate2(cosA, sinA);
	//然后圆心
	//结果1就是
	p1.x = res1.dbX + dbCenterX;
	p1.y = res1.dbY + dbCenterY;
	//
	auto res2 = op.rotate2(cosA, -sinA);
	//然后圆心
	//结果2就是
	p2.x = res2.dbX + dbCenterX;
	p2.y = res2.dbY + dbCenterY;
}

 

本文由【一个小妞】发布于开源中国,原文链接:https://my.oschina.net/u/2930533/blog/2885458

全部评论: 0

    我有话说: