外積の使い道
大学で習うベクトルの外積。これを何に使えるかの一つの答えとして持ち出す話。
三角形ポリゴンでできた地面の上にキャラクターが立ってるとする。そのとき、どのポリゴンの上にいるのかを知りたいとする。三角形の重心との距離が一番近い、でもいいが、外積でもできる。
以下のプログラムのように、三角形の3頂点とマウス座標の4点から、3つの外積を計算する。その3つ外積のz座標が正正正もしくは負負負なら、マウス座標は三角形の内側にある。
PVector a, b, c; //3頂点
PVector AB, BC, CA; //頂点間のベクトル
color c1 = color(0, 0, 255);
color c2 = color(255, 0, 0);
void setup() {
size(512, 512);
noFill();
a = new PVector(256, 128, 0);
b = new PVector(128, 384, 0);
c = new PVector(384, 256, 0);
AB = sub(b, a);
BC = sub(c, b);
CA = sub(a, c);
}
void draw() {
background(255);
PVector p = new PVector(mouseX, mouseY, 0);
PVector AP = sub(p, a);
PVector BP = sub(p, b);
PVector CP = sub(p, c);
float z1 = cross(AB, BP).z;
float z2 = cross(BC, CP).z;
float z3 = cross(CA, AP).z;
if ((z1<0 && z2<0 && z3<0)||
(z1>0 && z2>0 && z3>0)) {
println("in");
}else{
println("out");
}
fill(z1<0 ? c1 : c2, 105);
triangle(a.x, a.y, b.x, b.y, mouseX, mouseY);
fill(z2<0 ? c1 : c2, 85);
triangle(b.x, b.y, c.x, c.y, mouseX, mouseY);
fill(z3<0 ? c1 : c2, 64);
triangle(c.x, c.y, a.x, a.y, mouseX, mouseY);
}
PVector sub(PVector p, PVector q) {
PVector t = new PVector(0, 0, 0);
t.set(p);
return t.sub(q);
}
PVector cross(PVector p, PVector q) {
PVector t = new PVector(0, 0, 0);
t.set(p);
return t.cross(q);
}
PVectorは、基本型(int,float等)ではないので、参照渡しになる。数学に近い書き方にしたく、PVectorクラスのsubは、値が変わるので使わずに、自分で関数を作った。
fill(z<0 ? c1 : c2);
このコードは、以下のコードを三項演算子を用いて書いたもので、同等です。
if (z<0) {
fill(c1);
} else {
fill(c2);
}