python - Python:使用 scipy.spatial.transform.Rotation 旋转平面(点集)以匹配新的法线向量
问题描述
所以我目前正在尝试在与样条正交的平面上进行切片。方向并不重要,因为我使用点来插入 3D 扫描
我主要不确定 rotmat 方法(这是我的类的精简版本,技术上是 NURBS-Python 表面派生类),其中我从平面 x/y 平面旋转平面网格(所有 z=0 ) 以匹配新的法线向量(样条的切线,存储在 der 变量中)。
任何人都知道如何旋转一组点以从一个法向量到另一个?围绕新向量的轴的角度对我来说并不重要。
(对不起 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])
解决方案
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 x-y plane (assuming you're using x-y 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. Seems to work ok.
推荐阅读
- android - Android Studio App Inspection 有时不显示数据库
- html - “这个网站似乎使用了滚动链接的定位效果。” 项目中没有 CSS
- wpf - 如何告诉网格在需要时缩小哪一列
- api - 放心是给502的回报
- r - 制作具有多个分类变量的堆叠或多面条形图
- python - 与从预训练模型加载 state_dict 相关的错误
- git - 从 main(从 dev)恢复的两个提交,然后在再次将 dev 合并到 main 之后,这些恢复的更改不在 main
- asp.net-core - 尝试使用 RSA-OAEP-256 和 A256GCM 解密 JWE 有效负载时,填充模式无效
- c# - 将 JSON 对象加载到数组中?
- amazon-web-services - moto3 mock_s3文件上传,找不到文件