Qt绘制曲线
来源:互联网 发布:宏业软件下载 编辑:程序博客网 时间:2024/06/09 21:11
引言
应易和仓储系统需求,使运输车在行驶过程与刹车过程中运行得平稳,下位机通过无极变速控制应运而生,而上位机的无极变速参数设置也必不可少。这就用到了Qt的绘制曲线。
Qt的图形界面很厉害,之前的项目中用到的都是Qt的一些简单的应用,通过绘制曲线才对Qt的图形有了初步的了解。原来我也可以画出美丽平滑的余弦曲线。
1 坐标转换
(1)坐标系的认识
在绘制曲线之前,先要对坐标系有个深入的认识。如果对坐标系认识模糊,那么在绘制曲线时对于点的坐标也将是一团浆糊,更谈不上画出符合一定函数的曲线了。
在无极变速参数设置中,有三个坐标系,我把它们称为:世界坐标,屏幕坐标,窗口坐标。
世界坐标就是类似s(距离)--t(时间),v(速度)--t(时间)等坐标系。我们希望的是绘制出相应的函数曲线。
窗口坐标实际上是Qt的窗口坐标,显示的都是一个一个像素,单位是像素。另外,需注意的是Qt的窗口坐标是x向右y向下生长的,与数学中经常接触到的x向右y向上不太一样。
屏幕坐标是什么呢?可以认为是在窗口坐标中抠出一部分区域,在这个区域中绘制出肉眼看到的坐标系和曲线。单位也是像素。
但是Qt是只认识窗口坐标的。如何将无极变速中的速度(或频率),距离的函数关系描述出来,就需要将相应的世界坐标转换成相应的屏幕坐标,再将相应的屏幕坐标转换成窗口坐标显示。
当然,这3个坐标系只是当前应用所需,还可以继续推广。其他应用可能需要的坐标系转换更多,可能是5个(据说码垛机中的机器视觉识别就有5个坐标系)甚至更多。
(2)坐标系的转换
屏幕坐标-->窗口坐标
首先应明确的是窗口坐标中的总长度winWidth和总高度winHeigth。
winWidth = this->width();
winHeight = this->height();
那屏幕坐标最好在左右预留出xOff ,在上下预留出yOff 。也是对称美,也是为了标出x和y上的刻度。屏幕坐标的总长度scWidth和总高度scHeight也就有了。
scWidth = winWidth-2*xOff; //事先定义的xOff ,yOff
scHeight = winHeight-2*yOff;
接下来就可以推算屏幕坐标和窗口坐标的对应关系了。
由上图可以得到:屏幕坐标sPoint与窗口坐标qPoint的关系是
//屏幕坐标转换为窗口坐标
void sc2qc(QPoint& sPoint,QPoint &qPoint)
{
qPoint.setX(sPoint.x()+xOff);
qPoint.setY(winHeight-yOff-sPoint.y());
}
世界坐标-->屏幕坐标
类似比例尺的缩放一样,将世界坐标缩放成屏幕坐标,x向y向自是有各自的比例系数kx,ky。如果世界坐标中x方向的范围是xRange ,y方向的范围是yRange 。
kx=scWidth/xRange;
ky=scHeight/yRange;
世界坐标中任意一点(xw,yw)转换成屏幕坐标中的一点sPoint时,乘以对应的比例系数即可。
void wc2sc(double xw,double yw,QPoint& sPoint)
{
double x =xw*kx;
double y = yw*ky;
//如果x和y都是double类型,就需要将其转换成int类型,因为Point类的x和y是像素,只能是int类型。那么double转换成int需要注意(我好像一直都没弄明白过)
if(x>=0)sPoint.setX(x+0.5);
else sPoint.setX(x-0.5);
if(y>=0)sPoint.setY(y+0.5);
else sPoint.setY(y-0.5);
}
至此,就搞清楚了3个坐标系中对应坐标的转换了。
2 绘制坐标轴
三个点,两条直线确定两个坐标轴,三个点xePoint, originPoint, yePoint均是屏幕坐标下的点,画直线时都要转换成窗口坐标才行。根据xePoint和yePoint可以确定两坐标轴端处的两个空心三角形。这样,坐标轴就大致画好了。
接下来绘制坐标轴上的刻度线。这也是个体力活,不过自从弄清楚坐标系的转换后,这都是个容易的事情。把屏幕坐标像素总长度scWidth平均分成几段(xSpaces),像素总高度scHeight平均分成几段(ySpaces),找到x向各个刻度线的坐标,y向各个刻度线的坐标,再drawLine()就可以。道理很简单,画起来有许多细节要留心。比如,不用一个一个刻度线去找坐标,只是两个循环;要将刻度线都画成虚线,看起来更漂亮,也是需要设置相应的格式的。
xGridPixel=scWidth/xSpaces;
yGridPixel=scHeight/ySpaces;
void FuncWidget::drawXGrid(int n)
{
//设置刻度线为虚线
painter->setPen(Qt::white);
painter->setPen(Qt::DashLine);
//刻度线上两点
QPoint xGridPoint(n*xGridPixel,0);
QPoint xGridTopPoint(n*xGridPixel,scHeight);
QPoint xGridPointQt;
QPoint xGridTopPointQt;
//屏幕坐标转换成窗口坐标
sc2qc(xGridPoint,xGridPointQt);
sc2qc(xGridTopPoint,xGridTopPointQt);
//绘制刻度线
painter->drawLine(xGridPointQt,xGridTopPointQt);
//写上刻度
QPoint textPoint=xGridPoint+QPoint(-20,-20);
QPoint textPointQt;
sc2qc(textPoint,textPointQt);
painter->drawText(textPointQt,tr("%1").arg(xRange/xSpaces*n));
}
for(int n=0;n<=xSpaces;n++) //xSpaces可随意设置
{
drawXGrid(n);
}
//y向也类似,就不一一列举。
3 绘制曲线
各种准备工作做完后,这才进入到刻画数学函数关系的时刻了。
先来缕清数学函数关系y=f(x) ,这里f 可以是刻画直线y=k*x+b的数学函数,也可以是刻画余弦曲线y=cos(x)的数学函数。依据自己应用需要而定。我要实现的正是直线和余弦曲线的绘制。
设置这样一个表示数学函数关系的函数,这句话中有两个函数,一个是数学中常用的数学函数,一个是程序语言中类的成员函数。这个成员函数为double f(int mode,int x);表示直线模式和曲线模式下由x得到y。
如果是直线函数,由k和b即得到y;如果是余弦函数,由标准库函数可得到x对应的余弦值或反余弦值。
取尽xRange范围内的所有x值,得到对应的所有的y值,会得到有限个对应数学函数关系的点,然后由x和y值会用到世界坐标向屏幕坐标的转换,得到转换后的点,依次连接这些点,就会绘制出对应的曲线。
QWidget有个信号槽函数update() ,当update()被调用时,会自动调用void paintEvent(QPaintEvent *)事件。所以绘制工作都在这个函数中实现。
在此之前,在构造函数中新建一个painter=new QPainter;再painter->begin(this);将坐标轴,刻度线,曲线都在其中绘制。最后painter->end();就完成了绘制。
绘制的直线和曲线如下:
4 注意事项
1 double和int 的转换
double-->int :
可以用标准库中的round(x)函数,即取得x的四舍五入的整数值。
也可以如下:
double x;
int xi;
if(x>=0)xi=(x+0.5);
else xi=(x-0.5);
int-->double:
可以转换时在要转换的数前加double,也可以把数学符号前面或后面的某个数前做double转换。double w=2*(x-minHz); w-=1.0;
2 调用标准库函数
#include "stdio.h"
using namespace std;
#include "math.h"
double y=cos(x);
网址:http://blog.sina.com.cn/s/blog_9542b5c70102veg5.html
- Qt绘制贝塞尔曲线
- Qt- 绘制实时曲线
- Qt绘制曲线
- Qt绘制贝塞尔曲线例程
- Qt绘制贝塞尔曲线例程
- Qt 利用 Qwt 绘制动态曲线
- Qt QChart,利用QChart绘制动态曲线
- 绘制曲线
- 曲线绘制
- 绘制曲线
- 曲线绘制
- QT实现适时曲线的绘制(待完成)
- qt下bezier曲线的绘制(C++)
- Qt customplot插件中绘制实时时间堆积曲线
- 气象自动监测站QT程序设计(四):数据实时曲线绘制
- Qt鼠标绘制平滑曲线解决方案(1)
- Qt鼠标绘制平滑曲线解决方案(2)
- API-PolylineTo绘制曲线
- 两个乒乓球队进行比赛,各出3人。
- Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
- php绘图2
- Qt常用片段代码库(持续更新)
- 验证码
- Qt绘制曲线
- 验证码php
- Spring注解详解
- 屌炸天实战 MySQL 主从复制、备份恢复方案生产环境实战
- timer用法
- 这个月不知道写博客了没
- 最短的C编译器崩溃程序
- 领略千变万化的Android Drawable (一)
- 我又回来了