Python (線形変換)

線形変換

行列を使って、オブジェクトの回転を行うスクリプトです。

  1. 以下のスクリプトを、rotate.py というファイル名で保存します。
    #!env python
    import sys
    import math
    
    def torad(d):
        return d/180.0*math.pi
    
    def mulmatrix(m, v):
        vv = [0, 0, 0]
        for i in range(3):
            vv[i] = m[i][0]*v[0] + m[i][1]*v[1] + m[i][2]*v[2]
        return vv
    
    
    def rotateX(v, d):
        r = torad(d)
        s = math.sin(r)
        c = math.cos(r)
        m = [[1, 0, 0],
             [0, c, -s],
             [0, s, c]]
        return mulmatrix(m, v)
    
    
    def rotateY(v, d):
        r = torad(d)
        s = math.sin(r)
        c = math.cos(r)
        m = [[c, 0, s],
             [0, 1, 0],
             [-s, 0, c]]
        return mulmatrix(m, v)
    
    
    def rotateZ(v, d):
        r = torad(d)
        s = math.sin(r)
        c = math.cos(r)
        m = [[c, -s, 0],
             [s, c, 0],
             [0, 0, 1]]
        return mulmatrix(m, v)
    
    
    rx = float(sys.argv[1])
    ry = float(sys.argv[2])
    rz = float(sys.argv[3])
    infp = open(sys.argv[4], 'r')
    outfp = open(sys.argv[5], 'w')
    for line in infp.readlines():
        s = line.split()
        if len(s) < 1:
            continue
        if s[0] == 'v':
            v = [float(s[1]), float(s[2]), float(s[3])]
            v = rotateX(v, rx)
            v = rotateY(v, ry)
            v = rotateZ(v, rz)
            outfp.write('v ' + str(v[0]) + ' ' + str(v[1]) + ' ' + str(v[2]) + '\n')
        else:
            outfp.write(line)
    infp.close()
    outfp.close()
    
  2. 以下のように実行します。
    # python rotate.py 30 60 45 cube1.obj cube3.obj
    cube1.obj (回転前)

    cube3.obj (回転後)

    cube1.obj のObjデータ

スクリプト解説

import sys
コマンド引数を使用するためにsysモジュールをインポートします。
import math
三角関数を使用するためにsysモジュールをインポートします。
def torad(d):
角度の単位を、度からラジアンに変換する関数です。
return d/180.0*math.pi
ラジアンに変換した数値を返します。
def mulmatrix(m, v):
3X3の行列と、3次ベクトルとの積を計算する関数です。
vv = [0, 0, 0]
関数から返すベクトルを初期化します。
for i in range(3):
  vv[i] = m[i][0]*v[0] + m[i][1]*v[1] + m[i][2]*v[2]
行列とベクトルの積の計算です。
def rotateX(v, d):
ベクトルvをX軸中心にd度だけ回転させる関数です。
r = torad(d)
度をラジアンに変換しておきます。
s = math.sin(r)
c = math.cos(r)
三角関数をあらかじめ計算しておきます。
m = [[1, 0, 0],
[0, c, -s],
[0, s, c]]
X軸中心に回転させる行列を作成します。
return mulmatrix(m, v)
行列とベクトルの積を計算します。 
rx = float(sys.argv[1])
ry = float(sys.argv[2])
rz = float(sys.argv[3])
引数を実数値に変換しておきます。
infp = open(sys.argv[4], 'r')
outfp = open(sys.argv[5], 'w')
入出力ファイルをオープンします。
for line in infp.readlines():
入力ファイルから読み込んだデータを、1行ずつ変数lineに代入してループを実行します。
s = line.split()
1行分のデータを空白で分割し、リストにします。
if len(s) < 1:
  continue
空行データは読み飛ばします。
if s[0] == 'v':
リストの先頭が'v'であれば、頂点座標データです。
v = [float(s[1]), float(s[2]), float(s[3])]
頂点座標データを実数値に変換し、ベクトルを表すリストにします。
v = rotateX(v, rx)
v = rotateY(v, ry)
v = rotateZ(v, rz)
X軸、Y軸、Z軸中心の順に回転します。
outfp.write('v ' + str(v[0]) + ' ' + str(v[1]) + ' ' + str(v[2]) + '\n')
出力ファイルに結果の頂点座標データを出力します。
else:
  outfp.write(line)
頂点座標データ以外は、そのまま出力ファイルに出力します。

練習問題

  1. Objファイルを読み込んで、オブジェクトを移動、回転、スケールすることのできるlenear.pyを作成してみましょう。
    入出力ファイル名はコマンドラインで指定し、1番目の引数が-tで移動、-rで回転、-sでスケールを行います。
    cube1.objを(1, 2, 3)だけ現在の座標から移動します。
    # python lenear.py -t 1 2 3 cube1.obj cube4.obj

    cube1.objの原点中心にX軸中心に30度、 Y軸中心に60度、Z軸中心に45度回転されたデータがcube3.objに出力されます。

    # python lenear.py -r 30 60 45 cube1.obj cube3.obj
    cube1.objを原点中心にX方向に2倍、Y軸方向に3倍、Z軸方向に4倍します。
    # python lenear.py -s 2 3 4 cube1.obj cube5.obj

参考


Prev | Next
index | home
abetmhr@gmail.com