随笔-167  评论-8  文章-0  trackbacks-0
//从圆弧一些信息得到圆弧上一个特殊的点(计算的是二维图形的情况)
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;
}
posted on 2010-09-08 10:12 老马驿站 阅读(674) 评论(0)  编辑 收藏 引用 所属分类: c++