Python
numpy
Matrix
norm
rot_mat

Pythonによる回転行列と法線ベクトルの実装

More than 1 year has passed since last update.

0. Pythonによる回転行列と法線ベクトルの実装

色々と図形をぐるぐるまわしたいと思ったので実装した。
図形を回転させたら軌跡は円になるので、回転行列で計算可能なのである。

1. 回転行列

python 3.6を用いた。回転行列の数式は以下を参考にした。
http://1st.geocities.jp/shift486909/program/spin.html

2次元

{\begin{equation}
\begin{vmatrix}
X' \\
Y' \\
\end{vmatrix}
=
\begin{vmatrix}
\cos\theta &-\sin\theta \\
\sin\theta &\cos\theta \\
\end{vmatrix}
\times
\begin{vmatrix}
X \\
Y \\
\end{vmatrix}
\end{equation}
}

3次元 (Z軸周り= x -> y)

{\begin{equation}
\begin{vmatrix}
X' \\
Y' \\
Z' \\
\end{vmatrix}
=
\begin{vmatrix}
\cos\theta z &-\sin\theta z &0 \\
\sin\theta z &\cos\theta z &0 \\
0 &0 &1 \\
\end{vmatrix}
\times
\begin{vmatrix}
X \\
Y \\
Z \\
\end{vmatrix}
\end{equation}
}

今回は2次元で実装

# -*- coding: utf-8 -*-
import numpy as np


if __name__ == '__main__':

    # matrix
    a = np.matrix([2.5, 2.5]).A1
    b = np.matrix([5, 5]).A1
    print("a=" + str(a))
    print("b=" + str(b))
    # AB = AC = r
    pythagoras = b - a
    r = np.sqrt( (pythagoras[0] * pythagoras[0]) + (pythagoras[1] * pythagoras[1] ))
    print("r=" + str(r))

    # tan theta (Inclination)
    tant = (b[1] - a[1]) / (b[0] - a[0])
    # theta
    tan = np.arctan(tant)
    # AD = r*cos α
    # BD = r*sin α
    AD = r * np.cos(tan)
    BD = r * np.sin(tan)
    print("AD=" + str(AD))
    print("BD=" + str(BD))

    theta = np.deg2rad(90)

    rotateMat = np.matrix([
        [np.cos(theta), -np.sin(theta)],
        [np.sin(theta), np.cos(theta)],
    ])

    print(rotateMat)

    xy = np.matrix([[AD], [BD]])

    cxy = (rotateMat * xy)
    cxy = cxy.A1 + a
    print("cxy=" + str(cxy) )

    print("------------------")
    # cx = AD*cos θ-BD*sin θ+ax
    # cy = AD*sin θ+BD*cos θ+ay
    AD2 = b[0] - a[0]
    BD2 = b[1] - a[1]
    cx = ((AD2 * np.cos(theta)) - (BD2 * np.sin(theta))) + a[0]
    print(cx)
    cy = ((AD2 * np.sin(theta)) + (BD2 * np.cos(theta))) + a[1]
    print(cy)

1.1. 回転行列 - 関数化

関数化

def calcRot(_posxy, _orgxy, _rad):
    ADBD = _posxy - _orgxy
    ADBD = np.matrix([[ADBD[0]], [ADBD[1]]])
    rotateMat = np.matrix([
        [np.cos(_rad), -np.sin(_rad)],
        [np.sin(_rad), np.cos(_rad)],
    ])
    cxy = (rotateMat * ADBD).A1 + _orgxy

    return  cxy

こんな感じに使えばおk

 _posxy = np.matrix([_x, _y]).A1
 _orgxy = np.matrix([_x, _y]).A1
 _rad = np.deg2rad(90)

 rotatedPos = calcRot(_posxy, _orgxy, _rad)

1.2. 回転行列 - 複素数

コメントで教えて貰いましたが、回転行列は複素数でも表現できるらしい。

イメージ的にはこんな感じ。
https://atarimae.biz/wp-content/uploads/2015/05/fourway.png

確かに。

# -*- coding: utf-8 -*-
import numpy as np

if __name__ == '__main__':

    A = 2.5 + 2.5j
    B = 5.0 + 5.0j
    print('A=' + str(A))
    print('B=' + str(B))

    theta = np.deg2rad(90)
    rotate = np.cos(theta) + 1j * np.sin(theta) # = np.exp(1j * theta)

    AB = B - A
    AC = rotate * AB
    C  = AC + A
    print('C=' + str(C))

2. 法線ベクトル

法線ベクトルは対象とする直線に直交していればよいので、回転行列を用いて90度回転させるだけでよいのである。
もちろん他にもやり方は沢山ある。私は同じ関数(回転行列)を使いまわせるのでこれを使っている。

def calcNorm_vec(_posxy, _orgxy):
    ADBD = _posxy - _orgxy
    ADBD = np.matrix([[ADBD[0]], [ADBD[1]]])
    theta = np.deg2rad(90)
    rotateMat = np.matrix([
        [np.cos(theta), -np.sin(theta)],
        [np.sin(theta), np.cos(theta)],
    ])
    cxy = (rotateMat * ADBD)
    vv = cxy.A1
    nv = vv / np.linalg.norm(vv)
    return nv

以上。