原博客地址:https://blog.csdn.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 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u013935238/article/details/50012737?utm_source=copy