
前回の記事では指定された点が多角形の内部に存在するか否かを、ベクトルの外積を用いて判定しました。
本記事では角度を求めることで判定する仕組みについて紹介します。
本記事に関して
多角形の内外判定を行う方法のシリーズの2本目です。
UIや必要な事前準備は同じであるため、最初の記事からご覧いただけると理解しやすいと考えております。
この記事では1回目の記事でも用いた
IsPolygonInsideメソッドで多角形の内外判定を行っている箇所のみを紹介します。シリーズ目次
角度を用いた多角形の内外判定
本記事では角度を求める方法を2つ説明します。
数値計算を行い角度を計算する方法
仕組みやアルゴリズムは末尾に示したURLを参考に行いました。
仕組み
① 判定対象の点を始点とし、多角形の各辺の両端の点を終点とするベクトルを置きます。
ここでは下の写真のように2本のベクトル と
を置きます。

② 次にこの2本のベクトルが成す角を求めます。内積の式
からを求めます。
③ 次に、角度の向きを求めます。
先ほどの方法では2本のベクトルが成す角度はわかりましたが、反時計回りなのか、時計回りなのかを求めることはできていません。
そのため、❶~❸の操作を行います。
❷ ❶で求めたベクトルとカメラの視点方向のベクトルの内積を求めます。
この場合、時計回りであるものとして計算してほしいです。
2本のベクトルが逆方向であり、内積は負の値であることが分かります。
〇 また、点1、判定対象の点、点2の成す角を求める場合を考えます。
下図のような配置の場合、反時計回りであるものとして計算してほしいです。
2本のベクトルが同じ方向であり、内積は正の値であることが分かります。
④正負を考慮した角度の合計値を計算します。
このとき、多角形の内部にある場合は合計の角度が360度になります。

一方で上の写真の状態から下のように点を移動させ、多角形の外部に存在する場合を考えます。
③で角度に向きをつけたことにより下図のように合計の角度が0度になることが分かります。

そこで、360度ぴったりであれば多角形の内部、という判定が思いつきます。
しかし、そのように判定してしまうと浮動小数点の誤差が発生して正しく判定できないことがあります。
今回想定しているケースでは360度か0度にしかならないため、180度より大きければ多角形の内部、小さければ外部であると判定しました。
ソースコード
private bool IsPolygonInside(Vector3 mousePosition) { var count = _polygon.Vertices.Count; var totalAngle = 0f; for (int i = 0; i < count; i++) { var currentIndex = i; var nextIndex = (i + 1) % count; // 上図のa,bのベクトル var a = _polygon.Vertices[nextIndex] - mousePosition; var b = _polygon.Vertices[currentIndex] - mousePosition; // aとbのベクトルの余弦 var cosTheta = Vector3.Dot(a, b) / (a.magnitude * b.magnitude); // aとbのベクトルを挟んでいる角度 var theta = Mathf.Acos(cosTheta) * Mathf.Rad2Deg; // aとbのベクトルの外積 var cross = Vector3.Cross(a, b); // 正負がついた角度を得る var sign = Vector3.Dot(cross, _camera.transform.forward); if (sign > 0) theta = -theta; totalAngle += theta; } // 角度の合計が0度か360度のいずれかであり、360度の方であれば多角形の内部であるためtrueを返す return Mathf.Abs(totalAngle) >= 180; }
Unityで標準搭載されている機能を用いる方法
Unityが用意しているVector3.SignedAngleを用いると正負を考慮した角度が得られるため、thetaをシンプルに求めることも可能です。
var theta = Vector3.SignedAngle(a, b, _camera.transform.forward); totalAngle += theta;
参考URL
おわりに
KENTEMでは、様々な拠点でエンジニアを大募集しています! 建設×ITにご興味頂いた方は、是非下記のリンクからご応募ください。 recruit.kentem.jp career.kentem.jp