旋转矩阵不精确以将向量与轴对齐
Imprecision with rotation matrix to align a vector to an axis
几个小时以来,我一直在用头撞墙,但我似乎无法弄清楚自己做错了什么。
我正在尝试生成一个旋转矩阵,它将向量与特定轴对齐[=29=](我最终会转换更多数据,因此拥有旋转矩阵很重要).
我觉得我的方法是正确的,如果我在各种向量上测试它,它工作 相当好,但是转换后的向量总是 有点偏.
这是我用来测试该方法的完整代码示例:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d
import matplotlib as mpl
def get_rotation_matrix(i_v, unit=None):
# From http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38
if unit is None:
unit = [1.0, 0.0, 0.0]
# Normalize vector length
i_v = np.divide(i_v, np.sqrt(np.dot(i_v, i_v)))
# Get axis
u, v, w = np.cross(i_v, unit)
# Get angle
phi = np.arccos(np.dot(i_v, unit))
# Precompute trig values
rcos = np.cos(phi)
rsin = np.sin(phi)
# Compute rotation matrix
matrix = np.zeros((3, 3))
matrix[0][0] = rcos + u * u * (1.0 - rcos)
matrix[1][0] = w * rsin + v * u * (1.0 - rcos)
matrix[2][0] = -v * rsin + w * u * (1.0 - rcos)
matrix[0][1] = -w * rsin + u * v * (1.0 - rcos)
matrix[1][1] = rcos + v * v * (1.0 - rcos)
matrix[2][1] = u * rsin + w * v * (1.0 - rcos)
matrix[0][2] = v * rsin + u * w * (1.0 - rcos)
matrix[1][2] = -u * rsin + v * w * (1.0 - rcos)
matrix[2][2] = rcos + w * w * (1.0 - rcos)
return matrix
# Example Vector
origv = np.array([0.47404573, 0.78347482, 0.40180573])
# Compute the rotation matrix
R = get_rotation_matrix(origv)
# Apply the rotation matrix to the vector
newv = np.dot(origv.T, R.T)
# Get the 3D figure
fig = plt.figure()
ax = fig.gca(projection='3d')
# Plot the original and rotated vector
ax.plot(*np.transpose([[0, 0, 0], origv]), label="original vector", color="r")
ax.plot(*np.transpose([[0, 0, 0], newv]), label="rotated vector", color="b")
# Plot some axes for reference
ax.plot([0, 1], [0, 0], [0, 0], color='k')
ax.plot([0, 0], [0, 1], [0, 0], color='k')
ax.plot([0, 0], [0, 0], [0, 1], color='k')
# Show the plot and legend
ax.legend()
plt.show()
我已链接找到方法 here。为什么这产生的转换总是 稍微偏离 ???
您需要规范 uvw
才能正常工作。所以替换
u, v, w = np.cross(i_v, 单位)
有
uvw = np.cross(i_v, unit)
uvw /= np.linalg.norm(uvw)
这与您已有的 i_v = np.divide(i_v, np.sqrt(np.dot(i_v, i_v)))
行基本相同。
不过你可以做得更好,完全避免触发:
def get_rotation_matrix(i_v, unit=None):
# From http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38
if unit is None:
unit = [1.0, 0.0, 0.0]
# Normalize vector length
i_v /= np.linalg.norm(i_v)
# Get axis
uvw = np.cross(i_v, unit)
# compute trig values - no need to go through arccos and back
rcos = np.dot(i_v, unit)
rsin = np.linalg.norm(uvw)
#normalize and unpack axis
if not np.isclose(rsin, 0):
uvw /= rsin
u, v, w = uvw
# Compute rotation matrix - re-expressed to show structure
return (
rcos * np.eye(3) +
rsin * np.array([
[ 0, -w, v],
[ w, 0, -u],
[-v, u, 0]
]) +
(1.0 - rcos) * uvw[:,None] * uvw[None,:]
)
最后一个表达式是来自维基百科页面的方程式:
几个小时以来,我一直在用头撞墙,但我似乎无法弄清楚自己做错了什么。
我正在尝试生成一个旋转矩阵,它将向量与特定轴对齐[=29=](我最终会转换更多数据,因此拥有旋转矩阵很重要).
我觉得我的方法是正确的,如果我在各种向量上测试它,它工作 相当好,但是转换后的向量总是 有点偏.
这是我用来测试该方法的完整代码示例:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d
import matplotlib as mpl
def get_rotation_matrix(i_v, unit=None):
# From http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38
if unit is None:
unit = [1.0, 0.0, 0.0]
# Normalize vector length
i_v = np.divide(i_v, np.sqrt(np.dot(i_v, i_v)))
# Get axis
u, v, w = np.cross(i_v, unit)
# Get angle
phi = np.arccos(np.dot(i_v, unit))
# Precompute trig values
rcos = np.cos(phi)
rsin = np.sin(phi)
# Compute rotation matrix
matrix = np.zeros((3, 3))
matrix[0][0] = rcos + u * u * (1.0 - rcos)
matrix[1][0] = w * rsin + v * u * (1.0 - rcos)
matrix[2][0] = -v * rsin + w * u * (1.0 - rcos)
matrix[0][1] = -w * rsin + u * v * (1.0 - rcos)
matrix[1][1] = rcos + v * v * (1.0 - rcos)
matrix[2][1] = u * rsin + w * v * (1.0 - rcos)
matrix[0][2] = v * rsin + u * w * (1.0 - rcos)
matrix[1][2] = -u * rsin + v * w * (1.0 - rcos)
matrix[2][2] = rcos + w * w * (1.0 - rcos)
return matrix
# Example Vector
origv = np.array([0.47404573, 0.78347482, 0.40180573])
# Compute the rotation matrix
R = get_rotation_matrix(origv)
# Apply the rotation matrix to the vector
newv = np.dot(origv.T, R.T)
# Get the 3D figure
fig = plt.figure()
ax = fig.gca(projection='3d')
# Plot the original and rotated vector
ax.plot(*np.transpose([[0, 0, 0], origv]), label="original vector", color="r")
ax.plot(*np.transpose([[0, 0, 0], newv]), label="rotated vector", color="b")
# Plot some axes for reference
ax.plot([0, 1], [0, 0], [0, 0], color='k')
ax.plot([0, 0], [0, 1], [0, 0], color='k')
ax.plot([0, 0], [0, 0], [0, 1], color='k')
# Show the plot and legend
ax.legend()
plt.show()
我已链接找到方法 here。为什么这产生的转换总是 稍微偏离 ???
您需要规范 uvw
才能正常工作。所以替换
u, v, w = np.cross(i_v, 单位)
有
uvw = np.cross(i_v, unit)
uvw /= np.linalg.norm(uvw)
这与您已有的 i_v = np.divide(i_v, np.sqrt(np.dot(i_v, i_v)))
行基本相同。
不过你可以做得更好,完全避免触发:
def get_rotation_matrix(i_v, unit=None):
# From http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38
if unit is None:
unit = [1.0, 0.0, 0.0]
# Normalize vector length
i_v /= np.linalg.norm(i_v)
# Get axis
uvw = np.cross(i_v, unit)
# compute trig values - no need to go through arccos and back
rcos = np.dot(i_v, unit)
rsin = np.linalg.norm(uvw)
#normalize and unpack axis
if not np.isclose(rsin, 0):
uvw /= rsin
u, v, w = uvw
# Compute rotation matrix - re-expressed to show structure
return (
rcos * np.eye(3) +
rsin * np.array([
[ 0, -w, v],
[ w, 0, -u],
[-v, u, 0]
]) +
(1.0 - rcos) * uvw[:,None] * uvw[None,:]
)
最后一个表达式是来自维基百科页面的方程式: