【Pythonで学ぶ線形代数学講座(17)】回転行列
回転行列
回転行列(rotation matrix)は任意のベクトルに作用したとき、ベクトルの始点を軸に回転させます。
\[R(\theta)=\begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\cos\theta\end{bmatrix}\tag{1}\]
$\theta$ は回転角度で、正の値のときは反時計回り、負の値とのきは時計回りに回転します。たとえば、行列 $R(\theta)$ を単位ベクトル $\boldsymbol{u}=\begin{bmatrix}1\\0\end{bmatrix}$ に乗じると、
\[R(\theta)\boldsymbol{u}=\begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\cos\theta\end{bmatrix}\begin{bmatrix}1\\0\end{bmatrix}=\begin{bmatrix}\cos\theta\\\sin\theta\end{bmatrix}\tag{2}\]
となります。$\boldsymbol{u}$ が位置ベクトルであれば、$R(\theta)\boldsymbol{u}$ は原点を軸とする回転を表します。Python で単位ベクトル $\boldsymbol{u}=\begin{bmatrix}1\\0\end{bmatrix}$ に回転行列
\[R(\pi/4)=\begin{bmatrix}\cos\cfrac{\pi}{4}&-\sin\cfrac{\pi}{4}\\
\sin\cfrac{\pi}{4}&\cos\cfrac{\pi}{4}\end{bmatrix}\tag{3}\]
を作用させて、ベクトルを角度 $\pi/4$ だけ回転させてみましょう。予め コードライブラリ にある coordinate() と visual_vector() を実装しておいてください。
# python_rotation_matrix # In[1] import numpy as np import matplotlib.pyplot as plt # ここにcoordinate()を実装 # ここにvisual_vector()を実装 # ベクトル回転関数 # deg=Falseならばラジアンで角度を指定 # deg=Trueならば度数単位で角度を指定 def rotation_o(u, t, deg=False): # 度数単位の角度をラジアンに変換 if deg == True: t = np.deg2rad(t) # 回転行列 R = np.array([[np.cos(t), -np.sin(t)], [np.sin(t), np.cos(t)]]) return np.dot(R, u) # 単位ベクトル u = (1, 0) # uを45°回転させる Ru = rotation_o(u, np.pi/4) # 描画領域を作成 fig, ax = plt.subplots(1, 1, figsize=(5, 5)) coordinate(ax, [-1.5, 1.5], [-1.5, 1.5]) # uをプロット visual_vector(ax, (0, 0), u, color="blue") ax.text(u[0], u[1]+0.05, "u", color="blue", size=16) # Ruをプロット visual_vector(ax, (0, 0), Ru, color="red") ax.text(Ru[0], Ru[1], "Ru", color="red", size=16)
$\boldsymbol{u}$ に $R(\pi/6)$ を繰り返し作用させて、$R(\pi/6)\boldsymbol{u}$ の終点は半径 $1$ の円周上にあることを確認してみましょう。
# In[2] fig, ax = plt.subplots(1, 1, figsize=(5, 5)) coordinate(ax, [-1.5, 1.5], [-1.5, 1.5]) # ベクトルの初期値 Ru = (1, 0) # 単位ベクトルに繰り返し回転行列を作用させる for i in range(12): Ru = rotation_o(Ru, np.pi/6) visual_vector(ax, (0, 0), Ru, color="red")
したがって、$R(\theta)$ は平面座標上の任意の点 $(x,\ y)$ を角度 $t$ だけ回転させる行列であるともいえます。また、複数の位置ベクトル
\[\boldsymbol{r}_1=\begin{bmatrix}x_1\\y_1\end{bmatrix},\ \boldsymbol{r}_2=\begin{bmatrix}x_2\\y_2\end{bmatrix},\ \cdots,\ \boldsymbol{r}_k=\begin{bmatrix}x_k\\y_k\end{bmatrix}\tag{4}\]
を行列
\[X=\begin{bmatrix}x_1 & x_2 & \cdots & x_k\\y_1 & y_2 & \cdots & y_k\end{bmatrix}\tag{5}\]
の形にまとめて回転行列を作用させると、すべての点を一斉に回転させることができます。以下のコードは放物線 $P_0(x)=x^2$ 全体を反時計回りに $90^\circ$ 回転させます。
# In[3] # FigureとAxesを作成 fig, ax = plt.subplots(1, 1, figsize=(5, 5)) # 座標を設定 coordinate(ax, [-2, 2], [-2, 2]) # 放物線のデータを作成 x = np.linspace(-2, 2, 33) y = x ** 2 # xとyを縦軸方向に連結して行列を作成 p0 = np.vstack((x, y)) # 放物線p0を左に90°回転 p1 = rotation_o(p0, np.pi/2) # p0とp1をAxesにプロット ax.plot(p0[0], p0[1], label="P0", color="blue") ax.plot(p1[0], p1[1], label="P1", color="darkorange") # 凡例を表示 ax.legend(loc = "lower right") plt.show()
次は $xy$ 平面上点 $\mathrm{Q}(x,\ y)$ を点 $\mathrm{P}(a,\ b)$ の周りに回転させることを考えます (下図)。
図にあるように、ベクトル $\vec{PQ}$ は
\[\vec{PQ}=\begin{bmatrix}x-a\\y-b\end{bmatrix}\tag{6}\]
で表されます。$\vec{PQ}$ が $R(t)$ によって $\vec{PQ’}$ に移ったとすると、線形写像の式は
\[\begin{bmatrix}x’-a\\y’-b\end{bmatrix}=\begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\cos\theta\end{bmatrix}\begin{bmatrix}x-a\\y-b\end{bmatrix}\tag{7}\]
と表せます。したがって、$\mathrm{Q’}(x’,\ y’)$ は
\[\begin{bmatrix}x’\\y’\end{bmatrix}=\begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\cos\theta\end{bmatrix}\begin{bmatrix}x-a\\y-b\end{bmatrix}+\begin{bmatrix}a\\b\end{bmatrix}\tag{8}\]
と表されます。任意の軸周りの回転操作を Python で実装してみましょう。
# In[4] # 平面上の任意の点の回転関数 # qに軸の座標を指定 # pに回転させたい点の座標を指定 # tに回転角を指定 def rotation(xy, r_axis, t, deg=False): # 度数単位の角度をラジアンに変換 if deg == True: t = np.deg2rad(t) xy = np.array(xy) r_axis = np.array(r_axis) # 回転行列 R = np.array([[np.cos(t), -np.sin(t)], [np.sin(t), np.cos(t)]]) return np.dot(R, xy - r_axis) + r_axis
rotation 関数を使って、平面上の点 $(3,\ 3)$ を点 $(2,\ 1)$ の周りに角度 $\pi/6$ ずつ回転させてみます。
# In[5] fig, ax = plt.subplots(1, 1, figsize=(5, 5)) coordinate(ax, [-3, 5], [-3, 5]) # 座標点 q = (3, 3) # 回転軸の座標 p = (2, 1) # 点qに繰り返し回転行列を作用させる for i in range(12): q = rotation(q, p, np.pi/6) ax.scatter(q[0], q[1], color="red")
rotation() の xy に回転対象となる複数の座標点を二次元配列の形でまとめて渡して、グラフや図形を回転させることができます。放物線 $P_0(x)=x^2$ を点 $(2,\ 2)$ の周りに $\pi/4$ 回転させてみます。
# In[6] # グラフ描画領域を作成 fig, ax = plt.subplots(1, 1, figsize=(5, 5)) coordinate(ax, [-3, 5], [-3, 5]) # 放物線のデータを作成 x = np.linspace(-4, 4, 65) y = x**2 # xとyを縦軸方向に連結して行列を作成 p0 = np.vstack((x, y)) # 回転軸の座標 r_axis = np.array([[2], [2]]) # 放物線p0を左に45°回転 p1 = rotation(f0, r_axis, np.pi/4) # p0とp1をAxesにプロット ax.plot(p0[0], p0[1], label="P0", color="blue") ax.plot(p1[0], p1[1], label="P1", color="darkorange") # 凡例を表示 ax.legend(loc = "lower right") plt.show()
コメント