4つの頂点座標からRectを求める【C#】
概要
与えられた複数の頂点(Vector2)が矩形(Rect)になるかどうかを判定して処理を分岐させたかったので、与えられた頂点からRectを求める関数を実装してみました。
実装
Rectを求める関数の実装:
using System.Collections.Generic; using UnityEngine; public static class RectUtility { /// <summary> /// 頂点が矩形を表すならtrueを返し、その情報をresultに格納する /// </summary> public static bool ToRect( out Rect result, IList<Vector2> vertices, float allowedError = 0 // 許容できる誤差 ) { result = default; if (vertices == null || vertices.Count != 4) { return false; } // 0番目の頂点から見て左 or 右にある頂点を特定 var h = GetHorizontalVertexIndex(vertices, 0, allowedError); if (h <= 0) { return false; } // 0番目の頂点から見て上 or 下にある頂点を特定 var v = GetVerticalVertexIndex(vertices, 0, allowedError); if (v <= 0) { return false; } // 0番目の頂点から見て斜めの位置にある頂点を特定 var d = GetDiagonalVertexIndex(vertices, 0, allowedError); if (d <= 0) { return false; } // 位置関係に問題がないかを確認 if (!( Equals(vertices[h].x, vertices[d].x, allowedError) && Equals(vertices[v].y, vertices[d].y, allowedError) )) { return false; } // 位置やサイズを設定 result = new Rect( Mathf.Min(vertices[h].x, vertices[0].x), Mathf.Min(vertices[v].y, vertices[0].y), Mathf.Abs(vertices[h].x - vertices[0].x), Mathf.Abs(vertices[v].y - vertices[0].y) ); return true; } /// <summary> /// selfIndex番目の頂点から斜めの位置にある頂点のIndexを取得する /// </summary> private static int GetDiagonalVertexIndex( IList<Vector2> vertices, int selfIndex, float allowedError ) { var self = vertices[selfIndex]; for (int i = 0; i < vertices.Count; ++i) { if (i == selfIndex) { continue; } if ( !Equals(vertices[i].x, self.x, allowedError) && !Equals(vertices[i].y, self.y, allowedError) ) { return i; } } return -1; } /// <summary> /// selfIndex番目の頂点から上 or 下の位置にある頂点のIndexを取得する /// </summary> private static int GetVerticalVertexIndex( IList<Vector2> vertices, int selfIndex, float allowedError ) { var self = vertices[selfIndex]; for (int i = 0; i < vertices.Count; ++i) { if (i == selfIndex) { continue; } if (Equals(vertices[i].x, self.x, allowedError)) { return i; } } return -1; } /// <summary> /// selfIndex番目の頂点から左 or 右の位置にある頂点のIndexを取得する /// </summary> private static int GetHorizontalVertexIndex( IList<Vector2> vertices, int selfIndex, float allowedError ) { var self = vertices[selfIndex]; for (int i = 0; i < vertices.Count; ++i) { if (i == selfIndex) { continue; } if (Equals(vertices[i].y, self.y, allowedError)) { return i; } } return -1; } /// <summary> /// 誤差を許容するfloatの比較 /// </summary> private static bool Equals(float a, float b, float allowedError) { return Mathf.Abs(a - b) <= allowedError; } }
使用例:
var list = new Vector2[] { new Vector2(1, -1), new Vector2(1, 0), new Vector2(3, -1), new Vector2(3, 0) }; if (RectUtility.ToRect(out Rect rect, list)) { Debug.Log(rect); }
ToRectの第三引数を指定すれば誤差を許容することもできます。
出力結果:
(x:1.00, y:-1.00, width:2.00, height:1.00)
※ 回転した状態の矩形には対応していません
環境
- Unity 2018.4.2f1
- VisualStudio 2019