² 貝塞爾曲線html
貝塞爾曲線是經過一組多邊折線的各頂點來定義。在各頂點中,曲線通過第一點和最後一點,其他各點則定義曲線的導數、階次和形狀。第一條和最後一條則表示曲線起點和終點的切線方向。this
² B樣條曲線spa
針對貝塞爾曲線存在的一些缺點,數學家們提出了B樣條方法,在保留貝塞爾所有優勢的同時,克服可貝塞爾方法的弱點。.net
1) 二次B樣條曲線3d
2) 三次B樣條曲線orm
QT中的QPainter提供了繪製貝塞爾曲線的相關API:htm
void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)blog
void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)ci
void QPainter::drawPath(const QPainterPath &path)get
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
///////////////////////////////////////////////////////////// /// @file Widget.h /// @brief 繪製B樣條曲線Widget類 /// /// 經過鼠標點擊來繪製B樣條曲線 /// @author Michael Joessy /// @date 2019-07-02 ///////////////////////////////////////////////////////////// #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QVector> class Widget : public QWidget { Q_OBJECT public : Widget(QWidget *parent = nullptr); ~Widget(); protected : virtual void mousePressEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); virtual void mouseDoubleClickEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); virtual void paintEvent(QPaintEvent *event); private : void drawSpline(); qreal N( int k, int i, qreal u); qreal N1( int i, qreal u); qreal N2( int i, qreal u); qreal N3( int i, qreal u); private : QVector<QPointF> m_ctrlPoints; // 控制點 QVector<QPointF> m_curvePoints; // 曲線上的點 }; #endif // WIDGET_H |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
#include
"Widget.h"
#include <QMouseEvent> #include <QPainter> #include <cmath> Widget::Widget(QWidget *parent) : QWidget(parent) { } Widget::~Widget() { } void Widget::mousePressEvent(QMouseEvent *event) { // 單擊鼠標左鍵獲取控制點 if (event->buttons() == Qt::LeftButton){ m_ctrlPoints.push_back(event->pos()); } // 單擊鼠標右鍵清空控制點 else if (event->buttons() == Qt::RightButton) { m_ctrlPoints.clear(); } update(); } void Widget::mouseReleaseEvent(QMouseEvent *event) { } void Widget::mouseDoubleClickEvent(QMouseEvent *event) { } void Widget::mouseMoveEvent(QMouseEvent *event) { } void Widget::paintEvent(QPaintEvent *event) { drawSpline(); } void Widget::drawSpline() { QPainter painter( this ); int currentK = 3 ; // 階數 m_curvePoints.clear(); for (qreal u = currentK; u < m_ctrlPoints.size(); u += 0 . 01 ){ QPointF pt( 0 . 0 , 0 . 0 ); for ( int i = 0 ; i < m_ctrlPoints.size(); ++i){ QPointF pts = m_ctrlPoints[i]; pts *= N(currentK, i, u); pt += pts; } m_curvePoints.push_back(pt); } // draw control points QPen ctrlPen1(QColor( 0 , 0 , 255 )); ctrlPen1.setWidth( 5 ); painter.setPen(ctrlPen1); for ( int i = 0 ; i < m_ctrlPoints.size(); ++i){ painter.drawPoint(m_ctrlPoints[i]); } // draw control lines QPen ctrlPen2(QColor( 255 , 0 , 0 )); ctrlPen2.setWidth( 1 ); ctrlPen2.setStyle(Qt::DashDotDotLine); painter.setPen(ctrlPen2); for ( int i = 0 ; i < m_ctrlPoints.size() - 1 ; ++i){ painter.drawLine(m_ctrlPoints[i], m_ctrlPoints[i + 1 ]); } // draw spline curve QPen curvePen(QColor( 0 , 0 , 0 )); curvePen.setWidth( 2 ); painter.setPen(curvePen); for ( int i = 0 ; i < m_curvePoints.size() - 1 ; ++i){ painter.drawLine(m_curvePoints[i], m_curvePoints[i + 1 ]); } } qreal Widget::N( int k, int i, qreal u) { switch (k) { case 1 : return N1(i, u); case 2 : return N2(i, u); case 3 : return N3(i, u); default : break ; } } qreal Widget::N1( int i, qreal u) { qreal t = u - i; if ( 0 <= t && t < 1 ){ return t; } if ( 1 <= t && t < 2 ){ return 2 - t; } return 0 ; } qreal Widget::N2( int i, qreal u) { qreal t = u - i; if ( 0 <= t && t < 1 ){ return 0 . 5 * t * t; } if ( 1 <= t && t < 2 ){ return 3 * t - t * t - 1 . 5 ; } if ( 2 <= t && t < 3 ){ return 0 . 5 * pow( 3 - t, 2 ); } return 0 ; } qreal Widget::N3( int i, qreal u) { qreal t = u - i; qreal a = 1 . 0 / 6 . 0 ; if ( 0 <= t && t < 1 ){ return a * t * t * t; } if ( 1 <= t && t < 2 ){ return a * (- 3 * pow(t - 1 , 3 ) + 3 * pow(t - 1 , 2 ) + 3 * (t - 1 ) + 1 ); } if ( 2 <= t && t < 3 ){ return a * ( 3 * pow(t - 2 , 3 ) - 6 * pow(t - 2 , 2 ) + 4 ); } if ( 3 <= t && t < 4 ){ return a * pow( 4 - t, 3 ); } return 0 ; } |