qt下bezier曲线的绘制(C++)
原博客地址:https://blog.****.net/u013935238/article/details/50012737
bezier曲线在编程中的难点在于求取曲线的系数,如果系数确定了那么就可以用微小的直线段画出曲线。bezier曲线的系数也就是bernstein系数,此系数的性质可以自行百度,我们在这里是利用bernstein系数的递推性质求取
简单举例
两个点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[n]; //系数数组
-
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 的**** 博客 ,全文地址请点击:https://blog.****.net/u013935238/article/details/50012737?utm_source=copy