行列と幾何変換II

今回の授業では、平面上の点の回転と平行移動を検討します。回転や平行移動を行うために、ファイン変換を使用します。

復習:「家」を描く

ヒント:以下の三角の点列と四角の点列を使って、シンプルな「家」を描けます。特に、各部分はplt.fill命令を使って塗りつぶししています。

  • roof_nodes: (-3,2), (3,2), (0,3)
  • wall_nodes: (-2,2), (-2,0), (2,0), (2,2)
In [76]:
#ここでコードを書いてください。
import matplotlib.pyplot as plt
import numpy as np

#家を関数を定義します。
def home():
    roof_nodes = np.array([[-3,2], [3,2],[0,3],[-3,2]])
    roof_nodes = roof_nodes.T
    wall_nodes = np.array([[-2,2],[-2,0], [2,0], [2,2],[-2,2]])
    wall_nodes = wall_nodes.T

    plt.axes().set_aspect('equal')

    #変換前の家
    plt.plot(roof_nodes[0,:], roof_nodes[1,:],'ro-')
    plt.fill(roof_nodes[0,:], roof_nodes[1,:], color="r",alpha=0.4)#ピンク色で積分に対応するエリアを塗りつぶします
    plt.plot(wall_nodes[0,:], wall_nodes[1,:],'ro-')
    plt.fill(wall_nodes[0,:], wall_nodes[1,:], color=(0.2,0.2,0.9),alpha=0.4)# (r,g,b)のタプル(tuple)を利用して、色を指定します。
    plt.grid()
In [51]:
#家の作成関数を呼びだします。
home()

1.1 拡大と縮小 (復習)

対角行列を利用して、図形を拡大または縮小することができます。

$x$方向で$\alpha$倍,$y$方向で$\beta$倍にする変換は以下の行列となります。

$$ \left(\begin{array}{c} x \\ y \end{array}\right) \Longrightarrow \left(\begin{array}{c} x' \\ y' \end{array}\right) = A \left(\begin{array}{c} x \\ y \end{array}\right) \quad A=\left(\begin{array}{cc} \alpha & 0 \\ 0 & \beta \end{array}\right) $$

2.2 回転変換

点$(x,y)$を原点に関して反時周り$\alpha$度で回転するための変換を考えます。

回転後の点を$(x',y')$とする。回転変換は以下の行列を使って表現できます。

$$ \left(\begin{array}{c}x\\y\end{array}\right) \Rightarrow \left(\begin{array}{c}x'\\y'\end{array}\right) = A \left(\begin{array}{c}x\\y\end{array}\right) $$ ここで、$A$は以下の形を持っています。 $$ A=\left(\begin{array}{cc} \cos \alpha & -\sin \alpha \\ \sin \alpha & \cos \alpha \end{array}\right) $$

回転変換の行列を求める

$(x,y)$を極座標で考えます。 $$ (x,y) = ( r \cos(\theta) , r \sin(\theta) ) $$ この点を反時周り$\alpha$度で回転する後、新しい座標$(x',y')$は以下のようになります。 $$ (x',y') = ( r \cos(\theta+\alpha), r \sin (\theta+\alpha) ) $$ 三角関数の計算を行って、以下の結果が分かります。 $$ x'= r \cos(\theta) \cos(\alpha) - r \sin(\theta) \sin(\alpha),\quad y'= r \cos(\theta) \sin(\alpha) + r \sin(\theta) \cos(\alpha) $$ 即ち、 $$ x'= r x\cos(\alpha) - r y\sin(\alpha),\quad y'= r x \sin(\alpha) + r y \cos(\alpha) $$

例1:反時計周り10度で回転する

頂点(0,0), (1,0), (1,1)を持っている三角形を反時計周り10度で回転します。 回転前の三角形をを青色、回転後の三角形を赤色で描きます。

In [77]:
import math
p_list =np.array([[0,0],[1,0],[1,1]]).T

plt.axes().set_aspect('equal')
         
plt.fill( p_list[0,:], p_list[1,:], 'blue',alpha=0.8)

#回転用の行列を作成します。
alpha = 10/180*math.pi
A=np.array([[math.cos(alpha), -math.sin(alpha)],
            [math.sin(alpha), math.cos(alpha)]])

new_p_list = A@p_list #回転行列と点のリストのかけ算
plt.fill( new_p_list[0,:], new_p_list[1,:], 'red',alpha=0.8)

plt.grid()

2.3 平行移動とアフィン変換

グラフを指定される場所に移動する場合、平行移動の変換が使用されます。例えば、グラフを$(x_0,y_0)$に移動するために、以下の変換を行います。

$$ \left(\begin{array}{c}x\\y\end{array}\right) \Rightarrow \left(\begin{array}{c}x'\\y'\end{array}\right) = \left(\begin{array}{c}x'\\y'\end{array}\right) + \left(\begin{array}{c}x_0 \\ y_0 \end{array}\right) $$

線形変換$A$(拡大や縮小,回転など)と平行移動$(x_0, y_0)$を組み合わせた変換はアフィン変換と呼ばれています。 一般的なアフィン変換は以下の形に現れています。

$$ \left(\begin{array}{c}x\\y\end{array}\right) \Rightarrow \left(\begin{array}{c}x'\\y'\end{array}\right) = A \left(\begin{array}{c}x\\y\end{array}\right) + \left(\begin{array}{c}x_0 \\ y_0 \end{array}\right) $$ ここで、$(x_0,y_0)$は平行移動の方向を示しています。

注意: アフィン変換は線形変換ではありません!

例2:平行移動

例1で作成した三角形を(2,1)方向で平行移動します。即ち、x方向で距離2, y方向で距離1で移動します。

In [78]:
import math
plt.axes().set_aspect('equal')

p_list =np.array([[0,0],[1,0],[1,1]]).T

#変換前の三角形を青色で描く。
plt.fill( p_list[0,:], p_list[1,:], 'blue', alpha=0.8)

#回転用の行列を作成します。
alpha = 10/180*math.pi
A=np.array([[math.cos(alpha), -math.sin(alpha)],
            [math.sin(alpha), math.cos(alpha)]])

#平行移動のベクトルを作成します。

b = np.array([[2,1]]).T

#回転+平行移動
new_p_list = A@p_list + b 

#変換後の三角形を赤色で描く。
plt.fill( new_p_list[0,:], new_p_list[1,:], 'red',alpha=0.8)

plt.grid()

例2:家の回転

前回のレポート課題で作成した「家」をそれぞれ反時計周り10度で回転します。その後、方向(6,2)で平行移動します。

ここで、home_transformという関数に、線形変換行列$A$と平行移動ベクトル$b$の引き数を新しく導入しています。

In [74]:
#ここでコードを書いてください。
import matplotlib.pyplot as plt
import numpy as np

#家を関数を定義します。
def home_transform(A,b):
    roof_nodes = np.array([[-3,2], [3,2],[0,3],[-3,2]]).T
    wall_nodes = np.array([[-2,2],[-2,0], [2,0], [2,2],[-2,2]]).T
    
    roof_nodes = A@roof_nodes + b
    wall_nodes = A@wall_nodes + b

    plt.axes().set_aspect('equal')

    #変換後の家
    plt.plot(roof_nodes[0,:], roof_nodes[1,:],'ro-')
    plt.fill(roof_nodes[0,:], roof_nodes[1,:], color="r",alpha=0.4)#ピンク色で積分に対応するエリアを塗りつぶします
    plt.plot(wall_nodes[0,:], wall_nodes[1,:],'ro-')
    plt.fill(wall_nodes[0,:], wall_nodes[1,:], color=(0.2,0.2,0.9),alpha=0.4)# (r,g,b)のタプル(tuple)を利用して、色を指定します。
    plt.grid()
In [79]:
#回転用の行列を作成します。
alpha = 10/180*math.pi
A=np.array([[math.cos(alpha), -math.sin(alpha)],
            [math.sin(alpha), math.cos(alpha)]])

#平行移動のベクトル
b = np.array([[6,2]]).T

#変更前
home()
#変更後
home_transform(A,b)

plt.grid()

演習1

前回のレポート課題で作成した「家」を以下の要求に従って変換してください。

  • 反時計周り10度で回転して、方向(-5,0)で平行移動します。
  • 時計周り10度で回転して、方向(5,1)で平行移動します。

【ヒント】まず、家の描画関数を myhome(A,b) としてください。その後、上記の二つの変換に対して、それぞれの回転行列Aと平行移動行列bを作成します。

In [80]:
#ここでコードを書いてください。
import matplotlib.pyplot as plt
import numpy as np

#家を関数を定義します。
def myhome(A,b):
    pass

演習 2

  • [1] 家を反時計回り15度回転し、$x$方向で$2$、$y$方向で$3$移動して、描いてください。
  • [2] 家を$(2,3)$方向で移動し、反時計回り15度回転して、描いてください。
  • [3] 平行移動と回転の順番が変わると、得られた図は同じでしょうか?

ヒント:回転変換を$A$、平行移動を$(x_0,y_0)=(2, 3)$とすると、

[1]のアフィン変換は

$$ \left(\begin{array}{c}x\\y\end{array}\right) \Rightarrow \left(\begin{array}{c}x'\\y'\end{array}\right) = A \left(\begin{array}{c}x\\y\end{array}\right) + \left(\begin{array}{c}x_0 \\ y_0 \end{array}\right) $$

[2]のアフィン変換は

$$ \left(\begin{array}{c}x\\y\end{array}\right) \Rightarrow \left(\begin{array}{c}x'\\y'\end{array}\right) = A \left( \left(\begin{array}{c}x\\y\end{array}\right) + \left(\begin{array}{c}x_0 \\ y_0 \end{array}\right)

\right)

A \left(\begin{array}{c}x\\y\end{array}\right) + A \left(\begin{array}{c}x_0 \\ y_0 \end{array}\right) $$

In [70]:
# 演習2のコード

2.4 一般的な線形変換

拡大・縮小の変換、回転変換以外に、線形変換を自由に定義することができます。例えば, 直線y=2xに関する反射変換も線形変換です。反射変換に対する行列を求めてみてください。

例3:様々な変換行列 A

以下の行列Aはどうのような変換に対応しているか? 家にかけて確認してください。

$$ A=\left(\begin{array}{cc}0&1\\ 1& 0\end{array}\right),\quad A=\left(\begin{array}{cc}1&0\\ 0& -1\end{array}\right),\quad A=\left(\begin{array}{cc}1&1\\ 0& 1\end{array}\right),\quad A=\left(\begin{array}{cc}1&1\\ 1& 1\end{array}\right) $$

各$A$を試して家を描画するとき、以下のことを考えてください。

  • 変換前後の図形の面積の変化とAの行列式の関係
  • 行列式が0,または負の場合、それに対応する幾何変換の特徴
  • 変換前に平行である線分は変換後にまた平行であるですか?
  • 図形の中の点と点の間の距離は変換前後に変わりますか?
In [ ]:
b = np.array([[0,0]]).T

A=np.array([[0,1],[1,0]])
#A=np.array([[1,0],[0,-1]])
#A=np.array([[1,1],[0,1]])
#A=np.array([[1,1],[1,1]])
home_transform(A,b)

レポート課題

以下のグラフで描かれた「坂の上の家」のように様々な形を持っている家を描いてください。

  • 家を少なくでも二つを描いてください。
  • 家に関する変換などは自由にします。
  • 変形の例:家を(-10,5)に移動して、反時計周り10度で回転し、家の高さを1.5倍にする。