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

名称

 Math::Vec - オブジェクト指向のベクトル演算


概要

use Math::Vec;

$v = Math::Vec->new(0,1,2);

 または

use Math::Vec qw(NewVec);

$v = NewVec(0,1,2);
@res = $v->Cross([1,2.5,0]);
$p = NewVec(@res);
$q = $p->Dot([0,1,0]);

 または

use Math::Vec qw(:terse);

$v = V(0,1,2);
$q = ($v x [1,2.5,0]) * [0,1,0];

注意

 本モジュールは一部分は未完成である。関数が何も処理しなければそれなりの理由がある。これを生産的な環境で用いるならコードを確認して欲しい。


著者

 Eric L. Wilhelm, <ewilhelm at cpan dot org>
 http://scratchcomputing.com


説明

 本モジュールは Wayne M. Syvinski が開発した Math::Vector を改良したものである。ほとんどは同じアルゴリズムを採用し、同じ関数名を用いている。ただしより自然になると思われる名称にはエイリアスを作成している。(少なくとも私がそう思う名称に。)
 オブジェクト指向呼び出し形式のオブジェクトは [x,y,z] の形式をしたベクトルを含む配列参照である。メソッドはリストを返す。


著作権表示

 Copyright (C) 2003-2006 Eric Wilhelm

 部分的に Copyright 2003 Wayne M. Syvinski


無保証

 本ソフトウェアは明示的にも暗示的にも無保証であり、ユーザは自らのリスクで本ソフトウェアを利用すること。損失が生じたとしても Wayne M. Syvinski にも他の誰にも責任はなく、ユーザに責任がある。あなたは警告された。

 損失が発生した場合であっても Wayne M. Syvinski, Eric Wilhelm その他いかなる人物もその責任を負わない。以上のことを警告する。  また、数学的な正確性についても保証しない。本コードを製品の環境で利用するのであれば、利用者の責任で正しい値を返すことを検証のうえで行うこと。


ライセンス

本ソフトウェアを以下のライセンスの元に利用してもよい。

  1. GNU General Public License
    http://www.gnu.org/copyleft/gpl.html で入手可能。)
  2. Artistic License
    http://www.perl.com/pub/language/misc/Artistic.html で入手可能。)

参考資料

 Math::Vector


コンストラクタ

new

 デカルト座標における点 ($x, $y, $z)(ただし $z は省略可能)への配列参照を返す。feed-me-list 及び get-back-reference 文法に留意すること。他のメソッドとは理由があって逆にしている。(これにより関数呼び出しのネストが可能になる。)
 z 値はオプションである。未定義の値は黙って0に設定される。

$vec = Math::Vec->new($x, $y, $z);

NewVec

 何度も Math::Vec->new($x, $y, $z) とタイプしたくない場合にショートカットとして利用することができる。これにより関数呼び出しがネストやチェーンしている場合に非常に簡単になる。メソッドはリストを出力することに留意すること。(質問に対する答えのように。)
 配列参照の答えのために[]を用いているが $object->method(@args) と記してもよい。
 本関数はオプションとしてエクスポートできる。使用するためには単にコードの最初に use Math::Vec qw(NewVec); と書くだけでよい。

use Math::Vec qw(NewVec);

$vec = NewVec($x, $y, $z);
$diff = NewVec($vec->Minus([$ovec->ScalarMult(0.5)]));

関数

 これらは :terse フラグで名前空間にインポートされた1文字のショートカットである。

use Math::Vec qw(:terse);

V

 これは Math::Vec->new($x,$y,$z) と同様である。

$vec = V($x, $y, $z);

U

 V($x,$y,$z)->UnitVector() へのショートカットである。

$unit = U($x, $y, $z);

 ベクトルオブジェクトとともに呼び出してもよい。

$unit = U($vector);

X

 x-軸単位ベクトルを返す。

$xvec = X();

Y

 y-軸単位ベクトルを返す。

$yvec = Y();

Z

 z-軸単位ベクトルを返す。

$zvec = Z();

オーバーロード

 :terse 関数と用いるのが一番よいが、オーバーロードによってメソッドへのインタフェースを1つにすることもできる。メソッドは参照をとってリストを返し、オーッバーロードされた演算子は参照を返す。これはベクトル演算の連結を容易にする。もちろん @{$vec} との参照を解除することもできる。
 以下のセクションは長短両方のインタフェースを示している。

符号反転

@a = NewVec->(0,1,1)->ScalarMult(-1);
@a = @{-V(0,1,1)};

文字列化

 連結及び他の文字列演算子を実行する。

print join(", ", 0,1,1), "\n";

print V(0,1,1), "\n";

$v = V(0,1,1);
print "$v\n";
print "$v" . "\n";
print $v, "\n";

追加

@a = NewVec(0,1,1)->Plus([2,2]);

@a = @{V(0,1,1) + V(2,2)};

# 引数には括弧が必要
@a = @{V(0,1,1) + [2,2]};

# Vでなくてもよい。
@a = @{[0,1,1] + V(2,2)};

引き算

@a = NewVec(0,1,1)->Minus([2,2]);

@a = @{[0,1,1] - V(2,2)};

スカラー倍

@a = NewVec(0,1,1)->ScalarMult(2);

@a = @{V(0,1,1) * 2};

@a = @{2 * V(0,1,1)};

スカラーによる除算

@a = NewVec(0,1,1)->ScalarMult(1/2);

# 順序は重要!
@a = @{V(0,1,1) / 2};

外積

@a = NewVec(0,1,1)->Cross([0,1]);

@a = @{V(0,1,1) x [0,1]};

@a = @{[0,1,1] x V(0,1)};

内積

 スカラー積としても知られる。

$a = NewVec(0,1,1)->Dot([0,1]);

$a = V(0,1,1) * [0,1];

注意:
 '.' 演算子はここでは使わない。
  * はドットではないことはわかっているが、少なくとも数学上の演算子ではある。(perl ではドットを使うと暗黙のうちに文字列連結を行うことがあるため)

比較

  == 及び != 演算子は向きと大きさの観点から等しいか否かを比較する。等しさに対する許容範囲は指定しない。

長さ

$a = NewVec(0,1,1)->Length();

$a = abs(V(0,1,1));

ベクトル射影

 これは少し違う。$b から $a に対する射影という意味で $a->Proj($b) と書かれるが、逆にも読めてしまう恐れがある。そのために次のようにも書く。$b>>$a.

@a = NewVec(0,1,1)->Proj([0,0,1]);

@a = @{V(0,0,1)>>[0,1,1]};

演算の連結

 上記の例は単純にメソッドインタフェースからオーバーロードされたインターフェースへ如何に移管するかを示したものであり、オーバーロードすると複数の演算子を互いに連結できるようになる。オーバーロードされた演算子からの返り値はすべて参照なので、実行時に参照を解除することができる。

直線を離れた単位ベクトル

 CAD::Calc::line_to_rectangle() 関数に由来するものである。

use Math::Vec qw(:terse);

@line = ([0,1],[1,0]);

my ($a, $b) = map({V(@$_)} @line);
$unit = U($b - $a);
$left = $unit x -Z();

内積の長さ

$length = abs($va x $vb);

座標軸としてのベクトル

 dxf データを用いて曲線を描く際に有用である。

$val = 3.14159;                             # 'start parameter'
@c = (14.15973317961194, 6.29684276451746); # codes 10, 20, 30
@e = (6.146127847120538, 0);                # codes 11, 21, 31
@ep = @{V(@c) + \@e};                       # 軸の最終点
$ux = U(@e);                                # x' 軸上の単位
$uy = U($ux x -Z());                        # y' は x' の残差
$center = V(@c);

# autodesk はこう言うだろう
@pt = ($a * cos($val), $b * sin($val));

# しかし major/minor 軸問題については何も教えてくれない
@pt = @{$center + $ux * $pt[0] + $uy * $pt[1]};;

優先順位

 演算子の優先順位は Perl が望む順位に従う。これが標準的なベクトル演算の記述に適合するかどうかは確認していない。もし問題がありそうなら括弧を使うこと。
 同じ優先順位の 'x' と '*' があった場合には左側が優先である。以下の例では外積を最初に処理すれば括弧なしでよい。

# 外積の内積
$v1 x $v2 * $v3
($v1 x $v2) * $v3

# ベクトルをはさんだスカラーとの外積(違法!)
$v3 * $v1 x $v2

メソッド

 メソッドは配列参照を引数とし、リストを返す。これは、他の関数呼び出しでフィードバックして利用する際に無名配列参照を生成するか、リストをそのまま使用するかを選択することができることを意味する。スカラーまたはスカラーのリストを返すメソッドはこの問題とは無関係であるが、ベクトルを返すメソッドはリストとして返す。
 連続的に呼び出し(chain calls)をしたい場合には NewVec コンストラクタを用いるか、出力を中カッコ [] で囲んだ無名配列を指定すること。

my $vec = NewVec(@pt);
my $doubled = NewVec($vec->ScalarMult(0.5));
my $other = NewVec($vec->Plus([0,2,1], [4,2,3]));
my @result = $other->Minus($doubled);

$unit = NewVec(NewVec(@result)->UnitVector());

 ベクトルオブジェクトは配列参照とする。これは操作上かなりの制限となるが、ベクトル演算はそれほど複雑ではない。ありがたいことにこのモジュールを利用するたびに少なくとも2行のコードを削減することができる。

Dot

 $vec と $othervec との内積を返す。

$vec->Dot($othervec);

DotProduct

 Dot() へのエイリアス。

$number = $vec->DotProduct($othervec);

Cross

 $vec と $other_vec との外積を返す。

@list = $vec->Cross($other_vec);
# または vac への結果を用いて
$cvec = NewVec($vec->Cross($other_vec));
pre>

CrossProduct

 Cross() へのエイリアス。

$vec->CrossProduct();

Length

 $vec の長さを返す。

$length = $vec->Length();

Magnitude

$vec->Magnitude();

UnitVector

$vec->UnitVector();

ScalarMult

 ベクトル $vec の各要素にスカラー $factor を乗じる。

@new = $vec->ScalarMult($factor);

Minus

 ベクトルから任意の数を減じる。

@result = $vec->Minus($other_vec, $another_vec?);

 これは以下のものと等値。

@result = $vec->Minus([$other_vec->Plus(@list_of_vectors)]);

VecSub

 Minus() へのエイリアス

$vec->VecSub();

InnerAngle

 2ベクトルで形成される平面上での角度(鋭角のほう;ただしラジアンで)を返す。

$vec->InnerAngle($other_vec);

DirAngles

$vec->DirAngles();

Plus

 ベクトルに任意の数を加える。

@result = $vec->Plus($other_vec, $another_vec);

PlanarAngles

 引数がリストの場合は最初の平面(primary planes)におけるベクトルのなす角度を返す。引数がスカラーの場合は x-y 平面における角度を返す。角度はラジアンで第1軸から反時計周りを正とする。

($xy_ang, $xz_ang, $yz_ang) = $vec->PlanarAngles();

Ang

 x-y 平面における角度を返すのではないかという懸念を払拭した PlanarAngles() へのエイリアス。

$xy_ang = $vec->Ang();

VecAdd

$vec->VecAdd();

UnitVectorPoints

 点 $A から点 $B に向かう向きの単位ベクトルを返す。

$A->UnitVectorPoints($B);

InnerAnglePoints

 3点間の InnerAngle() を返す。$Vert は頂点である。

$Vert->InnerAnglePoints($endA, $endB);

PlaneUnitNormal

 3点により定義される平面に垂直な単位ベクトルを返す。このベクトルの意味は右手の法則と与えられた点の順序とによる。ベクトル $Vert が3点の頂点とする。たとえば if $Vert が x 軸が $A、y 軸が $B であるような座標系の原点であるとすると、z 軸の正方向に沿った単位ベクトルを返す。

$Vert->PlaneUnitNormal($A, $B);

TriAreaPoints

 3点から形成される三角形の角度を返す。

$A->TriAreaPoints($B, $C);

Comp

 ベクトル $B のベクトル $A に対するスカラー射影(ベクトル $B の $A 方向の成分)を返す。

$A->Comp($B);

Proj

 ベクトル $B のベクトル $A に対する射影を返す。

$A->Proj($B);

PerpFoot

 可能な限り $pt に近い点 $A,$B を結ぶ直線上の点を返す。(垂線の足を求める。)

$pt->PerpFoot($A, $B);

未完成のメソッド

 以下のメソッドはまだ移植が進んでいない。Wayne M. Syvinski が書いた元の Math::Vector モジュールでの関数名を予約するためにここに列挙しておく。

TripleProduct

$vec->TripleProduct();

IJK

$vec->IJK();

OrdTrip

$vec->OrdTrip();

STV

$vec->STV();

Equil

$vec->Equil();
Toolbox Logo
Updated : 2007/05/30