zoukankan      html  css  js  c++  java
  • 模拟PLC 的圆弧插补方式在VC中绘制圆弧

           最近同事想让要做一个绘图的控件。VC里面的画弧函数Arc需要提供外接矩形的坐标。同事觉得不好用,他更习惯圆弧插补的那种方式。于是看了看圆弧插补的东西。其实这种画弧方式就是提供圆弧的起点、终点和半径来画弧。

               首先来简单介绍下圆弧插补:

               有两种圆弧插补:

                G02     顺时针圆弧插补

                G03    逆时针圆弧插补

              圆弧插补编程(半径编程):

              圆弧用编程功能G02 或G03 和其后圆弧终点坐标和半径值定义。

              

    圆弧半径用字母“R”表示。如果圆弧小于180 度,半径用正数符号,如果大于180 度用负数符号。这样基于所选圆弧插补(G02 或G03),可定义所选圆弧。

    结合圆弧插补,设计绘制圆弧的函数:函数可分为两种,顺时针绘制和逆时针绘制(分布对应G02 和G03)。函数的参数为圆弧起点,终点,半径。其中的半径若为正数,则绘制的圆弧为弧度小于180 的弧,这里称为小圆弧。若半径为负数,则绘制的弧为大雨180度的弧,这里成之为大圆弧。

    圆弧的绘制最终还是要使用C++ 提供的画弧函数Arc 。 因此我们需要找出来圆所在的外接矩形(这里是正方形)。因为我们已知半径,所以找到圆心就可以推导出圆所在的矩形。

    圆心的推导过程参考文章 已知圆上两点坐标和半径,求圆心   已知两点坐标和半径,求圆心 。圆心解出来有两个(x01,y01)(x02,y02)。如图所示,过相同的点并且半径相同的圆也确实有两个。那么到底哪一个是符合条件的圆呢。

     首先来讨论逆时针画弧的函数。如上图,从起点A到终点B,小圆弧就指的红色部分的弧,大圆弧是指的蓝色部分的弧。小圆弧的圆心是O2,大圆弧的圆心是O1;

    那么由什么条件能判断出所得的两个圆心(x01,y01)(x02,y02)哪一个是逆时针里的大圆弧的圆心O1,哪一个是逆时针里的小圆弧圆心O2呢? 这里我采用的是向量叉乘的方式判断的。

     

    也就是起点到终点组成的向量,与起点与大弧圆心组成的向量叉乘结果是小于0 的。(这个从图上使用右手法则可以判断出来,由AB 向AO1 弯曲,拇指垂直屏幕向里)。

    (有关向量知识参考 C语言-向量基本概念  向量叉乘判断点的位置)。

    所以在上一步所得的两个圆心坐标,与起点坐标组成向量。

    设A(x1,y1) B(x2,y2)

    向量AB={x2-x1,y2-y1}

    向量a={x01-x1,y01-y1}

    向量b={x02-x1,y02-y1}

    则(x01,y01)为大圆弧圆心 (x02,y02)为小圆弧圆心

    否则 反之。

     代码如下:

    //已知圆弧上两点 和半径,求圆心
    void CircleCenter(double x1,double y1,double x2,double y2,double R,double &x01,double &y01,double &x02,double &y02)  
    {  
    	//x1 == x2
    	if (abs(x1-x2)<0.0000001)
    	{
    		//(x1,y1)(x2,y2)之间的距离 /2
    		double dis = abs(y1-y2)/2;
    		
    		double dx = sqrt(R*R-dis*dis);
    
    		double dy = (y1+y2)/2;
    
    		x01 = x1-dx;
    		y01 = dy;
    
    		x02 = x1+dx;
    		y02 = dy;
    		return ;
    	}
    
    	double c1 = (x2*x2 - x1*x1 + y2*y2 - y1*y1) / (2 *(x2 - x1));  
    	double c2 = (y2 - y1) / (x2 - x1);  //斜率
    	double A = (c2*c2 + 1);  
    	double B = (2 * x1*c2 - 2 * c1*c2 - 2 * y1);  
    	double C = x1*x1 - 2 * x1*c1 + c1*c1 + y1*y1 - R*R;  
    	y01 = (-B + sqrt(B*B - 4 * A*C)) / (2 * A);
    	x01 = c1 - c2 * y01;   
    
    	y02 =  (-B - sqrt(B*B - 4 * A*C)) / (2 * A);
    	x02 = c1 - c2*y02;
    }  
    

      

    //逆时针画弧
    void CDrawShapeCtrl::Arc_AntiClock(DOUBLE StartX, DOUBLE StartY, DOUBLE EndX, DOUBLE EndY, DOUBLE R)
    {
    	AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
    	// TODO: Add your dispatch handler code here
    	//圆心坐标
    	double x01,y01,x02,y02;
    	double x_big,y_big;//大弧圆心
    	double x_small,y_small;//小弧圆心
    
    	LONG nLeftRect, nTopRect,nRightRect,nBottomRect;
    
      CircleCenter(StartX,StartY,EndX,EndY,R,x01,y01,x02,y02);
    
      //向量 
      double ax = EndX- StartX;
      double ay = EndY - StartY;
    
      double bx = x01 - StartX;
      double by = y01 - StartY;
    
      //利用向量的叉乘判断圆心位置
      //叉乘<0  则为大弧圆心;否则为小弧圆心
       double mulRt = ax*by-bx*ay;
    
       if (mulRt<0)
       {
    	   x_big = x01;
    	   y_big = y01;
    	   x_small = x02;
    	   y_small = y02;
       }
       else
       {
    	   x_big = x02;
    	   y_big = y02;
    	   x_small = x01;
    	   y_small = y01;
       }
    
       CClientDC dc(this);
    
       CRect rc;
       GetClientRect(rc);
       dc.SetMapMode(MM_ISOTROPIC);//MM_ISOTROPIC
    
       //逻辑坐标原点
       dc.SetViewportOrg(rc.right/2,rc.bottom/2);
       //设置映射比例为1,逻辑坐标Y轴方向与设备坐标相反
       dc.SetWindowExt(100,100);
       dc.SetViewportExt(100,-100);
    
      //R>0   弧<180度; R<0  弧>180度
      if (R<0) //大弧
    	  {
    		  nLeftRect = x_big-R;
    		  nTopRect = y_big + R;
    		  nRightRect = x_big+R;
    		  nBottomRect = y_big -R;
    
    		 dc.Arc(nLeftRect,nTopRect,nRightRect,nBottomRect,StartX,StartY,EndX,EndY);	
    	  }
      else //小弧
    	  {
    		  nLeftRect = x_small-R;
    		  nTopRect = y_small+R;
    		  nRightRect = x_small+R;
    		  nBottomRect = y_small - R;
    		  dc.Arc(nLeftRect,nTopRect,nRightRect,nBottomRect,StartX,StartY,EndX,EndY);
    
    	  }
    
    }
    

     顺时针函数,只要将起点终点坐标对换,直接调用逆时针函数即可。

     arc 函数参考:

    https://blog.csdn.net/u012513234/article/details/45460783

          

  • 相关阅读:
    站立会议01---个人总结
    团队项目的NABCD
    查找水王
    《构建之法》读书笔记03
    《构建之法》读书笔记02
    《构建之法》读书笔记01
    Java web应用开发技术
    Java 模拟ATM(修正)
    Java 多态
    Java 接口与继承 道至简第六章发表阅读笔记
  • 原文地址:https://www.cnblogs.com/small-lazybee/p/10369394.html
Copyright © 2011-2022 走看看