qt下bezier曲線的繪製(C++)
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)
是不是有種似曾相識的感覺,對了,這就是高中牛頓二項式展開的過程
注: (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