//
从圆弧一些信息得到圆弧上一个特殊的点(计算的是二维图形的情况)
Point3d DBOPERATION::GetArcTangencyPoint(Point3d pStartPoint, Point3d pEndPoint,
Point3d pCenterPoint,
double
dRadius,
double
dStartAngle,
double
dSweepAngle)
{
Point3d pResultPoint;
pResultPoint.X
=
0
;
pResultPoint.Y
=
0
;
pResultPoint.Z
=
0
;
//
因为会得到两个点,哪个点在弧上需要再进行判断
double
dRx1
=
0
;
double
dRx2
=
0
;
double
dRy1
=
0
;
double
dRy2
=
0
;
const
double
PI
=
3.1415926535897932
;
Point3d pMiddlePoint;
pMiddlePoint.X
=
(pStartPoint.X
+
pEndPoint.X)
/
2
;
pMiddlePoint.Y
=
(pStartPoint.Y
+
pEndPoint.Y)
/
2
;
pMiddlePoint.Z
=
0.0
;
//
扫角的角度值
double
dArcSweepAngle
=
180
*
dSweepAngle
/
PI;
//
中点到圆心的距离
double
ddy
=
0
;
double
ddx
=
0
;
if
(pMiddlePoint.X
-
pCenterPoint.X
>=
0.1e-6
)
{
ddx
=
pMiddlePoint.X
-
pCenterPoint.X;
}
if
(pMiddlePoint.Y
-
pCenterPoint.Y
>=
0.1e-6
)
{
ddx
=
pMiddlePoint.Y
-
pCenterPoint.Y;
}
double
dDistance
=
sqrt(ddx
*
ddx
+
ddy
*
ddy);
if
((fabs(pMiddlePoint.Y
-
pCenterPoint.Y)
<
0.1e-6
&&
fabs(pMiddlePoint.X
-
pCenterPoint.X)
<
0.1e-6
)
&&
(fabs(pStartPoint.X
-
pEndPoint.X)
<
0.1e-6
||
fabs(pStartPoint.Y
-
pEndPoint.Y)
<
0.1e-6
))
{
//
半圆且斜率=0或者斜率为无穷大的情况
if
(fabs(pStartPoint.X
-
pEndPoint.X)
<
0.1e-6
)
{
//
结果的两个X的值
dRx1
=
pMiddlePoint.X
+
(dRadius
-
dDistance);
dRx2
=
pMiddlePoint.X
-
(dRadius
+
dDistance);
//
对应的两个Y的值
dRy1
=
pMiddlePoint.Y;
dRy2
=
pMiddlePoint.Y;
}
if
(fabs(pStartPoint.Y
-
pEndPoint.Y)
<
0.1e-6
)
{
//
结果的两个X的值
dRx1
=
pMiddlePoint.X;
dRx2
=
pMiddlePoint.X;
//
对应的两个Y的值
dRy1
=
pMiddlePoint.Y
+
(dRadius
-
dDistance);
dRy2
=
pMiddlePoint.Y
-
(dRadius
+
dDistance);
}
}
else
if
(fabs(pMiddlePoint.Y
-
pCenterPoint.Y)
<
0.1e-6
&&
fabs(pMiddlePoint.X
-
pCenterPoint.X)
>=
0.1e-6
)
{
//
圆心与端点中心点在水平线上的情况,斜率=0
//
结果的两个X的值
dRx1
=
pMiddlePoint.X
+
(dRadius
-
dDistance);
dRx2
=
pMiddlePoint.X
-
(dRadius
+
dDistance);
//
对应的两个Y的值
dRy1
=
pMiddlePoint.Y;
dRy2
=
pMiddlePoint.Y;
}
else
if
(fabs(pMiddlePoint.X
-
pCenterPoint.X)
<
0.1e-6
&&
fabs(pMiddlePoint.Y
-
pCenterPoint.Y)
>=
0.1e-6
)
{
//
圆心与端点中心点在垂直线上的情况,斜率=无穷大
//
结果的两个X的值
dRx1
=
pMiddlePoint.X;
dRx2
=
pMiddlePoint.X;
//
对应的两个Y的值
dRy1
=
pMiddlePoint.Y
+
(dRadius
-
dDistance);
dRy2
=
pMiddlePoint.Y
-
(dRadius
+
dDistance);
}
else
{
//
圆弧两个端点成线的斜率,已经排除了等于0或者无穷大的可能性
double
dTheKSAE
=
(pEndPoint.Y
-
pStartPoint.Y)
/
(pEndPoint.X
-
pStartPoint.X);
//
与端点组成的线垂直的线的斜率(0度,180度,360度弧的dk需要特殊处理)
double
dK
=
(
1
/
dTheKSAE)
*
(
-
1
);
if
(fabs(fabs(dArcSweepAngle)
-
360
)
<
0.1e-6
)
{
dK
=
(pMiddlePoint.Y
-
pCenterPoint.Y)
/
(pMiddlePoint.X
-
pCenterPoint.X);
}
if
(fabs(fabs(dArcSweepAngle)
-
180
)
<
0.1e-6
)
{
dK
=
(pStartPoint.Y
-
pCenterPoint.Y)
/
(pStartPoint.X
-
pCenterPoint.X);
dK
=
(
1
/
dK)
*
(
-
1
);
}
if
(fabs(fabs(dArcSweepAngle)
-
0
)
<
0.1e-6
)
{
dK
=
(pMiddlePoint.Y
-
pCenterPoint.Y)
/
(pMiddlePoint.X
-
pCenterPoint.X);
}
/
//
这是经过两端点中点并与两端点组成的直线垂直的直线的方程
//
k为斜率,M(x),M(y)分别为中心点坐标值
//
y=k * x - k * M(x) + M(y)
/
//
求出- k * M(x) + M(y)部分的值
double
dDif
=
(
-
1
)
*
dK
*
pMiddlePoint.X
+
pMiddlePoint.Y;
/
//
[x - C(x)]^2 + [y - C(y)]^2 = r^2
//
代入上面的y,其中- k * M(x) + M(y)以dDif代替
//
[x - C(x)]^2 + [kx + dDif - C(y)]^2 = r^2
//
下面以dBetween代替+ dDif - C(y)
/
double
dBetween
=
dDif
-
pCenterPoint.Y;
/
//
x^2 + 2*C(x)*x + [C(x)]^2
//
+
//
(kx)^2 + 2*k*dBetween*x + (dBetween)^2
//
= r^2
/
//
再求中间值
double
dNx
=
(
2
*
dK
*
dBetween
-
2
*
pCenterPoint.X)
/
(
1
+
dK
*
dK);
double
dLa
=
(dRadius
*
dRadius
-
pCenterPoint.X
*
pCenterPoint.X
-
dBetween
*
dBetween)
/
(
1
+
dK
*
dK);
double
dAd
=
dLa
+
dNx
*
dNx
/
4
;
//
结果的两个X的值
dRx1
=
sqrt(dAd)
-
dNx
/
2
;
dRx2
=
(
-
1
)
*
sqrt(dAd)
-
dNx
/
2
;
//
对应的两个Y的值
dRy1
=
dK
*
dRx1
-
dK
*
pMiddlePoint.X
+
pMiddlePoint.Y;
dRy2
=
dK
*
dRx2
-
dK
*
pMiddlePoint.X
+
pMiddlePoint.Y;
}
//
对得到的两个点进行判断,找到在弧上的那个
pResultPoint.X
=
dRx1;
pResultPoint.Y
=
dRy1;
if
(fabs(fabs(dArcSweepAngle)
-
180.0
)
<
0.1e-4
)
{
//
半圆情况处理
double
p1x,p1y,p2x,p2y,qx,qy,dx1,dy1,dx2,dy2,det;
p2x
=
pStartPoint.X;
p2y
=
pStartPoint.Y;
p1x
=
pCenterPoint.X;
p1y
=
pCenterPoint.Y;
qx
=
dRx2;
qy
=
dRy2;
dx1
=
p2x
-
p1x;
dy1
=
p2y
-
p1y;
dx2
=
qx
-
p2x;
dy2
=
qy
-
p2y;
det
=
dx1
*
dy2
-
dx2
*
dy1;
BOOL bBlockWise
=
TRUE;
if
(det
>
0.0
)
{
//
逆时针方向
bBlockWise
=
FALSE;
}
if
(((
!
bBlockWise)
&&
(dArcSweepAngle
>
0.0
))
||
((bBlockWise)
&&
(dArcSweepAngle
<
0.0
)))
{
pResultPoint.X
=
dRx2;
pResultPoint.Y
=
dRy2;
}
}
else
{
//
非半圆的情况
double
dd1
=
sqrt(pow(dRx1
-
pMiddlePoint.X,
2
)
+
pow(dRy1
-
pMiddlePoint.Y,
2
));
double
dd2
=
sqrt(pow(dRx2
-
pMiddlePoint.X,
2
)
+
pow(dRy2
-
pMiddlePoint.Y,
2
));
if
(((dd1
<
dd2)
&&
(fabs(dArcSweepAngle)
>
180.0
))
||
((dd1
>
dd2)
&&
(fabs(dArcSweepAngle)
<
180.0
)))
{
pResultPoint.X
=
dRx2;
pResultPoint.Y
=
dRy2;
}
}
return
pResultPoint; }