3D a、b、c に 3 つのベクトルがあります。ここで、a に適用すると b に平行な結果が得られる回転 r を計算したいと思います。次に、回転 r を c に適用する必要があります。
Pythonでこれを行うにはどうすればよいですか? numpy/scipy でこれを行うことは可能ですか?
numpy の使用:
import numpy as np
from numpy import linalg as LA
from math import pi,cos,sin,acos
def rotate(v,angle=0,ref=np.array([0,0,1]),deg=False):
'''Rotates a vector a given angle respect the
given reference. Option: deg=False (default)'''
if(abs(angle) < 1e-5):
return v
if(deg):
angle = angle*pi/180
# Define rotation reference system
ref = versor(ref) # rotation axis
# n1 & n2 are perpendicular to ref, and to themselves
n1 = versor(np.cross(ref,np.array([-ref[1],ref[2],ref[0]])))
n2 = np.cross(ref,n1)
vp = np.inner(v,ref)*ref # parallel to ref vector
vn = v-vp # perpendicular to ref vector
vn_abs = LA.norm(vn)
if(vn_abs < 1e-5):
return v
alp = acos(np.inner(vn,n1)/vn_abs) # angle between vn & n1
if(triprod(ref,n1,vn) < 0):
alp = -alp # correct if necesary
return vp+vn_abs*(n1*cos(alp+angle)+n2*sin(alp+angle))
def triprod(a,b,c):
'''Triple product of vectors: a·(b x c)'''
return np.inner(a,np.cross(b,c))
def versor(v):
'''Unitary vector in the direction of the one given as input'''
v = np.array(v)
return v/LA.norm(v)
###### Test ################################################
a = np.array([3,4,1])
b = np.array([0,-1,2])
c = np.array([1,1,5])
r = acos(np.inner(a,b)/(LA.norm(a)*LA.norm(b)))
ref = versor(np.cross(a,b))
print rotate(c,angle=r,ref=ref)
print r
print ref
質問へのコメントですでに「Python用のジオメトリライブラリ」が回答されていると仮定します。したがって、「a」を「b」に平行にする変換ができたら、それを「c」に適用するだけです。
ベクトル「a」と「b」は平面を一意に定義します。各ベクトルには、原点との点の差として標準表現があるため、「a」の頭、「b」の頭、および原点の3つの点があります。まず、この平面を計算します。Ax + By + Cz=0の形式の方程式があります。
この平面の法線ベクトルは、回転軸と回転方向の符号規則の両方を定義します。必要なのは、すべて同一線上にあるため、平面に対する1つの法線ベクトルだけです。このようなベクトルを解くには、平面内の2つの非共線ベクトルを選択し、法線ベクトルとの内積を取ります。これにより、クラメルの公式などの標準的な方法で解くことができる2つの変数の線形方程式のペアが得られます。これらすべての操作で、A、B、またはCのいずれかがゼロの場合、処理する特別なケースがあります。
回転角は、「a」と「b」の内積とそれらの長さの余弦定理によって与えられます。角度の符号は、「a」、「b」の三重積と法線ベクトルによって決定されます。これで、検索できる多くの標準形の1つで回転行列を作成するためのすべてのデータが得られました。