5
1

More than 1 year has passed since last update.

【numpy】2つのベクトルの任意のベクトルからの回転角を算出する方法

Last updated at Posted at 2022-10-24

概要

下図左側のように2つのベクトルの間の角度を算出する方法は内積などを取れば良く、よく知られている。本記事では、2つのベクトルの角度に加え、下図右側のように任意のベクトルを基準とした2つのベクトルの回転角を算出するコードget rotation angle between two vectorsの記事を参考にして紹介する。
Google Colabで作成したコードは、こちらにあります。

図1.png

各種インポート

各種インポート
import numpy as np
import matplotlib.pyplot as plt

2つのベクトルの角度

def vector_to_vector_angle(vector_1, vector_2):
    unit_vector_1 = vector_1 / np.linalg.norm(vector_1)
    unit_vector_2 = vector_2 / np.linalg.norm(vector_2)
    cos = np.dot(unit_vector_1, unit_vector_2)
    rad_angle = np.arccos(cos)
    angle = rad_angle / np.pi * 180
    return angle
  • vector_* / np.linalg.norm(vector_*)で単位ベクトルに変換します。
  • 単位ベクトルに対してnp.dot(unit_vector_1, unit_vector_2)で内積を取り、2つの角度の$\cos(\theta)$を求めます。
  • np.arccos(cos)で、$\theta$を求めます。
  • $\theta$はラジアンなので、rad_angle / np.pi * 180で度に変換します。

任意のベクトルからの回転角

任意のベクトルからの回転角
def vector_to_vector_rotation_angle(vector_1, vector_2):
    unit_vector_1 = vector_1 / np.linalg.norm(vector_1)
    unit_vector_2 = vector_2 / np.linalg.norm(vector_2)
    cos = np.dot(unit_vector_1, unit_vector_2)
    rad_angle = np.arccos(cos)
    angle = rad_angle / np.pi * 180
    cross = np.cross(vector_1, vector_2)
    if cross < 0:
        angle *= -1
    return angle

途中までは、2つのベクトルの角度と同じです。

  • cross = np.cross(vector_1, vector_2)で、2次元のクロス積を求めます。(np.cross(vector_1, vector_2)は、vector_1[0]*vector_2[1]-vector_2[0]*vector_1[1]で定義されていて、$|vector_1||vector_2|\sin(\theta)$となり、$\sin(\theta)$が求まるので回転方向を決めるのに役立ちます。)
  • cross < 0のとき、$\sin(\theta)$が負となり回転角も負となります。

サンプルでの実装結果

サンプルでの実装結果
# サンプル1
vector_1 = np.array([3, 5])
vector_2 = np.array([4, 2])
angle = vector_to_vector_angle(vector_1, vector_2)
rotate_angle = vector_to_vector_rotation_angle(vector_1, vector_2)
print(f'2つのベクトルの角度: {angle:.2f}')
print(f'vector_1を基準とした回転角: {rotate_angle:.2f}')

# 図に表示
fig, ax = plt.subplots()
ax.quiver(*vector_1, angles='xy', scale_units='xy', scale=1, color='r', label='vector_1')
ax.quiver(*vector_2, angles='xy', scale_units='xy', scale=1, color='b', label='vector_2')
ax.set_aspect('equal')
ax.set_xlim(0, 5)
ax.set_ylim(0, 5)
ax.legend()
plt.show()
出力結果
2つのベクトルの角度: 32.47
vector_1を基準とした回転角: -32.47

image.png

注意事項

  • vector_1とvector_2=λvecotr_1(λ>0)の場合、0°が期待されるが正しく計算されない場合がある。
  • vecotr_1とvector_2=-λvecotr_1(λ>0)の場合、180°が期待されるが正しく計算されない場合がある。
  • 0ベクトルがある場合は正しく計算されない。

参考資料

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1