² 贝塞尔曲线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 ; } |