Python: повернуть плоскость (набор точек) для соответствия новому вектору нормали с помощью scipy.spatial.transform.Rotation - PullRequest
0 голосов
/ 06 августа 2020

Итак, сейчас я пытаюсь сделать срезы на плоскости, ортогональной сплайну. Направление на самом деле не имеет большого значения, так как я использую точки для интерполяции 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])
...