Location : Home > Languages > Perl > Package
Title : Math::SO3
Toolbox Logo

名称

 Math::SO3 - 原点のまわりの回転群

(以下の場合に有用である:3次元における方向付けの実装。本パッケージの重要な特徴の1つは、多数の回転行列を連結するときに数値的なブレのために直交でなくなるようなことを防ぐことである。SO3の直接の実装であり、4元数及び SU2->SO3 準同型を使っていない。)


概要

use Math::SO3;

$rotation = Math::SO3->new("zr" => 3.14159/2,
                           "xr" => 3.14159/4,
                           "zr" => 3.14159/8);

$rotation = Math::SO3->new("zd" => 90, 
                           "xd" => 90, 
                           "zr" => 3.14159/6);

$rotation->invert();

$rotation->turn("zr" => 3.14159/2, "xr" => 3.14159/4);
$rotation->turn_round_axis((pack "d3", 1,1,1), 30, "degrees");

$rotation->combine($rotation_after);
$rotation->translate_vectors($vec1, $vec2, $vec3, $vec4, @more_vectors);

$rotation->inv_translate_vectors($vec1, $vec2, $vec3, $vec4, @more_vectors);

($angle, $dir) = $rotation->turning_angle_and_dir("d");

($phi, $theta, $psi) = $rotation->euler_angles_zxz("d");

($heading, $pitch, $roll) = $rotation->euler_angles_yxz("d");

$rotation->format_matrix();
$rotation->format_matrix("%16.8f");

$rotation->format_eigenvector();
$rotation->format_eigenvector("%16.8f");

$rotation->format_euler_zxz();
$rotation->format_euler_zxz("%16.8f");

$rotation->format_euler_yxz();
$rotation->format_euler_yxz("%16.8f");

説明

内部表現:
 SO3 は標準的な C の順序における回転行列の要素を含む 3*3*sizeof(double) サイズの文字列への参照である。これはオフィシャルなインタフェースの一部であり、もし彫り蹴ればこの情報を用いてもよい。(このような純粋な数学的データタイプから継承してもあまり意味はない。)
注意:
 以下のテキストにおける d (または d から始まる文字列)は度表示による角度を表す。同様に r であればラジアンを意味する。もしこのことから離れたければデフォルト r を用いればよい。これらの用語を最も記述的に、可読に選択することで自由になることができる。
 機械工学に関するテキストでは(とてもとても影響のあるゴールドシュタインのものなどは)以下のような記述となっている。

(e1')    (   ) (e1)
(e2')  = ( M ) (e2)
(e3')    (   ) (e3)

 残念なことに、これには少しあいまいさが残っている。ベクトル回転行列 M を係数回転行列 M^T と誤記するのは簡単である。
 行列/ベクトル演算は係数ベクトルを列ベクトル及び行ベクトルとしての基底ベクトルの配列として記述することを許せば最良のものといえる。

                                   (a1)
a1*e1 + a2*e2 + a3*e3 = (e1 e2 e3) (a2)
                                   (a3)

 このようにすれば以下のように書ける。

(a1')    (   ) (a1)
(a2')  = ( M ) (a2)
(a3')    (   ) (a3)

                           (   )
(e1 e2 e3) = (e1' e2' e3') ( M ) 
                           (   )

 詳しくは例えば "Misner, Thorne, Wheeler: Gravitation" を見よ。残念なことに間違った方法が流布している。OpenGL でさえもこのように考えて欲しい。これについては混乱しないように。仮に混乱したとしてもここではまったく関係ない。我々の3次元空間は少々複雑なのだ。しかしこれをマスターする方法がある。慣れろ。ここに2つの異なる座標系があると考えてみよう。それでいい。
 剛体力学ではこの M を、列空間座標ベクトル(CSCV; column space-coordinate vector)として対応する列剛体座標ベクトル(CBCV; column body-coordinate vector)を与える、右からかける行列として扱うのが最良である。

$rotation = Math::SO3->new("zr" => 3.14159/2, 
                           "xr" => 3.14159/4, 
                           "zr" => 3.14159/8);

 新しい SO3-回転行列 を生成する。単位行列で任意の数の回転を適宜してもよい。上の場合では、$rotation を、列空間座標ベクトルを列剛体座標ベクトルに変換する行列と考えれば(以下、cscv->cbcv と記す)、これらの回転は剛体に適用され、剛体の軸の周りを回転する。
重要:最も左の回転は最初に適用される。 "zr" はZ軸周りの回転を意味し、角度はラジアンである。(全体では 2piラジアン) "xd" はX軸周りの回転で単位は度(全体では360度)である。これらは混合できる。
 また、コンストラクタをコピーすることもできる。

$copy=$rotation->new().
$rotation->invert();

 逆の回転である。

$rotation->turn("zr" => 3.14159/2, "xr" => 3.14159/4);

 SO3 生成時の回転を特定できるように、後に属性を指定することができる。数値的ドリフト(numerical drift)は構築可能であるが、明らかな非直交を取得するための回転は不可能である。

$rotation->turn_round_axis((pack "d3", 1,1,1), 30, "degrees");

 空間座標において所与の軸の周りの回転体を返す。

$rotation->combine($rotation_after);

 $rotation_after を左からかけると、上記で定義したような意味で $rotation の後に $rotation_after を実行する。

$rotation->translate_vectors($vec1, $vec2, $vec3, $vec4, @other_vectors);

 cscv のリストの1つをそれぞれ対応する cbcv のリストで破壊的に置き換える。ベクトルは packed-double-strings : $vec=pack("d3",$xcoord,$ycoord,$zcoord) でなければならない。
 もしベクトルが長い、すなわち pack("d4", 5,8,10,1) のような場合には最初の3つの座標のみが置き換えられる。
 これは相同座標を扱う際にはきわめて有用である。

$rotation->inv_translate_vectors($vec1, $vec2, $vec3, $vec4, @other_vectors);

 他の方法と同様に cbcv -> cscv を行う。

($angle, $dir)=$rotation->turning_angle_and_dir("d");

 オイラーの定理では、3次元ではあらゆる回転の組み合わせは所与の方向に関する回転で表現できる。これはその回転と角度を決定する。角度が度で欲しければ "d" を、ラジアンで欲しければ "r" を指定する。
 本関数に対する FIXME コードはいささか奇妙で見直されるべきである。そんなわけでNASAの諸君よ、RTG-衛星の軌道計算にこれを使わないでくれ。

($phi, $theta, $psi)=$rotation->euler_angles_zxz("d");

 回転に対応する有名なオイラー角を返す。度で欲しければ "d" を、ラジアンで欲しければ "r" を指定する。
 速度を優先しているので、あらゆる可能な角度を分数で計算している。そのため非常に小さな値で割った場合にはおかしな値を返すかも知れない。

($heading, $pitch, $roll)=$rotation->euler_angles_yxz("d");

 標準的な zxzオイラー角には1つの問題がある。θ(theta)が非常に小さければφ(phi)及びψ(psi)回転はほとんど同じ方向になる。2つの回転が非常に似ている場合、座標からはこれらを区別することはきわめて困難であるか不可能である。航空額では非常によくある、他の角度の特定である。
 これが必要なのはフライとシミュレータを構築したいときだろう。
 精度は上記のごとし。

$rotation->format_matrix();
$rotation->format_matrix("%16.8f");

 行列の座標を表示する文字列 "[[m00 m01 m02][m10 m11 m12][m20 m21 m22]]" を計算する。オプションとして sprintf のフォーマット指定文でフォーマットを指定することができる。デフォルトは "%10.5f" である。

$rotation->format_eigenvector();
$rotation->format_eigenvector("%16.8f");

 同様に "<rotate 92.06153 deg round [ 0.88972 0.07784 -0.44982]>" のような文字列を計算する。

$rotation->format_euler_zxz();
$rotation->format_euler_zxz("%16.8f");

  同様に "D_z(psi= 330.00000 deg) D_x(theta= 80.00000 deg) D_z(phi= 340.00000 deg)" のような文字列を計算する。

$rotation->format_euler_yxz();
$rotation->format_euler_yxz("%16.8f");

 同じであるが、文字列は "D_z(heading= 338.30608 deg) D_x(pitch= -24.51349 deg) D_z(roll= 348.25034 deg)" のようなものである。
 基本的にこれらの関数はデバッグようの情報を取得するために追加されたものである。それゆえに可読性のため全ての角度は度で与えられる。


著者とライセンス

 Copyright 1999 Thomas Fischbacher, (tf@cip.physik.uni-muenchen.de)

 License: GNU Lesser General Public License (いわゆる GNU LGPL)
 Perl 本体に含まれているので LGPL のコピーは含まれていない。http://www.gnu.org/copyleft/lesser.html で見ることができる。


参考資料

 perl(1)

Toolbox Logo
Updated : 2007/11/30