最近同事想让要做一个绘图的控件。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

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

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

    本文转自:http://blog.sina.com.cn/s/blog_486285690100ljwu.html 目前知道三种方式:WinExec,ShellExecute ,CreateProce ...

  2. VC中GetLastError()获取错误信息的使用,以及错误代码的含义

    转载:http://www.seacha.com/article.php/knowledge/windows/mfc/2011/0423/335.html VC中GetLastError()获取错误信 ...

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

    汇编程序结构 一个显示字符串的汇编程序 程序格式 一.模式定义 二.includelib语句 三.函数声明语句 四.数据和代码部分 Visual C/C++环境 建立工程 汇编程序的调试 一.设置断点 ...

  4. VC中基于 Windows 的精确定时[转]

    在工业生产控制系统中,有许多需要定时完成的操作,如定时显示当前时间,定时刷新屏幕上的进度条,上位 机定时向下位机发送命令和传送数据等.特别是在对控制性能要求较高的实时控制系统和数据采集系统中,就更需要 ...

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

    最近将两个开源C++项目编译成windows版本的时候遇到很多问题,关键是两个项目经过同事的修改之后,一个项目引用了另一个项目,两个项目的头文件中都有一些跨平台的关于数据类型,以及一些通用函数的定义, ...

  6. VC中Source Files, Header Files, Resource Files,External Dependencies的区别

    VC中Source Files, Header Files, Resource Files,External Dependencies的区别 区别: Source Files 放源文件(.c..cpp ...

  7. 如何在VC中查询中文,及QT5的中文处理

    1,VC中查询所有含中文字符串 使用正则表达式,查询内容为: (".*[\u4E00-\u9FA5]+)|([\u4E00-\u9FA5]+.*") 这样,就可以把代码中的中文都查 ...

  8. VC中不同类型DLL及区别

    1. DLL的概念可以向程序提供一些函数.变量或类. 静态链接库与动态链接库的区别:(1)静态链接库与动态链接库都是共享代码的方式.静态链接库把最后的指令都包含在最终生成的EXE文件中了:动态链接库不 ...

  9. VC中如何获取当前时间(精度达到毫秒级)

    标 题: VC中如何获取当前时间(精度达到毫秒级)作 者: 0xFFFFCCCC时 间: 2013-06-24链 接: http://www.cnblogs.com/Y4ng/p/Millisecon ...

随机推荐

  1. C++ 基于凸包的Delaunay三角网生成算法

    Delaunay三角网,写了用半天,调试BUG用了2天……醉了. 基本思路比较简单,但效率并不是很快. 1. 先生成一个凸包: 2. 只考虑凸包上的点,将凸包环切,生成一个三角网,暂时不考虑Delau ...

  2. zabbix监测图形界面显示方框乱码解决方法

    思路如下:用Windows下中文字体进行替换,修改配置文件即可 详细步骤如下: 1.在Windows的控制面板里的字体中,选择一种中文字体,将该字体文件复制到桌面.例如,我选择了宋体 常规字体,复制到 ...

  3. 1.2.7 Excel表格打印技巧

    1.打印居中显示 把打印的内容放在纸张中间,居中对齐. 方法: ①点击[页面布局]选项卡: ②找到[页面设置]群组点击右下角显示更多: ③在页边距对话框中选择[页边距]: ④勾选[居中方式]中的[水平 ...

  4. VS2012统计代码量

    第一步:打开项目 第二步:CTRL+SHIFT+H  选择在文件中查找,输入 表达式:b*[^:b#/]+.*$,如下图所示: 第三步:单击 查找全部 按钮,统计结果如下图所示:

  5. python列表的基础操作

    Operation Result Trans x in s True if an item of s is equal to x, else False x值是否在s列表中 x not in s Fa ...

  6. DApp demo之pet-shop

    注意: 这里使用的truffle版本为4.1.4,貌似使用高版本在truffle test时候会出问题,提示 truffle/Assert.sol is not found等错误 使用Truffle ...

  7. php变量函数

    这个东西相当于C语言中的函数指针,C#里的委托   function come() {                   //定义com函数 echo "来了<p>" ...

  8. 生信基础知识【04】GO和pathway分析

    非原创 参考资料: 一文掌握GO和pathway分析 - 生物信息学讨论版 -丁香园论坛http://www.dxy.cn/bbs/thread/34904124#34904124 GO富集 GO是G ...

  9. JSP的三个脚本元素

    JSP的脚本:JSP定义Java代码的方式 1. <% 代码 %>:[脚本段:java程序段]定义的java代码,在service方法中.service方法中可以定义什么,该脚本中就可以定 ...

  10. springboot项目简单启动脚本

    #!/bin/bash function log_info () { DATE=`date "+%Y-%m-%d %H:%M:%S"` USER=$(whoami) echo &q ...