修改自这个老哥的,非常的nice,此处仅作为学习记录。
matplotlib==3.7.0 可行
Note: 数值解法是真的快
先上图
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import math
import time
class Bezier:
def __init__(self, Points, InterpolationNum):
# 输入控制点,Points是一个array,num是控制点间的插补个数
self.pointsNum = Points.shape[0] # 控制点的个数
self.demension = Points.shape[1] # 点的维度
self.order = Points.shape[0] - 1 # 贝塞尔阶数=控制点个数-1
self.num = InterpolationNum # 相邻控制点的插补个数
self.Points = Points
def DigitalAlgo(self):
# 数值解法
PB = np.zeros((self.pointsNum, self.demension)) # 求和前各项
pis = [] # 插补点
for u in np.arange(0, 1 + 1 / self.num, 1 / self.num):
for i in range(0, self.pointsNum):
PB[i] = (math.factorial(self.order) / (
math.factorial(i) * math.factorial(self.order - i))) * (u ** i) * (
1 - u) ** (self.order - i) * self.Points[i]
pi = sum(PB).tolist() # 求和得到一个插补点
pis.append(pi)
return np.array(pis)
def DeCasteljauAlgo(self):
# 德卡斯特里奥解法
pis = [] # 插补点
for u in np.arange(0, 1 + 1 / self.num, 1 / self.num):
Att = self.Points
for i in np.arange(0, self.order):
for j in np.arange(0, self.order - i):
Att[j] = (1.0 - u) * Att[j] + u * Att[j + 1]
pis.append(Att[0].tolist())
return np.array(pis)
def __call__(self, method):
# 获取Bezeir所有插补点
if method == 0:
return self.DigitalAlgo()
if method == 1:
return self.DeCasteljauAlgo()
points = np.array([
[1, 3, 0],
[1.5, 1, 0],
[4, 2, 0],
[4, 3, 4],
[2, 3, 11],
[5, 5, 9],
[1, 3, 0],
[1.5, 1, 0],
[4, 2, 0],
[4, 3, 4],
[2, 3, 11],
[5, 5, 9]
])
points[6:, ...] = 5 + points[6:, ...]
# points = np.array([
# [0.0, 0.0, 0.],
# [1.0, 0.0, 1.],
# [1.0, 1.0, 1.],
# [0.0, 1.0, 2.],
# ])
if points.shape[1] == 3:
fig = plt.figure()
ax = fig.add_axes(Axes3D(fig))
# 标记控制点
for i, point in enumerate(points, 1):
ax.scatter(point[0], point[1], point[2], marker='o', color='r')
ax.text(point[0], point[1], point[2], i, size=12)
# 直线连接控制点
ax.plot3D(points[:, 0], points[:, 1], points[:, 2], color='k')
# 贝塞尔曲线连接控制点
s = time.time()
matpi = Bezier(points, 10000)(0)
print(f'{time.time() - s:.5f}s')
ax.plot3D(matpi[:, 0], matpi[:, 1], matpi[:, 2], color='r')
plt.show()
# 0 0.12295s
# 1 0.35341s
if points.shape[1] == 2:
# 标记控制点
for i, point in enumerate(points, 1):
plt.scatter(point[0], point[1], point[2], marker='o', color='r')
plt.text(point[0], point[1], point[2], i, size=12)
# 直线连接控制点
plt.plot(points[:, 0], points[:, 1], color='k')
# 贝塞尔曲线连接控制点
matpi = Bezier(points, 1000)(1)
plt.plot(matpi[:, 0], matpi[:, 1], color='r')
plt.show()
推荐一下bezier这个库画bezier贝塞尔曲线
也非常的好用,具体的看官方介绍吧....
不会安装的看这个详细的安装教程
import bezier
import numpy as np
import matplotlib.pyplot as plt
nodes1 = np.array([
[0.0, 0.5, 1.0],
[0.0, 1.0, 0.0],
])
nodes2 = np.array([
[0.0, 0.25, 0.5, 0.75, 1.0],
[0.0, 2.0, -2.0, 2.0, 0.0],
])
print(nodes2)
curve1 = bezier.Curve(nodes1, degree=2)
curve2 = bezier.Curve.from_nodes(nodes2)
intersections = curve1.intersect(curve2)
s_vals = np.array(intersections[0, :])
points = curve1.evaluate_multi(s_vals)
ax = curve1.plot(num_pts=256)
_ = curve2.plot(num_pts=256, ax=ax)
lines = ax.plot(
points[0, :], points[1, :],
marker="o", linestyle="None", color="black")
# ax.plot(nodes1[0, :], nodes1[1, :], label='l1')
# ax.plot(nodes2[0, :], nodes2[1, :], label='l2')
# ax.axis("scaled")
ax.set_xlim(-0.125, 1.125)
ax.set_ylim(-0.0625, 0.625)
plt.legend()
plt.show()