QT绘制B样条曲线

²  贝塞尔曲线

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

²  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.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;
}

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

时间: 2024-08-30 11:20:57

QT绘制B样条曲线的相关文章

QT绘制系统简介

#3个类:QPainter,QPainterDevice 和 QPaintEngine 三个类 #qpainter用于执行绘制操作 #QPainterDevice是一个二维空间抽象,允许qpainter在其上面进行绘制,也就是qpainter工作空间 #QPaintEngine 提供了画笔(qpainter)在不同设备上进行绘制统一接口,QPaintEngine类应用于QPainter和QPaintDevice 之间,如果需要自定义一个设备时 #则不需要关心QPaintEngine 这个类的QP

qt绘制设备

# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' from PyQt4.QtGui import  * from PyQt4.Qt import * from PyQt4 import QtGui, QtCore from PyQt4.QtCore import * import sys #说明:绘图设备是继承 QPainterDevice 的类. QPaintDevice 就是能够进行绘制的类,也就是说, # Q

QT绘制饼图

QT版本:QT5.6.1 QT绘制饼图,出问题的代码如下 void DrawPieDialog::paintEvent(QPaintEvent *event) { float startAngle=0; float spanAngle=( (qreal) (sell) / (qreal)(sell+last) ) *360; QPoint startPt(30,30); //圆心 QRect rect(startPt.x(), startPt.y(), 200, 200); QPainter p

Qt绘制异形窗体

异形窗体即不规则窗体,一般采用png图片,一般绘制异形窗体分两步: 1.设置遮罩区 2.绘制图片   使用png图片的透明部分作为遮罩区,然后绘制图片,这样我们就看到一个只绘制了非透明部分的图形,废话少说,以实现绘制一只蝴蝶(蝴蝶为半透明)为例,效果如下: 头文件: 1: #include <QWidget> 2: class TransDialog : public QWidget 3: { 4: Q_OBJECT 5: public: 6: explicit TransDialog(QWi

Qt 学习之路 :Qt 绘制系统简介

Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类. QPainter用来执行绘制的操作:QPaintDevice是一个二维空间的抽象,这个二维空间允许QPainter在其上面进行绘制,也就是QPainter工作的空间:QPaintEngine提供了画笔(QPainter)在不同的设备上进行绘制的统一的接口.QPaintEngine类应用于QPainter和QPaintDevice

Qt绘制动态曲线

首先*.pro文件中加一句 QT += charts 然后 mainwindow.cpp文件如下: #include "mainwindow.h" #include "ui_mainwindow.h" #include "QtCharts/QChart" #include "QLineSeries" #include "QValueAxis" #include "QTimer" #inc

Qt绘制文本二 弧形路径 正弦函数路径

void WgtText::paintEvent(QPaintEvent *event) { QPainter painter(this); QString m_string("abcdefghijklmnopqrstuvwxy"); int font_size = 15; float x0 = font_size * m_string.count() * 0.5; int YSize = font_size * m_string.count() * 0.5; for(int i=0;

QT绘制半透明窗体(改写paintEvent,超级简单)

在派生类中重载QDialog的void paintEvent(QPaintEvent *)事件,在这个函数中加入以下代码 QPainter painter(this);    QLinearGradient grad(0, 0, width(), height());    QGradientStops gs;        gs << QGradientStop(0.0, QColor(0, 0, 0 , 100))        << QGradientStop(0.5, QC

QT的Paint 系统

下面对于QT的绘制系统做一个简要说明, 这个系统主要由三部分组成,  QPainter, QPaintDevice, QPaintEngine. QPainter 是一个绘制接口类,提供绘制各种面向用户的命令,而QPaintDevice 是一个QPainter绘制的目的地,相当于画布,   而QPaintEngine 是基本绘制命令的具体实现. 我们打交道比较多的是 QPainter , 注意对于Windows平台来说,当绘制目标是一个widget的时候,QPainter只能在 paintEve