接上文,在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_())