模拟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)
{
	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

原文地址:https://www.cnblogs.com/small-lazybee/p/10369394.html

时间: 2024-10-16 18:46:38

模拟PLC 的圆弧插补方式在VC中绘制圆弧的相关文章

[转]VC中调用外部exe程序方式

本文转自:http://blog.sina.com.cn/s/blog_486285690100ljwu.html 目前知道三种方式:WinExec,ShellExecute ,CreateProcess,别人已经总结的很好了<vc中调用其他应用程序的方法(函数) winexec,shellexecute ,createprocess>,我全文转载一下,另外后面加点自己的总结(黑体部分,除了标题). 三个SDK函数: WinExec,ShellExecute ,CreateProcess可以实

VC++中开发汇编语言(转)

汇编程序结构 一个显示字符串的汇编程序 程序格式 一.模式定义 二.includelib语句 三.函数声明语句 四.数据和代码部分 Visual C/C++环境 建立工程 汇编程序的调试 一.设置断点 二.内存窗口 三.寄存器窗口 四.监视窗口 常用调试命令 字符串输入.输出 printf sprintf scanf 常用Windows API调用 MessageBox 确定函数的声明语句和库文件 读取CPU标识 WinDbg调试工具 实验题:用MessageBox函数显示CPU信息 源自:ht

深度解析VC中的消息传递机制

摘要:Windows编程和Dos编程,一个很大的区别就是,Windows编程是事件驱动,消息传递的.所以,要学好Windows编程,必须 对消息机制有一个清楚的认识,本文希望能够对消息的传递做一个全面的分析. 一.什么是消息? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定 义了一个事件,向Windows发出一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键 都会使Windows发送一个

VC中LINK 2001 和 LINK 2009 的错误的解决

最近将两个开源C++项目编译成windows版本的时候遇到很多问题,关键是两个项目经过同事的修改之后,一个项目引用了另一个项目,两个项目的头文件中都有一些跨平台的关于数据类型,以及一些通用函数的定义,所以导致有冲突,编译的时候总是报错,报的最多的是“无法解析的外部符号”,经过近3天的折腾总算都通过了,这里是一些总结. 首先,关于VC中的lib,与linux下的静态库是不同的,在VC中编译动态库的时候会生成一个lib和一个对应的dll,使用者在使用的时候需要包含头文件以及连接到该lib,在发布最终

数组模拟堆栈的存储方式代码实践

堆栈的模式是先进后出,取出后堆栈中就没有取出的元素了,所以在模拟时候要注意这些问题. 1 import java.util.Arrays; 2 3 /* 4 5 需求:编写一个类使用数组模拟堆栈的存储方式. 6 7 堆栈存储特点: 先进后出,后进先出. 8 9 注意: 不再使用的对象,应该不要让变量指向该对象,要让该对象尽快的被垃圾回收期回收. 10 11 12 */ 13 class StackList{ 14 15 Object[] elements; 16 17 int index = 0

【转载】VC中如何调用其他的可执行程序

在开发项目的时候,有的时候会分开来开发,分开的有时是exe文件,有的时候也会调用现成的工具包里面的一些exe文件,这样在项目里面就要通过调用exe文件来使用. 那么在C++里面直接调用exe文件的方法有哪些呢?现在可考虑的方法主要有: a.使用system函数 b.使用exec或者是execv函数 c.使用WinExec函数 d.使用CreateProcess函数 e.使用ShellExcecuteEx函数 1)上面的5中方法中,system函数,函数原型system(执行shell命令)定义函

TQ2440与西门子S7-200 PLC自由口通信实现过程中问题总结

1.在win7上安装好PLC编程软件 STEP 7 MicroWIN 之后,无法实现编程软件与PLC的通信连接? 原因:STEP 7 MicroWIN 对win7支持不是很好 解决办法:在win7中安装虚拟机,虚拟机中安装XP系统,在XP下安装 STEP 7 MicroWIN 2.单向数据传输:PLC向PC串口1发送数据正确(波特率9600),但是双向数据传输:PC串口1先向PLC发送数据,PLC在接收到数据后,再向PC串口1发送数据出现错误,表现在PC串口1接收到的数据和PLC发送的数据不一致

深度解析VC中的消息(转发)

http://blog.csdn.net/chenlycly/article/details/7586067 这篇转发的文章总结的比较好,但是没有告诉我为什么ON_MESSAGE的返回值必须是LRESULT 摘要: Windows编程和Dos编程,一个很大的区别就是,windows编程是事件驱动,消息传递的.所以,要做好windows编程,必须对消息机制有一个清楚的认识,本文希望能够对消息的传递做一个全面的论述,由于小生初学VC,里面可能有一些错误的地方,还往各位大虾批评.指正. 注意:有些消息

Don’t Put View Code Into Your View Controller别把View创建的代码放在VC中(swift)

Don't Put Into Your View Controller别把View创建的代码放在VC中html, body {overflow-x: initial !important;}.CodeMirror { height: auto; } .CodeMirror-scroll { overflow-y: hidden; overflow-x: auto; } .CodeMirror-lines { padding: 4px 0px; } .CodeMirror pre { paddin