PyQt6实现N阶贝塞尔曲线

PyQt6实现N阶贝塞尔曲线

先看效果
贝塞尔曲线
贝塞尔曲线的教程以及代码网上资料蛮多的,这里也不做过多叙述。

制作思路:鼠标右键点击生成新点,左键移动点调节贝塞尔曲线,生成新点和移动点时调用self.update()函数刷新控件,实现实时调节贝塞尔曲线,完整代码如下。

import sys
from PyQt6.QtGui import *
from PyQt6.QtGui import QPaintEvent
from PyQt6.QtWidgets import *
from PyQt6.QtCore import *
import math

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.points = [] # 存储所有点
        self.current_point_index = -1 # 记录当前点的索引
        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle('Bézier curve')
        self.show()

    def mouseMoveEvent(self, e: QMouseEvent | None) -> None:
        if e.buttons() == Qt.MouseButton.LeftButton and self.current_point_index != -1:
            self.points[self.current_point_index] = e.pos()
            self.update()
    
    def mouseReleaseEvent(self, e: QMouseEvent | None) -> None:
        self.current_point_index = -1

    def mousePressEvent(self, e: QMouseEvent | None) -> None:
        if e.button() == Qt.MouseButton.RightButton:
            self.points.append(e.pos())
            self.update()
        elif e.button() == Qt.MouseButton.LeftButton:
            for i,p in enumerate(self.points):
                if pow(e.pos().x() - p.x(), 2) + pow(e.pos().y() - p.y(), 2) < 30:
                    self.current_point_index = i
                    break
        
        
    def paintEvent(self, e: QPaintEvent | None) -> None:
        qp = QPainter()
        qp.begin(self)
        qp.setRenderHint(QPainter.RenderHint.Antialiasing)
        # 绘制点
        self.drawPoint(qp)
        # 绘制曲线
        self.drawBezierCurve(qp)
        qp.end()
    
    def drawPoint(self, qp:QPainter):
        pen = QPen(Qt.GlobalColor.red, 15)
        pen.setCapStyle(Qt.PenCapStyle.RoundCap)
        for i,p in enumerate(self.points):
            qp.setPen(pen)
            qp.drawPoint(p)
            # 绘制索引
            qp.setPen(Qt.GlobalColor.white)
            rect = QFontMetrics(qp.font()).boundingRect(str(i))
            qp.drawText(p.toPointF() + QPointF(-rect.width() / 2, rect.height() / 2 - 2.0), str(i))
        

    def drawBezierCurve(self, qp:QPainter):
        # 贝塞尔曲线
        n = len(self.points) - 1
        if n <= 0:
            return
        pos = []
        step = 0.001 # 精度
        t = 0
        while t <= 1:
            b = []
            for j in range(n + 1):
                b.append(math.comb(n, j) * pow(t, j) * pow(1 - t, n - j))
            x = y = 0
            for j in range(n + 1):
                x += self.points[j].x() * b[j]
                y += self.points[j].y() * b[j]
            pos.append(QPointF(x, y))
            t += step
        pos.append(QPointF(self.points[-1]))

        # 开始绘制
        qp.setPen(QPen(Qt.GlobalColor.black, 3))
        path = QPainterPath()
        path.moveTo(pos[0])
        for i in range(len(pos) - 1):
            path.lineTo(pos[i + 1])
        qp.drawPath(path)
    
def main():

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec())


if __name__ == '__main__':
    main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值