1. 程式人生 > >qt下bezier曲線的繪製(C++)

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)

(b[0]+b[1])

是不是有種似曾相識的感覺,對了,這就是高中牛頓二項式展開的過程

注:  (u為區間(0,1)中的小數,在這裡明確下:在具體的程式設計中我們就是通過對u從0到1的累加求取得到無數多的點,然後用線段將每個點連線起來,得到曲線。你可以將p0,p1看成向量基底,將u看做時間)

  1. QPainter *painter = new QPainter(this);

  2. QPointF p0(10,10);

  3. QPointF p1(80,70);

  4. QPointF p2(10,50);

  5. painter->setPen(Qt::red);

  6. painter->drawLine(p0,p1);

  7. painter->drawLine(p1,p2);

  8. QPainterPath path;

  9. path.moveTo(p0);

  10. QPointF pTemp;

  11. for(double t=0; t<1; t+=0.01) //2次Bezier曲線

  12. {

  13. pTemp =pow((1-t),2)*p0+2*t*(1-t)*p1+pow(t,2)*p2;

  14. path.lineTo(pTemp);

  15. }

上文是使用最簡單的方式實現二次bezier曲線,但是也存在著及其不方便的地方,係數和引數不能分開,如果求三次或者多次都需要重寫,及其不方便。

下面我用c++實現,其中畫線是使用qt完成的,你只需要把畫線部分替換成你自己的,就完全可以得到n次bezier曲線

//一個小的注意事項n+1個點事n階曲線,請記清楚

  1. #ifndef BEZIER_H

  2. #define BEZIER_H

  3. #include "QList"

  4. #include "QPoint"

  5. #include "QPainter"

  6. #include "QPainterPath"

  7. template<typename Point> //Point 我使用的是qt的內部類QPointF 你可以使用自己定義的

  8. class Bezier{

  9. private:

  10. double precision=0.01; //你可以自己設定精度,確保所畫直線的細膩程度

  11. QList<Point> * pointList;

  12. private:

  13. void AllBernstein(int n,double u,double *B);

  14. Point PointOnBezierCurve(double u);

  15. public:

  16. Bezier();

  17. ~Bezier();

  18. void setPrecision(double precision);

  19. void appendPoint(Point point) ;

  20. QPainterPath getPainterPath();//你可以定義自己的畫圖方法 這裡就不寫虛方法了,

  21. int getListLengh();

  22. double getPrecision();

  23. // Point getPoint(int index);

  24. // Point deletePoint(int index);

  25. // void insertPoint();

  26. };

  27. template<typename Point>

  28. Bezier<Point>::Bezier()

  29. {

  30. pointList = new QList<Point>;

  31. }

  32. template<typename Point>

  33. Bezier<Point>::~Bezier()

  34. {

  35. delete pointList;

  36. }

  37. template<typename Point>

  38. void Bezier<Point>::appendPoint(Point point)

  39. {

  40. pointList->append(point);

  41. }

  42. template<typename Point>

  43. QPainterPath Bezier<Point>::getPainterPath()

  44. {

  45. QPainterPath path;

  46. path.moveTo(pointList->at(0));

  47. for(double t=0; t<1; t+= precision)

  48. {

  49. Point pTemp = PointOnBezierCurve(t);

  50. path.lineTo(pTemp);

  51. }

  52. return path;

  53. }

  54. template<typename Point>

  55. void Bezier<Point>::setPrecision(double precision)

  56. {

  57. if(precision<1)

  58. this->precision =precision;

  59. }

  60. template<typename Point>

  61. double Bezier<Point>::getPrecision()

  62. {

  63. return this->precision;

  64. }

  65. template<typename Point>

  66. void Bezier<Point>::AllBernstein(int n, double u, double *B)

  67. {

  68. B[0] = 1.0;

  69. double u1 = 1.0-u;

  70. for(int j=1; j<=n;j++)

  71. {

  72. double saved = 0.0;

  73. for(int k=0; k<j; k++)

  74. {

  75. double temp = B[k];

  76. B[k] = saved+u1*temp;

  77. saved = u*temp;

  78. }

  79. B[j] = saved;

  80. }

  81. }

  82. template<typename Point>

  83. Point Bezier<Point>::PointOnBezierCurve(double u)

  84. {

  85. int n = pointList->length();

  86. double *coefficient =new double[n]; //係數陣列

  87. memset(coefficient,0,sizeof(coefficient));

  88. AllBernstein(n-1,u,coefficient);//計算係數

  89. Point tempPoint(0.0,0.0);

  90. for(int i=0;i<pointList->length();i++)

  91. {

  92. Point temp = pointList->at(i);

  93. tempPoint = tempPoint +temp*coefficient[i];

  94. }

  95. return tempPoint;

  96. }

  97. #endif // BEZIER_H

在mainwindow中使用

  1. void MainWindow::paintEvent(QPaintEvent *event)

  2. {

  3. QPainter *painter = new QPainter(this);

  4. Bezier<QPointF> *bezier;// = new Bezier<QPointF>;

  5. bezier = new Bezier<QPointF>();

  6. QPointF p[3];

  7. p[0] = QPointF(100,100);

  8. p[1] = QPointF(800,700);

  9. p[2] = QPointF(100,500);

  10. painter->setPen(Qt::red);

  11. painter->drawLine(p[0],p[1]);

  12. painter->drawLine(p[1],p[2]);

  13. bezier->appendPoint(p[0]);

  14. bezier->appendPoint(p[1]);

  15. bezier->appendPoint(p[2]);

  16. QPainterPath path = bezier->getPainterPath();

  17. painter->setPen(Qt::blue);

  18. painter->drawPath(path);

  19. delete painter;

  20. }

執行效果

ps: 為了學習,自己使用了模板類做的,所以如果你想在其他c++環境下使用,那麼簡單的將QList替換為你自己的list其他的貌似就不用改了,對了如果非qt環境下你還要重新實現畫圖的方法 getPaiterPath

在用模板類的時候,必須放在將定義和實現放在一起,分開則不能編譯(c++是支援分開寫的,但是現在比較常用的編譯器都不支援),很久之前看的,這個地方就記不得了,然後就弄了好久,要好好看書了。

ph: 慢慢的,自己已經學會了好多,可是,還是覺得不夠

--------------------- 本文來自 自由幻想c 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/u013935238/article/details/50012737?utm_source=copy