Adobe Flash非公式テクニカルノート 2次元平面で2直線の交点を求める
本稿では、2次元平面においてふたつの直線の交わる点を求めます。直線が1次関数で表されることについては、「直線の式(方程式)」をご参照ください。直線の1次関数は、Vector3Dオブジェクトで扱うことにします。 01 直線の式をVector3Dオブジェクトで表す y = mx + n 図001■傾きmでy切片がnの直線 つぎのようにふたつの係数(a、b)とひとつの定数(c)を使えば、y軸に平行な直線も含めて、直線が一般的に表せます。ただ、パラメータが増えるので計算は面倒になり、どのような直線になるのかが直感的に捉えにくくなります。 ax + by + c = 0 けれど、交点を求めるという目的からは、例外は少ないほど望ましいといえます。また、関数を定めてしまえば、計算の手間は初めにスクリプトを書くときだけです。したがって、上記の一般的な1次方程式のかたちを使うことにします。 さて、直線を表すためのオブジェクトを用意します。パラメータがちょうど3つあるので、Vector3Dオブジェクトが使えます[*1]。上記の1次方程式のa、b、cが変数だとすれば、直線のVector3Dオブジェクトはつぎのようにつくります。 var line:Vector3D = new Vector3D(a, b, c)
02 直線を求める関数の定義 [1] 傾きとy切片から直線を求める
したがって、直線のVector3Dオブジェクトは、つぎのような引数を渡せば得られます。 var line:Vector3D = new Vector3D(m, -1, n) [2] 傾きと1点から直線を求める
スクリプト001の関数(xGetLineFromSlope())では、直線の傾きは引数(nSlope)として与えられているので、y切片さえわかれば前述[1]にしたがって直線のVector3Dオブジェクトが求められます。第2および第3引数(nX0とnY0)も用いて、そのy切片(intercept)を導いているのが第3行目です。 [3]通過する2点から直線を求める
スクリプト002の関数(xGetLine())は、2点のxy座標から直線の傾き(nSlope)を求めます(第3および第5〜6行目)。そうすれば、前述[2]で定めた関数(xGetLineFromSlope())を呼出して、直線が求められます(第7行目)。なお、2点を通る直線の方程式の導き方については、前出「直線の式(方程式)」の2「指定された点を通る直線の式」をご参照ください。 ただし、傾きの分母となるx座標の増分(nDeltaX)が0のときは、傾きが求まらず、直線はy軸に平行(x = 定数)となります(スクリプト第8〜10行目)。 03 2直線の交点を求める関数の定義
つぎのスクリプト003で定めた関数(xGetCrossPoint())は、引数に受取ったふたつの直線のVector3Dオブジェクトから交点をPointオブジェクトで返します。第9〜10行目をご覧いただければわかるとおり、2直線の交点の公式をそのまま当てはめました。 スクリプト003■ふたつの直線のVector3Dオブジェクトから交点をPointオブジェクトで求める
それでは、関数を試すために、ステージに正三角形を描いてみます。正三角形は、底辺の両端から底角60度の直線を伸ばし、交点を結べばつくれます。 なお、角度θの直線の傾きはtanθになります。距離が1で角度θのxy座標は(cosθ, sinθ)です(図002)。したがって、この直線の傾きはsinθ/cosθ = tanθだからです(「角度と座標の計算 − Flash の三角関数を使う」2「tanと逆関数」参照)。 図002■距離が1で角度θのxy座標は(cosθ, sinθ) 以下のスクリプト004は、座標(50, 120)を底辺の左端として、1辺100ピクセルの正三角形を描きます。底角60度の直線はスクリプト001の傾きと直線が通る1点の座標から直線のVector3Dオブジェクトを求める関数(xGetLineFromSlope())で定め、スクリプト003のふたつの直線のVector3Dオブジェクトから交点をPointオブジェクトで求める関数(xGetCrossPoint())により正三角形の頂点を導きました。 スクリプト004■ステージに正三角形を描く
スクリプト004は、まず座標(50, 120)と水平に100ピクセル右の座標で三角形の底辺を定めます(第3〜4行目)。ふたつの座標はPointオブジェクト(pointAおよびpointB)にしました。つぎに、その両端から底角60度の直線をそれぞれ(関数xGetLineFromSlope()から)求めています(第5〜7行目)。そして、それら2直線の交点を(関数xGetCrossPoint()で)求めれば、正三角形の頂点(pointC)が定まります(第8行目)。 そのうえで、求めた正三角形の3頂点を直線で結びました(図003)。描画用にSpriteインスタンスをつくり、Graphicsクラスの描画メソッドで線描しています(スクリプト004第9〜16行目)。Graphicsクラスの描画メソッドによる直線の描き方については、「Vector3Dクラスの3次元空間座標とインスタンスへの描画」の「Spriteインスタンスに直線を描く」をお読みください。 図003■正三角形の3頂点を定めて線描する 04 2直線の交点を求める公式 a1x + b1y + c1 = 0 … (1) 式(1)と(2)の両辺にそれぞれb2とb1を乗じると、(3)と(4)の式になります。 a1b2x + b1b2y + b2c1 = 0 … (3) 式(3)から(4)を差引くと、つぎのようにxが導かれます。 (a1b2 - a2b1)x + (b2c1 - b1c2) = 0 同様に、式(1)と(2)の両辺にそれぞれa2とa1を乗じて、式(5)と(6)を得ます。 a1a2x + a2b1y + a2c1 = 0 … (5) 式(5)から(6)を差引けば、yが求められます。 (a2b1 - a1b2)y + (a2c1 - a1c2) = 0 つぎに、a1b2 = a2b1の場合について考えます。b1 = 0のとき、a1 = 0ですと式(1)が直線を表さなくなります。したがって、b2 = 0でなければなりません。 a1b2 = a2b1で、b1 = 0ならb2 = 0 つまり、2直線の式はつぎの(1)'と(2)'のようになり、ともにy軸に平行です。 a1x + c1 = 0 … (1)' b1≠0のとき、もしb2 = 0ですと、a1b2 = a2b1 = 0となり、a2 = 0でなければなりません。すると式(2)が直線を表しません。したがって、b2≠0になりますので、つぎの等式が成立ちます。 a1/b1 = a2/b2 この両辺は、それぞれ式(1)と(2)の直線の傾きを表します。つまり2直線の傾きが等しいので、互いに平行です。以上から、つぎの結論が導けます。 a1b2 = a2b1のとき2直線は互いに平行 したがって、2直線の交点は存在しません。まとめると、2直線の交点はつぎのようになります。
なお、前掲スクリプト003で定めた2直線の交点を求める関数(xGetCrossPoint())は、交点が存在しないとき第9〜10行目の右辺の分母がともに0になります。そのため、戻り値のPointオブジェクトは、Point.xおよびPoint.yプロパティの値がともにNaNになります。 作成者: 野中文雄 Copyright © 2001-2011 Fumio Nonaka. All rights reserved. |
||||||||||