简体   繁体   English

Python:使用 scipy.spatial.transform.Rotation 旋转平面(点集)以匹配新的法线向量

[英]Python: Rotate plane (set of points) to match new normal vector using scipy.spatial.transform.Rotation

So I'm currently trying to take slices on a plane orthogonal to a spline.所以我目前正在尝试在与样条正交的平面上进行切片。 Direction doesn't really matter too much since I'm using the points to interpolate 3D scans方向并不重要,因为我使用这些点来插入 3D 扫描

I'm mainly unsure about the rotmat method (this is a stripped down version of my class, technically a NURBS-Python surface derived class), where I'm rotating the plane mesh from a flat x/y plane (all z=0) to match the new normal vector (tangent of the spline, stored in the der variable).我主要不确定 rotmat 方法(这是我的 class 的精简版本,技术上是 NURBS-Python 表面派生类),其中我从平面 x/y 平面旋转平面网格(所有 z=0 ) 以匹配新的法线向量(样条的切线,存储在 der 变量中)。

Anyone have an idea how to rotate a set of points to go from one normal vector to another?任何人都知道如何将一组点从一个法向量旋转到 go 到另一个? The angle around the axis of the new vector doesn't matter than much to me.围绕新向量的轴的角度对我来说并不重要。

(sorry for vg, kind of an obscure library but somewhat convenient actually): (对不起 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

Here's an example where I used a meshgrid instead of the _points, but is very similar:这是我使用网格而不是 _points 的示例,但非常相似:

Planes following spline跟随样条的平面

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])

I think I ended up producing something that seems to work in the end:我想我最终产生了一些似乎最终有效的东西:

import numpy as np
import vg
from pytransform3d.rotations import matrix_from_axis_angle

def _rotmat(self, vector, points):
    """
    Rotates a 3xn array of 3D coordinates from the +z normal to an
    arbitrary new normal vector.
    """
    
    vector = vg.normalize(vector)
    axis = vg.perpendicular(vg.basis.z, vector)
    angle = vg.angle(vg.basis.z, vector, units='rad')
    
    a = np.hstack((axis, (angle,)))
    R = matrix_from_axis_angle(a)
    
    r = Rot.from_matrix(R)
    rotmat = r.apply(points)
    
    return rotmat

Not too insanely complicated, just start with a plane of points aligned with the xy plane (assuming you're using xy as your horizontal like me here apparently, please don't hate me), then it'll rotate it along the vector and not really care about rotation about the axis.不太复杂,只需从与 xy 平面对齐的点平面开始(假设您显然像我一样在这里使用 xy 作为水平线,请不要讨厌我),然后它会沿着向量旋转它并不太关心绕轴旋转。 Seems to work ok.似乎工作正常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 scipy.spatial.transform.Rotation 旋转数组与同一 object 内的堆栈 - scipy.spatial.transform.Rotation Array of rotation vs Stack inside the same object 在python中使用scipy.spatial.distance.cdist(X,Y)查找一组点之间的距离 - finding the distance between a set of points using scipy.spatial.distance.cdist(X, Y) in python 使用 pyinstaller 编译 python 脚本后,没有名为 'scipy.spatial.transform._rotation_groups 的模块 - No module named 'scipy.spatial.transform._rotation_groups after compile python script with pyinstaller 使用numpy中的旋转矩阵有效旋转一组点 - Efficiently rotate a set of points with a rotation matrix in numpy ratcave: 'scipy.spatial.transform.rotation.Rotation' object 没有属性 'as_dcm' - ratcave : 'scipy.spatial.transform.rotation.Rotation' object has no attribute 'as_dcm' 将法线向量绘制到平面 - ploting the normal vector to a plane Rodrigues一组点相对于向量的旋转 - Rodrigues Rotation of a set of points relative to a vector CX_FREEZE 错误没有名为“scipy.spatial.transform._rotation_groups”的模块 - CX_FREEZE ERROR No module named 'scipy.spatial.transform._rotation_groups' SimpleITK.Euler3DTransform 和 scipy.spatial.transform.Rotation.from_euler 的区别? - Difference between SimpleITK.Euler3DTransform and scipy.spatial.transform.Rotation.from_euler? 如何使用角度轴旋转3d点集到旋转矩阵? - How to rotate set of 3d points using angle axis to rotation matrix?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM