您的位置:首页 > 编程语言 > C语言/C++

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: 慢慢的,自己已经学会了好多,可是,还是觉得不够


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: