Итак, сейчас я пытаюсь сделать срезы на плоскости, ортогональной сплайну. Направление на самом деле не имеет большого значения, так как я использую точки для интерполяции 3D-сканов
Я в основном не уверен насчет метода rotmat (это урезанная версия моего класса, технически NURBS- Python, производный класс поверхности), где я поворачиваю плоскость me sh из плоской плоскости x / y (все z = 0), чтобы соответствовать новому вектору нормали (касательной к сплайну, хранящемуся в переменной der).
Кто-нибудь знает, как повернуть набор точек на go из одного вектора нормали в другой? Угол вокруг оси нового вектора для меня не имеет большого значения.
(извините за vg, что-то вроде непонятной библиотеки, но на самом деле несколько удобное):
from scipy.interpolate import splprep, splev
import numpy as np
import vg
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.spatial.transform import Rotation as R
class SplineTube():
_points = np.array(
[[0, 0, 0],
[0, 1, 0],
[1, 1, 0],
[1, 0, 0]],
) - np.array([0.5, 0.5, 0])
_normal = np.array([0, 0, 1])
def __init__(self, x, y, z, n = 3, degree=2, **kwargs):
assert n >= 3
tck, u = splprep([x, y, z], s=0, k=2)
evalpts = np.linspace(0, 1, n)
pts = np.array(splev(evalpts, tck))
der = np.array(splev(evalpts, tck, der=1))
points = []
for i in range(n):
points_slice = self.rotmat(der[:, i], self._points)
points_slice = points_slice + pts[:, i]
points.append(points_slice)
points = np.stack(points)
return points
def rotmat(self, vector, points):
perpen = vg.perpendicular(self._normal, vector)
r = R.from_rotvec(perpen)
rotmat = r.apply(points)
return rotmat
Вот пример, в котором я использовал сетку вместо _points, но очень похож:
Плоскости, следующие за сплайном
x = [0, 1, 2, 3, 6]
y = [0, 2, 5, 6, 2]
z = [0, 3, 5, 7, 10]
tck, u = splprep([x, y, z], s=0, k=2)
evalpts = np.linspace(0, 1, 10)
pts = splev(evalpts, tck)
der = splev(evalpts, tck, der=1)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(pts[0], pts[1], pts[2])
ax.quiver(*pts, *der, length=0.05)
ax.scatter(x, y, z)
planes = SplineTube(x, y, z, n=10)
ax.scatter(planes[:, :, 0], planes[:, :, 1], planes[:, :, 2])