QT繪製B樣條曲線

²  貝塞爾曲線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

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
 
/////////////////////////////////////////////////////////////
/// @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
Widget.pp 
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 ;
}

相關文章
相關標籤/搜索