在Python中实现B-Spline

接上文,在python中使用numpy,pyside2 实现B-Spline。
(强烈吐槽网络上B-Spline的定义公式 玩起了 " <=, <, >, >=" 的排列组合游戏)

效果图:


B-Spline.PNG

代码:

import sys
import numpy as  np
from PySide2 import QtCore, QtGui
from PySide2.QtCharts import QtCharts
from PySide2.QtWidgets import (QApplication, QWidget, QGraphicsScene, QGraphicsView)

class Vector2d(object):
    def __init__(self, x = 0, y = 0):
        self.X = x
        self.Y = y
    
    def x(self):
        return self.X
    
    def y(self):
        return self.Y
    
    def __add__(self, other):
        return Vector2d(self.X+ other.x(), self.Y+ other.y())

    def __sub__(self, other):
        return Vector2d(self.X- other.x(), self.Y- other.y())

    def __mul__(self, other):
        return Vector2d(self.X* other, self.Y* other)

    def __rmul__(self, other):
        return Vector2d(self.X* other, self.Y* other)

def polyNomial(i, k, u, uNode):
    if k == 1:
        if  uNode[i] <= u and u < uNode[i + 1]:
            return 1
        else:
            return 0

    l1 = uNode[i+k-1] - uNode[i]
    l2 = uNode[i+k] - uNode[i+1]
    a = 0
    b = 0
    if l1 != 0:
        a = (u - uNode[i])/l1
    if l2 != 0:
        b =  (uNode[i+k] - u)/l2
    return a* polyNomial(i, k-1, u, uNode) + b* polyNomial(i+1, k-1, u, uNode)

def GenerateBPoint(cpoints = list(), distance = 0.1):

    bezierPoints = list()
    
    k = 3
    n = len(cpoints)

    uNode =  np.linspace(0, 10, n+k)

    for j in range(k-1, n):
        u = uNode[j]
        while u < uNode[j+1]:
            bSplinePt = Vector2d()
            for i in range(0, n):
                bkd = polyNomial(i, k, u, uNode)
                bSplinePt.X += cpoints[i].x() * bkd
                bSplinePt.Y += cpoints[i].y() * bkd
            bezierPoints.append(bSplinePt)
            u += distance
    return bezierPoints

def convert(v2d):
    qpoint =list()
    for item in v2d:
        qpoint.append( QtCore.QPointF( item.x(), item.y() ) )
    return qpoint

def BPoints():
    return [ Vector2d(10, 10), Vector2d(20, 90), Vector2d(40, 20), Vector2d(60, 80), Vector2d(80, 5)]

class MyBezier(QGraphicsView):
    def __init__(self, parent = None):
        super(MyBezier, self).__init__(parent)
        self.setWindowTitle('B-Spline')
        self.setScene(QGraphicsScene(self))
        self.setDragMode(QGraphicsView.NoDrag)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

        self.chart = QtCharts.QChart()
        self.chart.setMinimumSize(640, 480)
        self.chart.setTitle("B-Spline Test")
        self.chart.legend().hide()

        self.series = QtCharts.QLineSeries()
        self.series.append( convert( GenerateBPoint(BPoints()) )  )
        self.cSeries = QtCharts.QLineSeries()
        self.cSeries.append( convert(BPoints()) )

        self.chart.addSeries(self.series)
        self.chart.addSeries(self.cSeries)
        self.chart.createDefaultAxes()
        
        self.scene().addItem(self.chart)

        self.setRenderHint(QtGui.QPainter.Antialiasing)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    v = MyBezier()
    v.show()
    sys.exit(app.exec_())
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容