1. 程式人生 > >DXF檔案中將多段線凸度轉換成圓弧

DXF檔案中將多段線凸度轉換成圓弧

在數控系統中,我們常常會將DXF檔案轉換成G程式碼,主要涉及到 直線、多段線、圓、圓弧、橢圓、樣條曲線、點,七大類,在轉換成G程式碼過程中,其中樣條曲線和多段線中凸度問題是比較複雜一些,而樣條曲線的轉換網上有很多原始碼,而處理凸度問題的原始碼似乎少很多。最近剛好我也在解析DXF檔案,遇到了處理凸度的問題。我花了兩天時間集中完成這個難題。通過大量的測試程式碼基本沒有什麼問題,凸度問題完美解決了。(其中主要的方法是運用了數學推匯出來的方程計算的)
 double dConvexityDegree=0; //凸度
	long nSumLines = dxf_code.size();
	double theta_arc;
	double theta_degree ;//角度,包角
	double dAngle;//起點到終點的弦向量與X正方向之間的傾斜角
	double dStarX=0,dStarY=0;//圓弧起始點
	double dEndX=0,dEndY=0;	 //圓弧終止點
	double dStarC=0,dEndC=0; //圓弧起始角度,終止角度
	double dmiddleX=0,dmiddleY=0;//起始點和終止點連線線的中點橫縱座標
	double dCenterX=0,dCenterY=0;//圓心座標
	double dCenterX1=0,dCenterY1=0;//圓心座標1
	double dCenterX2=0,dCenterY2=0;//圓心座標2
	double dLength; //弦長
	double dfR;  //半徑
	double dH;	//圓心到弦的距離
	//double k; //起始點和終止點連線的中垂線斜率
	double dAmass; //弦向量與X軸正向單位向量的叉積
	double dDirectionAngel;//弦中點到圓心的直線向量的方向角(0-2PI之間)
	double dD; //圓心到弦長的距離
	double dNslope;////弦的斜率
	double dK;     //弦中垂線的斜率
	double dNAngel;//中垂線的傾斜角
	double dX,dY;		//圓心相對於弦中心點的座標偏移量
	double num1,num2;	//x方向向量和圓心到弧線起點和終點的向量的叉乘的z 


	double k = 0.0;//弦的斜率
	double k_verticle = 0.0;//弦的中垂線的斜率
	double mid_x = 0.0,mid_y = 0.0;//弦的中點座標
	double a = 1.0;
	double b = 1.0;
	double c = 1.0;
	double angleChordX=0;//弦向量X正方向的角度
	int direction=0;//判斷是G02還是G03
	bool isMinorArc=TRUE;//圓弧半徑是否為較小的
	double dStartVale=0; //起始角的cos(dStarC)值
	double dEndVale=0; //終止角的cos(dEndC)值

      dConvexityDegree=code.r1;
	//當凸度dConvexityDegree不等於0時,表示為圓弧
	if (0!=dConvexityDegree)
	{
		theta_degree = 4*atan(fabs(dConvexityDegree));
				
		//起始點,終止點
		dStarX = code.x1;
		dStarY = code.y1;
		dEndX  = code.x2;
		dEndY  = code.y2;

		//弦長
		dLength = sqrt(pow(dStarX-dEndX,2)+pow(dStarY-dEndY,2));
		//圓弧半徑
		dfR = fabs(0.5*dLength/sin(0.5*theta_degree));

		k = (dEndY - dStarY) / (dEndX - dStarX);
		if(k == 0)
		{
			dCenterX1 = (dStarX + dEndX) / 2.0;
			dCenterX2 = (dStarX + dEndX) / 2.0;
			dCenterY1 = dStarY + sqrt(dfR * dfR -(dStarX - dEndX) * (dStarX - dEndX) / 4.0);
			dCenterY2 = dEndY - sqrt(dfR * dfR -(dStarX - dEndX) * (dStarX - dEndX) / 4.0);
		}
		else
		{
			k_verticle = -1.0 / k;
			mid_x = (dStarX + dEndX) / 2.0;
			mid_y = (dStarY + dEndY) / 2.0;
			a = 1.0 + k_verticle * k_verticle;
			b = -2 * mid_x - k_verticle * k_verticle * (dStarX + dEndX);
			c = mid_x * mid_x + k_verticle * k_verticle * (dStarX + dEndX) * (dStarX + dEndX) / 4.0 - 
			(dfR * dfR - ((mid_x - dStarX) * (mid_x - dStarX) + (mid_y - dStarY) * (mid_y - dStarY)));

			dCenterX1 = (-1.0 * b + sqrt(b * b -4 * a * c)) / (2 * a);
			dCenterX2 = (-1.0 * b - sqrt(b * b -4 * a * c)) / (2 * a);
			dCenterY1 = k_verticle*dCenterX1 -k_verticle*mid_x+mid_y;
			dCenterY2 = k_verticle*dCenterX2 -k_verticle*mid_x+mid_y;
		}


		//凸度絕對值小於1表示圓弧包角小於180°,凸度絕對值大於1表示圓弧包角大於180°
		if (fabs(dConvexityDegree)<=1)
			isMinorArc=TRUE;
		else
			isMinorArc=FALSE;


		//確定圓弧的順逆
		if (0>dConvexityDegree)
			direction=2;
		else
			direction=3;

		//確定圓心
		angleChordX=acos((1*(dEndX-dStarX)+0*(dEndY-dStarY))/dLength)*180/PI;	
		if ((dEndY-dStarY)<0)
		{
			angleChordX*=-1;
		}
		if ((angleChordX>0 && angleChordX<180)||angleChordX==180)
		{
			if (direction==2)//順圓
			{
				if(isMinorArc)
				{
					dCenterX=dCenterX1;
					dCenterY=dCenterY1;
				}
				else
				{
					dCenterX=dCenterX2;
					dCenterY=dCenterY2;
				}
			}
			else if (direction==3)//逆圓
			{
				if (isMinorArc)
				{
					dCenterX=dCenterX2;
					dCenterY=dCenterY2;
				}
				else
				{
					dCenterX=dCenterX1;
					dCenterY=dCenterY1;
				}
			}
		}
				
		else 
		{
			if (direction==2)//順圓
			{
				if(isMinorArc)
				{
					dCenterX=dCenterX2;
					dCenterY=dCenterY2;
				}
				else
				{
					dCenterX=dCenterX1;
					dCenterY=dCenterY1;
				}
			}
			else if (direction==3)//逆圓
			{
				if (isMinorArc)
				{
					dCenterX=dCenterX1;
					dCenterY=dCenterY1;
				}
				else
				{
					dCenterX=dCenterX2;
					dCenterY=dCenterY2;
				}
			}
		}


		//起始角度、終止角度
		dStartVale=(dStarX-dCenterX)/dfR;
		//在C++中,浮點型中的結果1可能是1.00000000000000001,避免這種情況出現。
		if (dStartVale>1)
			dStartVale=1;
		if (dStartVale<-1)
			dStartVale=-1;
		dStarC = acos(dStartVale);  
		//x方向向量和圓心到弧線起點和終點的向量的叉乘的z 
		num1=dStarY-dCenterY;  
		if(num1<0)  
			dStarC=2*PI-dStarC; 

		//終止角度、終止角度
		dEndVale=(dEndX-dCenterX)/dfR;
		//在C++中,浮點型中的結果1可能是1.00000000000000001,避免這種情況出現。
		if (dEndVale>1)
			dEndVale=1;
		if (dEndVale<-1)
			dEndVale=-1;
		dEndC = acos(dEndVale);  
		//x方向向量和圓心到弧線起點和終點的向量的叉乘的z 
		num2=dEndY-dCenterY;  
		if(num2<0)  
			dEndC=2*PI-dEndC; 

		//將DXF_LWPOLYLINE轉換成ARC

		code.mStyle=DXF_ARC;
		//如果凸度小於0則為順時針,clockwise為true
		if (0>dConvexityDegree)
			code.bWise=TRUE;
		else
			code.bWise=FALSE;

		code.x1 = dCenterX;
		code.y1 = dCenterY;
		code.x2 = dStarC;
		code.y2 = dEndC;
		code.r1 = dfR;
	}

本文章只供參考,希望不要用在商業性質上。