プログラミングの備忘録

プログラムをつくる過程を残すもの

processingの備忘録 -ベクトル-

こんにちは。
今回はprocessingで「ベクトル」を扱ってみます。

processingのサンプルコードを見ていたときにまねてみたいものがあり、それがベクトルを使って書かれていたのでこれを機にやってみようと思った次第です。
今回はベクトルの基礎の部分だけをまとめることにして、実際に使ってコードを書くのは別の記事でやることにします。


ベクトルの表し方

processingにおいて、ベクトルを表す型は「PVector」です。
例えば「$\vec{a}$」と「$\vec{b}$」というベクトルをつくりたければ、

PVector a, b;

そして、そのベクトルの成分をそれぞれ$\vec{a} = \left( 2 , 4 \right)$、$\vec{b} = \left( 3 , 6 \right)$としたければ、

a = new PVector(2, 4);
b = new PVector(3, 6);

これで、x方向に2、y方向に4の大きさのベクトル$\vec{a}$と、x方向に3、y方向に6の大きさのベクトル$\vec{b}$がつくられました。


x成分、y成分をスカラーとして取り出したければ、

float ax = a.x;
float ay = a.y;


PVectorクラスの関数

割と数があるので先に一覧を示します。
(クリックするとその説明のところに飛びます。)


加減乗除をする関数add()、sub()、mult()、div()

ベクトル$\vec{a}$とベクトル$\vec{b}$について計算してみると、

PVector add = PVector.add(a, b);
//PVector add = a.add(b);と書くこともできる。以下同様。

PVector sub1 = PVector.sub(a, b);
PVector sub2 = PVector.sub(b, a);

PVector mult = PVector.mult(a, 10);

PVector div = PVector.div(a, 10);

それぞれをprintln()で表示すると、

[ 5.0, 10.0, 0.0 ] //add
[ -1.0, -2.0, 0.0 ] //sub1
[ 1.0, 2.0, 0.0 ] //sub2
[ 20.0, 40.0, 0.0 ] //mult
[ 0.2, 0.4, 0.0 ] //div

ベクトルとしては指定しなくても3次元となっているようです。


その他、レファレンスを見ればわかることではありますが、ここにも書いておくことにします。


ベクトルの成分を変更する関数set()

a.set(b);
print(a); //[ 3.0, 6.0, 0.0 ]

この例では、ベクトル$\vec{a}$の成分$\left( 2 , 4 \right)$がベクトル$\vec{b}$の成分$\left( 3 , 6 \right)$に置き換わります。

配列でも指定可能です。

float[] v = {4, 8};
a.set(v);
print(a); //[ 4.0, 8.0, 0.0 ]


向きがランダムで大きさが1のベクトルを生成する関数random2D()、random3D()

PVector v1 = PVector.random2D();
PVector v2 = PVector.random3D();


指定した向きで大きさが1のベクトルを生成する関数fromAngle()
角度はラジアン単位で指定します。

PVector v = PVector.fromAngle(PI/2);
println(v); //[ -4.371139E-8, 1.0, 0.0 ]

この例なら[ 0.0 1.0 0.0 ]となるはずですが、円周率の桁数の関係でx成分が変な数字になっていると考えられます。
($10^{-8}$オーダーならほぼ$0$なので問題は無いです。)


ベクトルをコピーする関数copy()

PVector v = new PVector();
v = a.copy();
print(v); //[ 2.0, 4.0, 0.0 ]

この例では、ベクトル$\vec{v}$の成分がベクトル$\vec{a}$の成分と同じものになっています。


ベクトルの長さ(magnitude)を計算する関数mag()

float m = a.mag();
print(m); //4.472136

計算としては、

sqrt(a.x*a.x + a.y*a.y)

と同じになるはずです。


ベクトルの長さを2乗した値を計算する関数magSq()

float m = a.magSq();
print(m); //20.0

計算としては、

a.x*a.x + a.y*a.y

と同じになるはずです。


2点間の距離を計算する関数dist()
「点」にあたる部分は矢印の先端です。

float d = PVector.dist(a, b);
print(d); //2.236068

計算としては、

sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y))

と同じになるはずです。


2つのベクトルの内積を計算する関数dot()

float d = PVector.dot(a, b);
print(d); //30.0

計算としては、

a.x*b.x + a.y*b.y

と同じになるはずです。


2つのベクトルの外積を計算する関数cross()
この関数は3次元でのみ使うことができる関数です。

PVector v1 = new PVector(10, 20, 2);
PVector v2 = new PVector(60, 80, 6); 
PVector v3 = v1.cross(v2);
println(v3);  // [ -40.0, 60.0, -400.0 ]


指定したベクトルの大きさを1にする関数normalize()

a.normalize();
print(a); //[ 0.4472136, 0.8944272, 0.0 ]


指定したベクトルの長さを制限する関数limit()

a.limit(1);
print(a); //[ 0.4472136, 0.8944272, 0.0 ]

ベクトルの長さが引数で指定した長さまでになります。


指定したベクトルの長さを変更する関数setMag()

a.setMag(10);
print(a); //[ 4.472136, 8.944272, 0.0 ]

ベクトルの長さが引数で指定した長さになります。


指定したベクトルの角度を計算する関数heading()
角度はラジアン単位で返されます。
fromAngle()の逆のような関数です。

float angle = a.heading();
print(angle); //1.1071488


指定したベクトルを指定した角度だけ回転させる関数rotate()
角度はラジアン単位で指定します。

PVector v = a.rotate(PI/2);
print(v); //[ -4.0, 1.9999999, 0.0 ]


2つのベクトルの間を線形補間するベクトルを計算する関数lerp()

PVector c = new PVector(2, 4);
PVector d = new PVector(5, 3);
PVector v = PVector.lerp(c, d, 0.5);
print(v); //[ 3.5, 3.5, 0.0 ]

2つのベクトルの傾きで一方を0、他方を1としたときに相対的に計算した傾きをもつベクトルを生成するものだと思います。
引数の3つ目の値で傾きの「寄り具合」を指定できるようで、この例でいえば、0に近いほど$\vec{c}$に近く、1に近いほど$\vec{d}$に近い傾きをもつようになります。
(ベクトルを図示してみるとわかりやすいです。)


2つのベクトルの間の角度を計算する関数angleBetween()
角度はラジアン単位で返されます。

float angle = PVector.angleBetween(a, b);
print(angle); //0.5667292


指定したベクトルの成分を配列で返す関数array()

float[] f = a.array();
print(f[0], f[1], f[2]); //2.0 4.0 0.0


レファレンスにあった関数は以上です。
もしこれら以外にもあったとしたら、それはコードを書く中で出てきたときに説明します。


まとめ

かなり煩雑になってしまいましたが、ここまででベクトルのつくりかたとPVectorクラスの関数についてを説明できました。
別の記事で実際にベクトルを使ってコードを書いてみようと思います。
それではまた次回。


参考