矢量的旋转 (Python)
Rotation of a vector (Python)
我使用以下代码通过两个 2D 旋转在 3D 中旋转矢量:
注意:L 是
np.array([11.231303753070549, 9.27144871768164, 18.085790226916288])
下图中以蓝色显示的预定义矢量。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def angle_between(p1, p2):
ang1 = np.arctan2(*p1[::-1])
ang2 = np.arctan2(*p2[::-1])
return ((ang1 - ang2) % (2 * np.pi))
L = np.vstack([L,np.zeros(3)])
line_xy = [0.,1.]
line_L = [L[0,0],L[0,1]]
a = angle_between(line_xy, line_L)
def rotation(vector,theta):
v1_new = (vector[0]*np.cos(theta)) - (vector[1]*np.sin(theta))
v2_new = (vector[1]*np.cos(theta)) + (vector[0]*np.sin(theta))
z_trans = [v1_new,v2_new,vector[2]]
line_yz= [0.,1.]
theta2 = angle_between(line_yz, [z_trans[1],z_trans[2]])
v1_new = (z_trans[0]*np.cos(theta2)) - (z_trans[1]*np.sin(theta2))
v2_new = (z_trans[1]*np.cos(theta2)) + (z_trans[0]*np.sin(theta2))
y_trans = np.array([z_trans[0],v1_new,v2_new])
return z_trans,y_trans
L2,L3 = rotation(L[0,:],a)
L2 = np.vstack([L2,np.zeros(3)])
L3 = np.vstack([L3,np.zeros(3)])
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#ax.scatter(x1*1000,y1*1000,z1*1000,c ='r',zorder=2)
ax.plot(L[:,0],L[:,1],L[:,2],color='b',zorder=1)
line = np.array([[0,0,0],[0,0,15]])
ax.plot(line[:,0],line[:,1],line[:,2],color = 'g')
ax.set_xlabel('X Kpc')
ax.set_ylabel('Y Kpc')
ax.set_zlabel('Z Kpc')
ax.plot(L2[:,0],L2[:,1],L2[:,2],color='g')
ax.plot(L3[:,0],L3[:,1],L3[:,2],color='y')
我在这里做的是计算 x=0、y=1 之间的角度(即 line_xy 部分),然后使用旋转函数的第一部分将其围绕 z 轴旋转:
v1_new = (vector[0]*np.cos(theta)) - (vector[1]*np.sin(theta))
v2_new = (vector[1]*np.cos(theta)) + (vector[0]*np.sin(theta))
z_trans = [v1_new,v2_new,vector[2]]
然后重复该过程,但这次使用旋转函数的第二部分绕 x 轴旋转:
line_yz= [0.,1.]
theta2 = angle_between(line_yz, [z_trans[1],z_trans[2]])
v1_new = (z_trans[0]*np.cos(theta2)) - (z_trans[1]*np.sin(theta2))
v2_new = (z_trans[1]*np.cos(theta2)) + (z_trans[0]*np.sin(theta2))
y_trans = np.array([z_trans[0],v1_new,v2_new])
旋转是通过标准二维旋转方程完成的:
x' = x cos(theta) - y sin(theta)
y' = y cos(theta) + x sin(theta)
但由于某些原因,第二次旋转后,线(黄色)与绿线(旋转此矢量的原始目标)不在一条直线上。
我已经尝试检查弧度和度数的角度,但它似乎只适用于弧度。
检查角度 theta2 时,结果大约是 35 度,这看起来是合理的。
我不太清楚你的问题,但希望这会有所帮助。
如果您想围绕特定轴旋转 3D 矢量,请利用 matrix transformations 而不是元素方式(就像您上面写的那样)。
下面是围绕任意轴旋转 3-D 矢量的代码:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def unit_vector(vector):
""" Returns the unit vector of the vector."""
return vector / np.linalg.norm(vector)
def angle_between(v1, v2):
"""Finds angle between two vectors"""
v1_u = unit_vector(v1)
v2_u = unit_vector(v2)
return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))
def x_rotation(vector,theta):
"""Rotates 3-D vector around x-axis"""
R = np.array([[1,0,0],[0,np.cos(theta),-np.sin(theta)],[0, np.sin(theta), np.cos(theta)]])
return np.dot(R,vector)
def y_rotation(vector,theta):
"""Rotates 3-D vector around y-axis"""
R = np.array([[np.cos(theta),0,np.sin(theta)],[0,1,0],[-np.sin(theta), 0, np.cos(theta)]])
return np.dot(R,vector)
def z_rotation(vector,theta):
"""Rotates 3-D vector around z-axis"""
R = np.array([[np.cos(theta), -np.sin(theta),0],[np.sin(theta), np.cos(theta),0],[0,0,1]])
return np.dot(R,vector)
将原始蓝色矢量旋转 45 度(pi/2)
L_predef = np.array([11.231303753070549, 9.27144871768164, 18.085790226916288]) #blue vector
new_vect = z_rotation(L_predef, np.pi/2.0)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(np.linspace(0,L_predef[0]),np.linspace(0,L_predef[1]),np.linspace(0,L_predef[2]))
ax.plot(np.linspace(0,new_vect[0]),np.linspace(0,new_vect[1]),np.linspace(0,new_vect[2]))
plt.show()
这个问题有一个通用的解决方案。给定一个向量、一个旋转轴和一个逆时针角度,我写了一个简单的代码,它当然也适用于已经提到的情况。它的作用是:
- 将矢量投影到由旋转轴定义的平面上;
- 在平面中旋转向量的分量;
- 最后重新组合在一起给出最终结果。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib
def rotve(v,erot,angle):
rotmeasure=np.linalg.norm(erot)
erot=erot/rotmeasure;
norme=np.dot(v,erot)
vplane=v-norme*erot
plnorm=np.linalg.norm(vplane)
ep=vplane/plnorm
eo=np.cross(erot,ep)
vrot=(np.cos(angle)*ep+np.sin(angle)*eo)*plnorm+norme*erot
return(vrot)
</pre>
<p>如果需要,您可以检查一个示例,该示例绘制了由旋转产生的 "umbrella":</p>
<pre>axrot=np.array([1,0,1]); v=np.array([1.,1.,1.])
fig3 = plt.figure(3)
ax3d = fig3.add_subplot(111, projection='3d')
ax3d.quiver(0,0,0,axrot[0],axrot[1],axrot[2],length=.5, normalize=True, color='black')
angles=np.linspace(0,2,10)*np.pi
for i in range(len(angles)):
vrot=rotve(v,axrot,angles[i]);
ax3d.quiver(0,0,0,vrot[0],vrot[1],vrot[2],length=.1, normalize=True, color='red')
ax3d.quiver(0,0,0,v[0],v[1],v[2],length=.1, normalize=True, color='blue')
ax3d.set_title('rotations')
fig3.show()
plt.show()
我使用以下代码通过两个 2D 旋转在 3D 中旋转矢量:
注意:L 是
np.array([11.231303753070549, 9.27144871768164, 18.085790226916288])
下图中以蓝色显示的预定义矢量。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def angle_between(p1, p2):
ang1 = np.arctan2(*p1[::-1])
ang2 = np.arctan2(*p2[::-1])
return ((ang1 - ang2) % (2 * np.pi))
L = np.vstack([L,np.zeros(3)])
line_xy = [0.,1.]
line_L = [L[0,0],L[0,1]]
a = angle_between(line_xy, line_L)
def rotation(vector,theta):
v1_new = (vector[0]*np.cos(theta)) - (vector[1]*np.sin(theta))
v2_new = (vector[1]*np.cos(theta)) + (vector[0]*np.sin(theta))
z_trans = [v1_new,v2_new,vector[2]]
line_yz= [0.,1.]
theta2 = angle_between(line_yz, [z_trans[1],z_trans[2]])
v1_new = (z_trans[0]*np.cos(theta2)) - (z_trans[1]*np.sin(theta2))
v2_new = (z_trans[1]*np.cos(theta2)) + (z_trans[0]*np.sin(theta2))
y_trans = np.array([z_trans[0],v1_new,v2_new])
return z_trans,y_trans
L2,L3 = rotation(L[0,:],a)
L2 = np.vstack([L2,np.zeros(3)])
L3 = np.vstack([L3,np.zeros(3)])
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#ax.scatter(x1*1000,y1*1000,z1*1000,c ='r',zorder=2)
ax.plot(L[:,0],L[:,1],L[:,2],color='b',zorder=1)
line = np.array([[0,0,0],[0,0,15]])
ax.plot(line[:,0],line[:,1],line[:,2],color = 'g')
ax.set_xlabel('X Kpc')
ax.set_ylabel('Y Kpc')
ax.set_zlabel('Z Kpc')
ax.plot(L2[:,0],L2[:,1],L2[:,2],color='g')
ax.plot(L3[:,0],L3[:,1],L3[:,2],color='y')
我在这里做的是计算 x=0、y=1 之间的角度(即 line_xy 部分),然后使用旋转函数的第一部分将其围绕 z 轴旋转:
v1_new = (vector[0]*np.cos(theta)) - (vector[1]*np.sin(theta))
v2_new = (vector[1]*np.cos(theta)) + (vector[0]*np.sin(theta))
z_trans = [v1_new,v2_new,vector[2]]
然后重复该过程,但这次使用旋转函数的第二部分绕 x 轴旋转:
line_yz= [0.,1.]
theta2 = angle_between(line_yz, [z_trans[1],z_trans[2]])
v1_new = (z_trans[0]*np.cos(theta2)) - (z_trans[1]*np.sin(theta2))
v2_new = (z_trans[1]*np.cos(theta2)) + (z_trans[0]*np.sin(theta2))
y_trans = np.array([z_trans[0],v1_new,v2_new])
旋转是通过标准二维旋转方程完成的:
x' = x cos(theta) - y sin(theta) y' = y cos(theta) + x sin(theta)
但由于某些原因,第二次旋转后,线(黄色)与绿线(旋转此矢量的原始目标)不在一条直线上。
我已经尝试检查弧度和度数的角度,但它似乎只适用于弧度。
检查角度 theta2 时,结果大约是 35 度,这看起来是合理的。
我不太清楚你的问题,但希望这会有所帮助。
如果您想围绕特定轴旋转 3D 矢量,请利用 matrix transformations 而不是元素方式(就像您上面写的那样)。 下面是围绕任意轴旋转 3-D 矢量的代码:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def unit_vector(vector):
""" Returns the unit vector of the vector."""
return vector / np.linalg.norm(vector)
def angle_between(v1, v2):
"""Finds angle between two vectors"""
v1_u = unit_vector(v1)
v2_u = unit_vector(v2)
return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))
def x_rotation(vector,theta):
"""Rotates 3-D vector around x-axis"""
R = np.array([[1,0,0],[0,np.cos(theta),-np.sin(theta)],[0, np.sin(theta), np.cos(theta)]])
return np.dot(R,vector)
def y_rotation(vector,theta):
"""Rotates 3-D vector around y-axis"""
R = np.array([[np.cos(theta),0,np.sin(theta)],[0,1,0],[-np.sin(theta), 0, np.cos(theta)]])
return np.dot(R,vector)
def z_rotation(vector,theta):
"""Rotates 3-D vector around z-axis"""
R = np.array([[np.cos(theta), -np.sin(theta),0],[np.sin(theta), np.cos(theta),0],[0,0,1]])
return np.dot(R,vector)
将原始蓝色矢量旋转 45 度(pi/2)
L_predef = np.array([11.231303753070549, 9.27144871768164, 18.085790226916288]) #blue vector
new_vect = z_rotation(L_predef, np.pi/2.0)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(np.linspace(0,L_predef[0]),np.linspace(0,L_predef[1]),np.linspace(0,L_predef[2]))
ax.plot(np.linspace(0,new_vect[0]),np.linspace(0,new_vect[1]),np.linspace(0,new_vect[2]))
plt.show()
这个问题有一个通用的解决方案。给定一个向量、一个旋转轴和一个逆时针角度,我写了一个简单的代码,它当然也适用于已经提到的情况。它的作用是:
- 将矢量投影到由旋转轴定义的平面上;
- 在平面中旋转向量的分量;
- 最后重新组合在一起给出最终结果。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib
def rotve(v,erot,angle):
rotmeasure=np.linalg.norm(erot)
erot=erot/rotmeasure;
norme=np.dot(v,erot)
vplane=v-norme*erot
plnorm=np.linalg.norm(vplane)
ep=vplane/plnorm
eo=np.cross(erot,ep)
vrot=(np.cos(angle)*ep+np.sin(angle)*eo)*plnorm+norme*erot
return(vrot)
</pre>
<p>如果需要,您可以检查一个示例,该示例绘制了由旋转产生的 "umbrella":</p>
<pre>axrot=np.array([1,0,1]); v=np.array([1.,1.,1.])
fig3 = plt.figure(3)
ax3d = fig3.add_subplot(111, projection='3d')
ax3d.quiver(0,0,0,axrot[0],axrot[1],axrot[2],length=.5, normalize=True, color='black')
angles=np.linspace(0,2,10)*np.pi
for i in range(len(angles)):
vrot=rotve(v,axrot,angles[i]);
ax3d.quiver(0,0,0,vrot[0],vrot[1],vrot[2],length=.1, normalize=True, color='red')
ax3d.quiver(0,0,0,v[0],v[1],v[2],length=.1, normalize=True, color='blue')
ax3d.set_title('rotations')
fig3.show()
plt.show()