Qt中绘制曲线

贝塞尔曲线(自动生成控制点)

效果
这里写图片描述

代码:

void CurveLearn::paintEvent(QPaintEvent *) {
    // 曲线上的点
    static QList<QPointF> points = QList<QPointF>() << QPointF(0, 0) << QPointF(100, 100) << QPointF(200, -100)
                                                    << QPointF(300, 100) << QPointF(330, -80) << QPointF(350, -70);
    QPainterPath path(points[0]);
    for (int i = 0; i < points.size() - 1; ++i) {
        // 控制点的 x 坐标为 sp 与 ep 的 x 坐标和的一半
        // 第一个控制点 c1 的 y 坐标为起始点 sp 的 y 坐标
        // 第二个控制点 c2 的 y 坐标为结束点 ep 的 y 坐标
        QPointF sp = points[i];
        QPointF ep = points[i+1];
        QPointF c1 = QPointF((sp.x() + ep.x()) / 2, sp.y());
        QPointF c2 = QPointF((sp.x() + ep.x()) / 2, ep.y());
//        QPointF c2 = QPointF(ep.x(), (sp.y() + ep.y()) / 2);
        path.cubicTo(c1, c2, ep);
    }
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setPen(QPen(Qt::black, 2));
    // 绘制 path
    //移动默认(0,0)到(40,130)
    painter.translate(40, 130);
    painter.drawPath(path);
    // 绘制曲线上的点
    painter.setBrush(Qt::gray);
    for (int i = 0; i < points.size(); ++i) {
        painter.drawEllipse(points[i], 4, 4);
    }
}

2.另一种效果
在这里插入图片描述

资源路径:https://download.csdn.net/download/yuxing55555/10841947

pyqt中绘制贝塞尔曲线(示例)

from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsScene, QGraphicsView, QWidget, QLabel
from PyQt5.QtGui import QPainterPath, QPainter, QPen
from PyQt5.QtCore import Qt


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.label_size = 5
        self.resize(600, 600)
        self.startLabel = QLabel(self)
        self.startLabel.resize(self.label_size, self.label_size)
        self.startLabel.setStyleSheet('QLabel{background-color:red}')
        self.startLabel.move(100, 110)

        self.ctrlLabel1 = QLabel(self)
        self.ctrlLabel1.resize(self.label_size, self.label_size)
        self.ctrlLabel1.setStyleSheet('QLabel{background-color:green}')
        self.ctrlLabel1.move(200, 100)

        self.ctrlLabel2 = QLabel(self)
        self.ctrlLabel2.resize(self.label_size, self.label_size)
        self.ctrlLabel2.setStyleSheet('QLabel{background-color:green}')
        self.ctrlLabel2.move(300, 300)

        self.endLabel = QLabel(self)
        self.endLabel.resize(self.label_size, self.label_size)
        self.endLabel.setStyleSheet('QLabel{background-color:red}')
        self.endLabel.move(400, 200)

        self.selectedWidget = None

    def paintEvent(self, event):
        pen = QPen(Qt.black, 2)

        painter = QPainter()
        painter.begin(self)
        painter.setPen(pen)
        painter.drawLine(self.startLabel.pos(), self.ctrlLabel1.pos())
        painter.drawLine(self.ctrlLabel2.pos(), self.endLabel.pos())

        path = QPainterPath()
        path.moveTo(self.startLabel.pos())
        path.cubicTo(self.ctrlLabel1.pos(), self.ctrlLabel2.pos(), self.endLabel.pos())
        painter.setPen(Qt.red)
        painter.drawPath(path)

        painter.end()

    def mousePressEvent(self, event):
        w = self.childAt(event.pos())
        if w is None:
            return
        if w.inherits('QLabel'):
            self.selectedWidget = w
        # if event.button() == Qt.LeftButton:
        #     print("Left mouse button pressed")

    def mouseMoveEvent(self, event):
        if self.selectedWidget:
            self.selectedWidget.move(event.pos())
            self.update()

    def mouseReleaseEvent(self, event):
        self.selectedWidget = None


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

效果图:
在这里插入图片描述

pyqt中通过鼠标事件绘制贝塞尔曲线

代码:

from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsScene, QGraphicsView, QWidget, QLabel
from PyQt5.QtGui import QPainterPath, QPainter, QPen
from PyQt5.QtCore import Qt, QPoint


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(600, 600)
        self.label_size = 10
        self.style_point = 'QLabel{background-color:red}'
        self.style_ctrl_point = 'QLabel{background-color:green}'
        self.selectedWidget = None
        self.point_array = []
        self.point_ctrl_array = []
        self.left_button_down = False

    def addPoint(self, pos, pos_type):
        print('pos:', pos, pos_type)
        pos_label = QLabel(self)
        pos_label.resize(self.label_size, self.label_size)
        if pos_type == 0:
            pos_label.setStyleSheet(self.style_point)
        elif pos_type == 1:
            pos_label.setStyleSheet(self.style_ctrl_point)
        pos_label.move(pos)
        pos_label.show()
        self.update()
        return pos_label

    def paintEvent(self, event):
        if len(self.point_array) < 1:
            self.update()
            return
        if len(self.point_array) != len(self.point_ctrl_array)/2:
            return
        pen = QPen(Qt.black, 2)
        painter = QPainter()
        painter.begin(self)
        painter.setPen(pen)
        for i in range(len(self.point_array)):
            painter.drawLine(self.point_array[i].pos(), self.point_ctrl_array[i*2].pos())
            painter.drawLine(self.point_array[i].pos(), self.point_ctrl_array[i*2+1].pos())

        if len(self.point_array) == 1:
            painter.end()
            return

        path = QPainterPath()
        path.moveTo(self.point_array[0].pos())
        for i in range(1, len(self.point_array)):
            path.cubicTo(self.point_ctrl_array[(i-1)*2+1].pos(), self.point_ctrl_array[i*2].pos(),
                         self.point_array[i].pos())

        pen_curve = QPen(Qt.red, 2)
        painter.setPen(pen_curve)
        painter.drawPath(path)
        painter.end()
        self.update()

    def mousePressEvent(self, event):
        w = self.childAt(event.pos())
        print('widget:', w)
        if w is None:
            self.left_button_down = True
            point = self.addPoint(event.pos(), 0)
            self.point_array.append(point)
            self.update()
            return
        if w.inherits('QLabel'):
            self.selectedWidget = w
        # if event.button() == Qt.LeftButton:
        #     print("Left mouse button pressed")

    def mouseMoveEvent(self, event):
        if self.selectedWidget:
            self.selectedWidget.move(event.pos())
        else:
            if self.left_button_down:
                right_pos = event.pos()
                tmp_pos = self.point_array[-1].pos()
                delta_value = [right_pos.x()-tmp_pos.x(), right_pos.y()-tmp_pos.y()]
                left_pos = QPoint(tmp_pos.x()-delta_value[0], tmp_pos.y()-delta_value[1])
                if len(self.point_array) == len(self.point_ctrl_array) / 2:
                    self.point_ctrl_array[-2].move(left_pos)
                    self.point_ctrl_array[-1].move(right_pos)
                else:
                    self.point_ctrl_array.append(self.addPoint(left_pos, 1))
                    self.point_ctrl_array.append(self.addPoint(right_pos, 1))
        self.update()

    def mouseReleaseEvent(self, event):
        self.selectedWidget = None
        self.left_button_down = False
        if len(self.point_array) == len(self.point_ctrl_array)/2:
            return
        else:
            pos_step = 20
            last_pos = self.point_array[-1].pos()
            left_pos = QPoint(last_pos.x()-pos_step, last_pos.y()+pos_step)
            right_pos = QPoint(last_pos.x()+pos_step, last_pos.y()-pos_step)
            self.point_ctrl_array.append(self.addPoint(left_pos, 1))
            self.point_ctrl_array.append(self.addPoint(right_pos, 1))
        self.update()


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

效果图:
在这里插入图片描述

纯numpy实现贝塞尔曲线计算

地址:https://github.com/torresjrjr/Bezier.py

效果图:
在这里插入图片描述
在这里插入图片描述
源码:

"""Bezier, a module for creating Bezier curves.
Version 1.1, from < BezierCurveFunction-v1.ipynb > on 2019-05-02
"""

import numpy as np

__all__ = ["Bezier"]


class Bezier():
    def TwoPoints(t, P1, P2):
        """
        Returns a point between P1 and P2, parametised by t.
        INPUTS:
            t     float/int; a parameterisation.
            P1    numpy array; a point.
            P2    numpy array; a point.
        OUTPUTS:
            Q1    numpy array; a point.
        """

        if not isinstance(P1, np.ndarray) or not isinstance(P2, np.ndarray):
            raise TypeError('Points must be an instance of the numpy.ndarray!')
        if not isinstance(t, (int, float)):
            raise TypeError('Parameter t must be an int or float!')

        Q1 = (1 - t) * P1 + t * P2
        return Q1

    def Points(t, points):
        """
        Returns a list of points interpolated by the Bezier process
        INPUTS:
            t            float/int; a parameterisation.
            points       list of numpy arrays; points.
        OUTPUTS:
            newpoints    list of numpy arrays; points.
        """
        newpoints = []
        #print("points =", points, "\n")
        for i1 in range(0, len(points) - 1):
            #print("i1 =", i1)
            #print("points[i1] =", points[i1])

            newpoints += [Bezier.TwoPoints(t, points[i1], points[i1 + 1])]
            #print("newpoints  =", newpoints, "\n")
        return newpoints

    def Point(t, points):
        """
        Returns a point interpolated by the Bezier process
        INPUTS:
            t            float/int; a parameterisation.
            points       list of numpy arrays; points.
        OUTPUTS:
            newpoint     numpy array; a point.
        """
        newpoints = points
        #print("newpoints = ", newpoints)
        while len(newpoints) > 1:
            newpoints = Bezier.Points(t, newpoints)
            #print("newpoints in loop = ", newpoints)

        #print("newpoints = ", newpoints)
        #print("newpoints[0] = ", newpoints[0])
        return newpoints[0]

    def Curve(t_values, points):
        """
        Returns a point interpolated by the Bezier process
        INPUTS:
            t_values     list of floats/ints; a parameterisation.
            points       list of numpy arrays; points.
        OUTPUTS:
            curve        list of numpy arrays; points.
        """

        if not hasattr(t_values, '__iter__'):
            raise TypeError("`t_values` Must be an iterable of integers or floats, of length greater than 0 .")
        if len(t_values) < 1:
            raise TypeError("`t_values` Must be an iterable of integers or floats, of length greater than 0 .")
        if not isinstance(t_values[0], (int, float)):
            raise TypeError("`t_values` Must be an iterable of integers or floats, of length greater than 0 .")

        curve = np.array([[0.0] * len(points[0])])
        for t in t_values:
            #print("curve                  \n", curve)
            #print("Bezier.Point(t, points) \n", Bezier.Point(t, points))

            curve = np.append(curve, [Bezier.Point(t, points)], axis=0)

            #print("curve after            \n", curve, "\n--- --- --- --- --- --- ")
        curve = np.delete(curve, 0, 0)
        #print("curve final            \n", curve, "\n--- --- --- --- --- --- ")
        return curve

测试代码:

from Bezier import Bezier
import numpy as np
import matplotlib.pyplot as plt


t_points = np.arange(0, 1.1, 0.05) #................................. Creates an iterable list from 0 to 1.
points1 = np.array([[0, 0], [0, 8], [5, 10], [9, 7]]) #.... Creates an array of coordinates., [4, 3]
curve1 = Bezier.Curve(t_points, points1) #......................... Returns an array of coordinates.
print(len(curve1))
plt.figure()
plt.plot(
	curve1[:, 0],   # x-coordinates.
	curve1[:, 1]    # y-coordinates.
)
plt.plot(
	points1[:, 0],  # x-coordinates.
	points1[:, 1],  # y-coordinates.
	'ro:'           # Styling (red, circles, dotted).
)
plt.grid()
plt.show()

help(Bezier)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力减肥的小胖子5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值