|
|||||||||||||
■Twitter: @FumioNonaka / Facebook Page: CreateJS / Away3D
Creators MeetUp ベクトルふたたび − 外積と内積を使う「ベクトル」というのは、とっつきにくい印象が強いらしい。とくに、「内積」とか「外積」とか、果たして何の積なのか。いずれも、式そのものは単なる四則演算だ。けれど、そもそもどんなときに使うのかわらないのが、近寄りがたい理由だろう[*1]。そこで、内積も加えて、最近小学校の算数教材の制作で使った例を採上げる。式は前述のとおり四則演算なので、考え方に重点を置いてご説明したい。 なお、このレジュメは、2015年3月21日土曜日に催された第26回Creators Meetupで務めた高座「ベクトルふたたび − 外積と内積を使う」の参加者向けとして書いた。当日のYouTube録画をつぎに掲げる。
01 座標でかたちを扱う算数教材でベクトルの外積や内積を使ったのは、図形の上でマウスポインタが重なった面や辺をハイライトするという処理だ(図001)。以下のサンプル001は、もっとも簡単なかたちである三角形について、ポインタ座標の重なりを確かめている。 図001■図形の面や辺と座標との重なりを調べる サンプル001■EaselJS 0.8.0: Using the dot product and the cross product to search the line and the face under the mouse pointer マウスポインタが重なるとハイライトするというのは、ボタンにも使われる動きだ。たとえば、Flashでは、予めハイライトのパーツを置いておき、初めは見えないようにしたうえで、ロールオーバーしたら表示するというつくり方がよく用いられる(図002)。 図002■予めハイライトのパーツを置いてロールオーバーで表示させる (Flash Professional CC) しかし、図形をパーツに分けて扱うのが適さない場合もある。立体図形をアニメーションさせるときは、3次元の頂点座標をデータにして計算し、辺や面は線と塗りで描く方が扱いやすい(図003)。すると、マウスポインタとの重なりも、座標にもとづいて確かめなければならない。 図003■立体をアニメーションさせるには3次元の頂点座標で扱う ただし、ここで気をつけなければならないのは、マウスポインタの座標は2次元(xとy)であり、重なりは2次元平面で調べるということだ。立体の頂点座標は3次元であっても、それらに遠近法を加えて2次元平面に投影する(図004)。「透視投影」と呼ばれる考え方だ(「遠近法が投影された座標を求める」参照)。 図004■遠近法を投影した図形は2次元平面で扱われる 02 座標が面の中か外かを調べるマウスポインタと面との重なり、つまり座標が面の中か外かを調べるにはベクトルの外積が使える。3次元ベクトルの外積A×Bはベクトルで表され、方向と大きさをもつ(図005)。そして、ベクトルの外積は交換法則が成立たない。掛ける順序が変わると、方向は逆になる。 図005■3次元ベクトルの外積は方向と大きさをもつ
2次元ベクトルの外積の大きさは、3次元ベクトルと同じくふたつのベクトルを2辺とする平行四辺形の面積に等しい。しかし、方向はなく、そのかわりに正負が定められている。ふたつのベクトルの位置が右ネジなら+、左ネジなら-になる。 図006■2次元ベクトルの外積は方向のかわりに正負が定まる
2次元ベクトルA(ax, ay)とB(bx, by)の外積A×Bはつぎの式で導かれる。なお、外積は乗算ではないので、記号「×」は「クロス」と読む。前掲サンプル001には、以下のように2次元座標のクラス(Vector2D)に外積を求めるメソッド(crossProduct2D())が備わっている。 【2次元ベクトルA(ax, ay)とB(bx, by)の外積A×B】
2次元平面の三角形について、座標が内側にあるかどうかは、3辺と調べる座標の外積で確かめられる。3辺のベクトルは、向きを時計回りに決めておく(図007)。そして、各ベクトルの始点と調べる座標を結んだベクトルから、それぞれ外積を計算する。3つの外積がいずれも正なら、調べた座標は3辺すべてに対して右ネジの位置にある。つまり、三角形の内側に座標があるということになる。 図007■2次元平面上の座標が三角形の内側にあるかどうかを外積で調べる前掲サンプル001は、つぎのように三角形を定めるクラス(Triangle)に備えたメソッド(hitTestPoint())により、引数の座標が三角形の内側にあるかどうか調べている。なお、このクラスはプロパティ(vertex0とvertex1およびvertex2)に3頂点座標をもつ。また、ふたつの座標をメソッド(subtract())で引き算することにより、それらを結ぶベクトルが求まる。
03 座標が線分に近いか遠いかを調べる座標が辺つまり線分に近いか遠いかは、距離で調べることになる。そして、2次元平面における直線と点との距離は外積で求められる(図008)。線分(ab)と点(c)をベクトル(PとQ)として求めた外積の大きさ(|P×Q|)は平行四辺形の面積に等しい。したがって、その面積を底辺となる線分の長さ(ab = |P|)で割れば、高さ(cd = |Q|sinθ)は線分と点との距離になる。 図008■2次元平面における直線と点の距離は外積で求められる 【外積P×Qから直線との距離を求める】 ただし、外積から求めた距離は、線分(ab)ではなく直線に対する値になる。つまり、点が線分の外側にあっても、両端から伸ばした直線との距離が導かれる。しかし、線分の両端より外側の点(c'やc'')は省きたい(図009)。そこでベクトルの内積を使う。 図009■線分の両端で座標を3つの領域に分ける 2次元ベクトルA(ax, ay)とB(bx, by)の内積A・Bはつぎの式で導かれる。なお、内積の記号「・」は「ドット」と読む。前掲サンプル001には、以下のように2次元座標のクラス(Vector2D)に内積を求めるメソッド(dotProduct2D())も備わっている。 【2次元ベクトルA(ax, ay)とB(bx, by)の内積A・B】 図010■ベクトルAとBの内積
内積A・B = |A||B|cosθの正負はcosθの値で決まる。ふたつのベクトルのなす角θは、内積が正なら鋭角、負は鈍角、0のとき直角になる(図011)。つまり、線分(ab)と点(cまたはc')をベクトルとして求めた内積が負なら、点(c')は線分の外にある。 図011■線分の端の点aを通る垂線の内側か外側かはcosθの正負でわかる 内積P・Q = |P||Q|cosθを一方のベクトル(P)の絶対値(|P|)で割れば、他方のベクトル(Q)にそのベクトルを投影した大きさ(|Q|cosθ)が求まる(図010参照)。その大きさが一方のベクトル(P)よりも長ければ、やはりその点(c'')は線分の端(b)を超えている(図012)。 図012■点c"が点bを通る垂線の外側にあると|Q"|cosθ"は|P|より大きい 前掲サンプル001では、つぎのように三角形を定めるクラス(Triangle)に備えたメソッド(getCloseLine())が、引数の座標の近くに辺を返す。近い辺がなければ、戻り値はnullとした。まず、座標のクラス(Vector2D)の外積を求めるメソッド(crossProduct2D())で、距離が一定値(threshold)より近いかどうかを調べる。近かったら、つぎに内積を求めるメソッド(dotProduct2D())で、座標が線分の両端より内側であることを確かめた[*2]。
作成者: 野中文雄 Copyright © 2001-2015 Fumio Nonaka. All rights reserved. |
|||||||||||||