码迷,mamicode.com
首页 > 其他好文 > 详细

QT绘制B样条曲线

时间:2019-07-02 19:20:16      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:include   +=   private   cal   upd   user   font   inter   obj   

²  贝塞尔曲线

贝塞尔曲线是通过一组多边折线的各顶点来定义。在各顶点中,曲线经过第一点和最后一点,其余各点则定义曲线的导数、阶次和形状。第一条和最后一条则表示曲线起点和终点的切线方向。

技术图片

²  B样条曲线

针对贝塞尔曲线存在的一些缺点,数学家们提出了B样条方法,在保留贝塞尔全部优点的同时,克服可贝塞尔方法的弱点。

1)      二次B样条曲线

技术图片

2)      三次B样条曲线

技术图片

 QT中的QPainter提供了绘制贝塞尔曲线的相关API:

void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)

void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)

void QPainter::drawPath(const QPainterPath &path)

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.00.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(00255));
    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(25500));
    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(000));
    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 - 13) + 3 * pow(t - 12) + 3 * (t - 1) + 1);
    }
    
if (2 <= t && t < 3){
        
return a * (3 * pow(t - 23) - 6 * pow(t - 22) + 4);
    }
    
if (3 <= t && t < 4){
        
return a * pow(4 - t, 3);
    }
    
return 0;
}

技术图片技术图片技术图片

QT绘制B样条曲线

标签:include   +=   private   cal   upd   user   font   inter   obj   

原文地址:https://www.cnblogs.com/MakeView660/p/11122320.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!