qt下bezier曲线的绘制(C++)
2015-11-24 14:46
148 查看
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">bezier曲线在编程中的难点在于求取曲线的系数,如果系数确定了那么就可以用微小的直线段画出曲线。bezier曲线的系数也就是bernstein系数,此系数的性质可以自行百度,我们在这里是利用bernstein系数的递推性质求取。</span>
简单举例
两个点p0,p1 为一阶曲线
系数为 (1-u)p0+u*p1; 将系数存在数组中b[0] = 1-u b[1]=u
三个点 p0 p1 p2 为二阶曲线
系数(1-u)(1-u)p0+2u(1-u)p1+u*u*p2 可以看出二阶的系数是一届的系数的关系 ((1-u)+u)(b[0]+b[1])
四个点 三阶曲线为
((1-u)+u)((1-u)+u)(b[0]+b[1])
是不是有种似曾相识的感觉,对了,这就是高中牛顿二项式展开的过程
注: (u为区间(0,1)中的小数,在这里明确下:在具体的编程中我们就是通过对u从0到1的累加求取得到无数多的点,然后用线段将每个点连接起来,得到曲线。你可以将p0,p1看成向量基底,将u看做时间)
QPainter *painter = new QPainter(this); QPointF p0(10,10); QPointF p1(80,70); QPointF p2(10,50); painter->setPen(Qt::red); painter->drawLine(p0,p1); painter->drawLine(p1,p2); QPainterPath path; path.moveTo(p0); QPointF pTemp; for(double t=0; t<1; t+=0.01) //2次Bezier曲线 { pTemp =pow((1-t),2)*p0+2*t*(1-t)*p1+pow(t,2)*p2; path.lineTo(pTemp); }上文是使用最简单的方式实现二次bezier曲线,但是也存在着及其不方便的地方,系数和参数不能分开,如果求三次或者多次都需要重写,及其不方便。
下面我用c++实现,其中画线是使用qt完成的,你只需要把画线部分替换成你自己的,就完全可以得到n次bezier曲线
//一个小的注意事项n+1个点事n阶曲线,请记清楚
#ifndef BEZIER_H #define BEZIER_H #include "QList" #include "QPoint" #include "QPainter" #include "QPainterPath" template<typename Point> //Point 我使用的是qt的内部类QPointF 你可以使用自己定义的 class Bezier{ private: double precision=0.01; //你可以自己设置精度,确保所画直线的细腻程度 QList<Point> * pointList; private: void AllBernstein(int n,double u,double *B); Point PointOnBezierCurve(double u); public: Bezier(); ~Bezier(); void setPrecision(double precision); void appendPoint(Point point) ; QPainterPath getPainterPath();//你可以定义自己的画图方法 这里就不写虚方法了, int getListLengh(); double getPrecision(); // Point getPoint(int index); // Point deletePoint(int index); // void insertPoint(); }; template<typename Point> Bezier<Point>::Bezier() { pointList = new QList<Point>; } template<typename Point> Bezier<Point>::~Bezier() { delete pointList; } template<typename Point> void Bezier<Point>::appendPoint(Point point) { pointList->append(point); } template<typename Point> QPainterPath Bezier<Point>::getPainterPath() { QPainterPath path; path.moveTo(pointList->at(0)); for(double t=0; t<1; t+= precision) { Point pTemp = PointOnBezierCurve(t); path.lineTo(pTemp); } return path; } template<typename Point> void Bezier<Point>::setPrecision(double precision) { if(precision<1) this->precision =precision; } template<typename Point> double Bezier<Point>::getPrecision() { return this->precision; } template<typename Point> void Bezier<Point>::AllBernstein(int n, double u, double *B) { B[0] = 1.0; double u1 = 1.0-u; for(int j=1; j<=n;j++) { double saved = 0.0; for(int k=0; k<j; k++) { double temp = B[k]; B[k] = saved+u1*temp; saved = u*temp; } B[j] = saved; } } template<typename Point> Point Bezier<Point>::PointOnBezierCurve(double u) { int n = pointList->length(); double *coefficient =new double ; //系数数组 memset(coefficient,0,sizeof(coefficient)); AllBernstein(n-1,u,coefficient);//计算系数 Point tempPoint(0.0,0.0); for(int i=0;i<pointList->length();i++) { Point temp = pointList->at(i); tempPoint = tempPoint +temp*coefficient[i]; } return tempPoint; } #endif // BEZIER_H
在mainwindow中使用
void MainWindow::paintEvent(QPaintEvent *event) { QPainter *painter = new QPainter(this); Bezier<QPointF> *bezier;// = new Bezier<QPointF>; bezier = new Bezier<QPointF>(); QPointF p[3]; p[0] = QPointF(100,100); p[1] = QPointF(800,700); p[2] = QPointF(100,500); painter->setPen(Qt::red); painter->drawLine(p[0],p[1]); painter->drawLine(p[1],p[2]); bezier->appendPoint(p[0]); bezier->appendPoint(p[1]); bezier->appendPoint(p[2]); QPainterPath path = bezier->getPainterPath(); painter->setPen(Qt::blue); painter->drawPath(path); delete painter; }
运行效果
ps: 为了学习,自己使用了模板类做的,所以如果你想在其他c++环境下使用,那么简单的将QList替换为你自己的list其他的貌似就不用改了,对了如果非qt环境下你还要重新实现画图的方法 getPaiterPath
在用模板类的时候,必须放在将定义和实现放在一起,分开则不能编译(c++是支持分开写的,但是现在比较常用的编译器都不支持),很久之前看的,这个地方就记不得了,然后就弄了好久,要好好看书了。
ph: 慢慢的,自己已经学会了好多,可是,还是觉得不够
相关文章推荐
- C++primer plus第六版课后编程练习答案2.2
- C++primer plus第六版课后编程题练习答案2.1
- C/C++——友元函数
- C++先,中,后顺序遍历的非递归实现
- C++之日志打印
- 第一章:C语言数据类型
- C语言-----循环单链表
- PVS-Studio C/C++/C++11 静态代码分析工具
- 线程安全的的map-CSuperMap
- 《C++编程规范:101条规则、准则与最佳实践》学习笔记
- vs2012编译c语言-指针不能判NULL
- 迷宫最少步数的求解(利用队列)
- 《C++必知必会》学习笔记
- C++笔记(8) template partitial specialization模板偏特化
- c++实现封装socket2
- 顺序队的基本操作(C++完整代码)
- C语言常见命名规范
- C++学习中关于cout遇到的一个小问题
- c++调试重要武器GetLastError
- C语言 side effect和sequence point