2017年06月26日
modo11.0v3のスクリプトについて調べてみた その98
引き続き「TD SDK」の「Vector3」クラスについて調べてみたい。
「angle()」メソッドは2つのベクトルの為す角度を求める。下がそのプログラムで、2つのベクトルの単位ベクトルを「normal()」メソッドで得て、それらを「dot()」メソッドで内積計算をして、得られた値を「acos()」メソッドで角度(ラジアン)に変換している。
def angle(self, other): """Returns the angle between this and another vector""" return math.acos(self.normal().dot(other.normal()))
これは2つのベクトルの内積が下の式である事から
V1・V2 = |V1||V2|cosθ
ベクトルを単位ベクトルにすれば |V1||V2|=1になって、cosθになるのを利用したものだ。「acos()」はcos関数の逆関数だ。
「rotate()」は実装されていないようだ。
def rotate(self, other): # by matrix, quaternion, euler etc. raise NotImplementedError
そのかわりクォータニオンや回転軸と角度を指定した回転メソッドが実装されている。
「rotateByQuat()」はクォータニオンでベクトルを回転するメソッドだ。下がそのプログラム。回転させたい「Vector3」を「Matrix4」の移動ベクトルにして、クォータニオンも「toMatrix4()」で「Matrix4」に変換して、掛け合わせる事で「Matrx4」の移動ベクトルを回転変換している。そしてその結果の「matrix4」から移動ベクトル部分を抽出して「Vector3」に戻している。「mulByMatrixAsPoint()」を使っても良かったね。
def rotateByQuat(self, other): """Rotate this vector by a quaternion""" matrix = Matrix4(position=self.values) matrix = matrix * other.toMatrix4() for i in range(3): self.values[i] = matrix[3][i]
「rotateByAxisAngle()」は回転軸ベクトル「axis」とその軸回りの回転角度「angle」を指定してベクトルを回転させるメソッドだ。下がそのプログラムで、回転軸と回転角度からクォータニオンを作って、あとは「rotateByQuat()」と同様の処理をしている。
def rotateByAxisAngle(self, axis, angle): """Rotates this vector by a given axis and angle :param Vector3 axis: This axis to rotate about :param float angle: The angle in radians to rotate by """ quat = Quaternion() quat.setAxisAngle(axis, angle) result = Matrix4(position=self.values) * quat.toMatrix4() self.values = list(result.position)
下のプログラムは「Cylinder」アイテムのY軸を中心に「Mesh」アイテムの選択された頂点を30度回転させるプログラムだ。「rotateByAxisAngle()」の回転は原点中心にしか出来ないので、回転させたい頂点の座標値から回転中心の座標値を一旦引いて回転させ、回転後に足して戻している。
import math from modo import * cylinder = Mesh('Cylinder') mesh = Mesh('Mesh') cylinder_m4 = Matrix4(cylinder.channel('worldMatrix').get()) cylinder_y = cylinder_m4[1] selected_vertex = mesh.geometry.vertices.selected for v in selected_vertex: tmp = Vector3(v.position) - cylinder_m4.position tmp.rotateByAxisAngle(cylinder_y,math.radians(30)) tmp = tmp + cylinder_m4.position v.position = tmp.values mesh.geometry.setMeshEdits()
こんなシーンを作って、
「Cylinder」のローカル座標は下のようになっている。
下が「Mesh」の上の面の頂点を選択して実行した結果。「Cylinder」を軸に30度回転したのがわかる。
続きはまた次回。