Pythonスクリプトでのベクトル/行列計算

Pythonスクリプトでベクトルや行列を計算する数値演算機能は、Shade3Dの機能としては用意されていません。
ベクトルや行列計算については、Pythonの「numpy」を使用するのが実装しやすいです。
Shade3Dのスクリプトからは、コードの先頭で以下を書くことで使用できます。

import numpy

以下、汎用的なnumpyの使い方をいくつか記載します。

ベクトル操作

numpyを使ったベクトルの操作は以下のようになります。

ベクトルの作成

import numpy

val = numpy.array([0.0, 0.0, 0.0])

print val[0]   # Xの要素を取得.
val[0] = 2.1   # Xの要素を変更.

(0.0, 0.0, 0.0)のXYZ要素を持つベクトルを生成します。
numpyで使用できるベクトル情報は「numpy.array」を使用して生成する必要があります。
ベクトルの各要素には、「val[0]」「val[1]」「val[2]」として読み込み、書き込みできます。

ベクトルと単一の数値での計算

import numpy

val = numpy.array([1.0, 2.0, 3.0])

val1 = val * 2.0
val2 = val / 2.0
print val1
print val2

ベクトルに対して1つの実数値与えて計算すると、
ベクトル内の各要素に計算が反映されます。

結果は以下のようになります。

[ 2.  4.  6.]
[ 0.5  1.   1.5]

numpyのデータ型

numpyは内部的にC言語で計算されるため、このベクトルは作成時に型が決定されます。
numpy.array指定時の型は「dtype」で取得できます。
以下の場合は、numpy.arrayに整数で格納しています。dtypeは”int32″の整数型です。

import numpy

val = numpy.array([1, 2, 3])
print "dtype = " + str(val.dtype)

以下の場合は、numpy.arrayに浮動小数点で格納しています。dtypeは”float64″の浮動小数点型です。

import numpy

val = numpy.array([1.0, 2.0, 3.0])
print "dtype = " + str(val.dtype)

以下のスクリプトを実行した場合はnumpy.arrayはint型になり、(1/4, 2/4, 3/4)の計算になります。
結果として「val = [0 0 0]」と整数値になります。

import numpy

val = numpy.array([1, 2, 3])
val[0] /= 4.0
val[1] /= 4.0
val[2] /= 4.0
print "val = " + str(val)

これを回避するために、numpy.arrayで小数点値を入れるか、第二引数に「dtype = ‘float64’」のように型を明示指定するのが有効です。

import numpy

# 以下、int32型.
val = numpy.array([1, 2, 3])

# 以下、float64型.
val = numpy.array([1.0, 2.0, 3.0])

# 以下、float64型.
val = numpy.array([1, 2, 3], dtype = 'float64')

ベクトル同士の計算

import numpy

val1 = numpy.array([1.0, 2.0, 3.0])
val2 = numpy.array([0.5, 0.4, 0.1])

print (val1 + val2)
print (val1 - val2)
print (val1 * val2)
print (val1 / val2)

2つのベクトルを加減剰余算します。
この場合、3つの要素をそれぞれ計算して格納します。
結果は以下のようになります。

[ 1.5  2.4  3.1]
[ 0.5  1.6  2.9]
[ 0.5  0.8  0.3]
[  2.   5.  30.]

ベクトルの長さを計算

import numpy

# ベクトルの指定.
val = numpy.array([1.0, 2.0, 3.0])

# ベクトルの長さを計算.
lenV = numpy.linalg.norm(val)

print lenV

「numpy.linalg.norm」でベクトルの長さを計算します。
結果は「3.74165738677」と返されます。

単位ベクトルを計算

単位ベクトルは、元のベクトルをベクトルの長さで割ることで求めます。

import numpy

# ベクトルの指定.
val = numpy.array([1.0, 2.0, 3.0])

# ベクトルの長さを計算.
lenV = numpy.linalg.norm(val)
if lenV != 0.0:
  val /= lenV
print val

結果は「[ 0.26726124 0.53452248 0.80178373]」が返されます。

2ベクトルの内積を計算

import numpy

# ベクトルの指定.
val1 = numpy.array([1.0, 2.0, 3.0])
val2 = numpy.array([0.5, 1.2, -2.0])

# 内積計算.
v = numpy.dot(val1, val2)
print v

「numpy.dot」で2つのベクトルの内積を計算します。
結果は「-3.1」が返ります。

2ベクトルの外積を計算

import numpy

# ベクトルの指定.
val1 = numpy.array([1.0, 2.0, 3.0])
val2 = numpy.array([0.5, 1.2, -2.0])

# 外積計算.
val3 = numpy.cross(val1, val2)
print val3

「numpy.cross」で2つのベクトルの外積を計算します。
結果は「[-7.6 3.5 0.2]」が返ります。

numpyのベクトルをShade3Dに渡す

numpy用にnumpy.array()を使用して計算したベクトルは、
そのままではShade3Dのスクリプトでは使用できません。

val = numpy.array([1.0, 2.0, 3.0])
print val

としたときは、「[ 1. 2. 3.]」のようになっています。

Shade3Dで使用するには、


val = [val[0], val[1], val[2]]

のように変換します。これで「[1.0, 2.0, 3.0]」のようになります。

行列操作

Shade3Dの場合は、内部的な計算で4×4行列がよく使用されます。

行列の作成

import numpy
m = numpy.matrix(numpy.identity(4))
print m

「numpy.matrix(numpy.identity(4))」とすることで4×4行列を作成します。
「print m」での結果は、以下のように単位行列が返されます。

[[ 1.  0.  0.  0.]
 [ 0.  1.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0.  1.]]

単一要素は「m[0,0]」のようにアクセスします。

Shade3Dからの行列をnumpyの行列に渡す

Shade3Dでの行列は、4×4個分の二次元配列を格納しています。
numpyの行列とは構成が違うため、そのままでは使用できません。
これをnumpyに渡すには以下のようにします。

import numpy

# 選択形状の変換行列を取得.
shape = xshade.scene().active_shape()
shade_matrix = shape.transformation

m = numpy.matrix(shade_matrix)

ここで返された「m」を使うことで、numpyとして行列計算できるようになります。

numpyの行列をShade3Dに渡す

numpyの行列をShade3Dの形状の行列要素として渡す場合、
4×4個分の二次元配列に変換する必要があります。

import numpy

# Shade3Dでの選択形状の変換行列を取得し、numpyの行列として渡す.
shape = xshade.scene().active_shape()
shade_matrix = shape.transformation
m = numpy.matrix(shade_matrix)

# 移動要素として (100, 200, 0)の位置を指定.
m[3] = [100.0, 200.0, 0.0, 1.0]

# 二次元配列の作成.
m2 = [[0 for j in range(4)] for i in range(4)]
for i in range(4):
  for j in range(4):
    m2[i][j] = m[i,j]

# Shade3Dに変換行列を渡す.
shape.reset_transformation()  # 行列をリセット.
shape.transform(m2) # 行列をかける.

この例では、選択形状の変換行列を取得してnumpyが計算できる行列を作成し、
位置を (100, 200, 0)に変更。
Shade3Dで使用する4×4行列の二次元配列を作成して値を代入してから、
Shade3Dに変換行列を格納しています。

行列同士の乗算

以下は、Shade3Dでの選択形状の変換行列に対して、
(50, 100, -20)の平行移動させた行列を計算しています。

import numpy

# Shade3Dでの選択形状の変換行列を取得.
shape = xshade.scene().active_shape()
shade_matrix = shape.transformation
m1 = numpy.matrix(shade_matrix)

# (50, 100, -20)の平行移動の変換行列.
m2 = numpy.matrix(numpy.identity(4))
m2[3] = [50.0, 100.0, -20.0, 1.0]

# 行列同士の乗算.
m = m1 * m2

# 行列同士の乗算.
m2 = numpy.dot(m1, m2)

行列同士の乗算は「*」を使用する、「numpy.dot」を使用する、
のどちらでも同じ値が返されます。

行列とベクトルの乗算

import numpy

# (1, 2, 3)のベクトル.
vec = numpy.array([1.0, 2.0, 3.0])

# 4x4行列(以下は単位行列).
m = numpy.matrix(numpy.identity(4))

# 乗算するベクトルが4要素となるようにする.
vec4 = numpy.array(vec)
if vec.size == 3:
  vec4 = numpy.array([vec[0], vec[1], vec[2], 1.0])

# ベクトルと行列の乗算.
retM = numpy.dot(vec4, m)
print retM

4つの要素を持つベクトルと4×4行列を乗算するには「numpy.dot」を使用します。
ベクトルの要素が4ではない場合は、サイズが4になるように合わせておきます。
結果は「[[ 1. 2. 3. 1.]]」となります。

結果は2次元配列であるため、Shade3Dにベクトルして渡す場合は以下のように変換します。

# ベクトルと行列の乗算.
retM = numpy.dot(vec4, m)
retM = [retM[0,0], retM[0,1], retM[0,2]]

逆行列の計算

import numpy

# (100, 140, 20.5)の平行移動の行列.
m = numpy.matrix(numpy.identity(4))
m[3] = [100.0, 140.0, 20.5, 1.0]

# 逆行列を計算.
mInv = m.I

# 逆行列を計算.
mInv = numpy.linalg.inv(m)

print mInv

行列を「m」としたとき、「m.I」が逆行列になります。
「numpy.linalg.inv(m)」としても同じ値が取得されます。

結果は以下のようになります。

[[   1.     0.     0.     0. ]
 [  -0.     1.    -0.    -0. ]
 [   0.     0.     1.     0. ]
 [-100.  -140.   -20.5    1. ]]
この記事のタイトルとURLをコピーする
Translate »