/// <summary> /// 擬似半平面の作成 /// </summary> public ConvexPolygon Execute(Line line, Vector2 exsample) { //lineと各境界線の交差を調べる Vector2 p1 = Vector2.zero; bool i1 = border1.GetIntersectionPoint(line, ref p1); Vector2 p2 = Vector2.zero; bool i2 = border2.GetIntersectionPoint(line, ref p2); Vector2 p3 = Vector2.zero; bool i3 = border3.GetIntersectionPoint(line, ref p3); List <Vector2> vertices = new List <Vector2>(); //lineが境界線1及び2と交差する場合 if (i1 && i2 && Vector2.Distance(p1, p2) >= distanceThreshold) { //lineが境界線1及び2と交差する場合 if (GeomUtil.CCW(p1, boundary2, p2) * GeomUtil.CCW(p1, exsample, p2) > 0f) { //境界線2とexsampleがlineから見て同じ側にあるなら //境界点2を含む方の切断後頂点リストを生成 AddVertices(vertices, p1, boundary2, p2); } else { //境界点2を含まない方の切断後頂点リストを生成 AddVertices(vertices, p1, p2, boundary3, boundary1); } } else if (i2 && i3 && Vector2.Distance(p2, p3) >= distanceThreshold) { //lineが境界線2及び3と交差する場合 if (GeomUtil.CCW(p2, boundary3, p3) * GeomUtil.CCW(p2, exsample, p3) > 0f) { AddVertices(vertices, p2, boundary3, p3); } else { AddVertices(vertices, p2, p3, boundary1, boundary2); } } else if (i3 && i1 && Vector2.Distance(p3, p1) >= distanceThreshold) { //lineが境界線3及び1と交差する場合 if (GeomUtil.CCW(p3, boundary1, p1) * GeomUtil.CCW(p3, exsample, p1) > 0f) { AddVertices(vertices, p3, boundary1, p1); } else { AddVertices(vertices, p3, p1, boundary2, boundary3); } } else { throw new ArgumentException(); } //頂点リストから凸多角形を生成して返す return(new ConvexPolygon(vertices)); }
/// <summary> /// 初期化 /// </summary> private void Initialize(List <Vector2> points) { int size = points.Count; //角数が3未満の場合はエラー if (size < 3) { throw new ArgumentException(); } this.vertices = points; //凸性判定 float baseCCW = 0f; for (int i = 0; i < size; ++i) { Vector2 p0 = points[i]; Vector2 p1 = points[(i + 1) % size]; Vector2 p2 = points[(i + 2) % size]; //CCW値の計算 float ccw = GeomUtil.CCW(p0, p1, p2); if (baseCCW == 0f && ccw != 0f) { baseCCW = ccw; } if (ccw * baseCCW < 0) { throw new ArgumentException("Polygon is not convex."); } } if (baseCCW > 0f) { rotation = Rotation.CCW; } else { rotation = Rotation.CW; } //線分の登録 edges = new List <LineSegment>(); for (int i = 0; i < size; ++i) { Vector2 p1 = points[i]; Vector2 p2 = points[(i + 1) % size]; //p1の次の頂点 //2つ頂点から辺の線分を作成して登録 edges.Add(new LineSegment(p1, p2)); } }
/// <summary> /// 初期化 /// </summary> private void Initialize(List <Vector2> points) { int size = points.Count; //角数が3未満の場合はエラー if (size < 3) { throw new ArgumentException(); } //最も遠い座標のインデックスを求める int index = 0; float maxDistance = 0f; float distance = 0f; for (int i = 0; i < size; ++i) { distance = points[i].magnitude; if (distance > maxDistance) { maxDistance = distance; index = i; } } mostFarIndex = index; //最も遠い座標の外積を求める Vector2 p0 = points[(index + (size - 1)) % size]; Vector2 p1 = points[index]; Vector2 p2 = points[(index + 1) % size]; mostFarCross = GeomUtil.CCW(p0, p1, p2); //頂点リストの作成 vertices = new List <PolygonVertex>(); for (int i = 0; i < size; ++i) { p0 = points[(i + (size - 1)) % size]; p1 = points[i]; p2 = points[(i + 1) % size]; float cross = GeomUtil.CCW(p0, p1, p2); float angle = GeomUtil.TwoVectorAngle(p1, p0, p2); if (cross * mostFarCross < 0f) { angle = 360f - angle; } vertices.Add(new PolygonVertex(p1, angle, i)); } }
private void UpdateLine() { if (line == null) { return; } int size = vertices.Count; if (size < 3) { return; } line.SetVertexCount(vertices.Count + 1); float baseCCW = GeomUtil.CCW(vertices [0].position, vertices [1].position, vertices [2].position); bool notConvex = false; for (int i = 0; i < size; ++i) { line.SetPosition(i, vertices [i].position); //凸性判定 Vector2 p1 = vertices [i].position; Vector2 p2 = vertices [(i + 1) % size].position; Vector2 p3 = vertices [(i + 2) % size].position; float ccw = GeomUtil.CCW(p1, p2, p3); if (baseCCW * ccw <= 0) { notConvex = true; } } line.SetPosition(size, vertices [0].position); if (notConvex) { line.SetColors(Color.red, Color.red); } else { line.SetColors(Color.white, Color.white); } }
private void Update() { float ccw = GeomUtil.CCW(p1.position, p2.position, p3.position); //Line Color Color c = Color.white; if (ccw < 0) { c = Color.blue; } else if (ccw > 0) { c = Color.red; } line.SetColors(c, c); //Draw Line line.SetVertexCount(3); line.SetPosition(0, p1.position); line.SetPosition(1, p2.position); line.SetPosition(2, p3.position); }
/// <summary> /// 簡易メッシュ変換 /// </summary> public EasyMesh ToEasyMesh(Color color) { int size = vertices.Count; Vector3[] verts = new Vector3[size]; Color[] colors = new Color[size]; int[] indices = new int[(size - 2) * 3]; //一時データと準備 List <PolygonVertex> temp = new List <PolygonVertex>(); for (int i = 0; i < size; ++i) { temp.Add(new PolygonVertex(vertices[i])); verts[i] = vertices[i].point; colors[i] = color; } //頂点処理ループ int index = mostFarIndex; int indicesCount = 0; Vector2 p0, p1, p2; int i0, i1, i2; int processNum = 0; int maxProcessNum = temp.Count * 2; while (temp.Count > 3 && processNum < maxProcessNum) { size = temp.Count; i0 = (index + size - 1) % size; p0 = temp[i0].point; i1 = index; p1 = temp[i1].point; i2 = (index + 1) % size; p2 = temp[i2].point; //外積の向きを調べる float cross = GeomUtil.CCW(p0, p1, p2); if (cross * mostFarCross >= 0f) { //三角形の中に他の頂点が混じってないか確認 bool contains = false; for (int i = 2; i < size - 1; ++i) { int j = (index + i) % size; if (GeomUtil.TriangleInPoint(p0, p1, p2, temp[j].point)) { contains = true; break; } } //インデックスの追加 if (!contains) { //回転方向によってポリゴンの順序が反転する if (mostFarCross > 0f) { indices[indicesCount + 0] = temp[i0].index; indices[indicesCount + 1] = temp[i2].index; indices[indicesCount + 2] = temp[i1].index; } else { indices[indicesCount + 0] = temp[i0].index; indices[indicesCount + 1] = temp[i1].index; indices[indicesCount + 2] = temp[i2].index; } indicesCount += 3; temp.RemoveAt(i1); size--; } } index = (index + 1) % size; ++processNum; } if (processNum >= maxProcessNum) { throw new ArgumentException("Not Create Mesh."); } //最後の3点を加える indices[indicesCount + 0] = temp[0].index; indices[indicesCount + 1] = temp[2].index; indices[indicesCount + 2] = temp[1].index; return(new EasyMesh(verts, colors, indices)); }
/// <summary> /// 簡易メッシュ変換コルーチン /// </summary> public IEnumerator CoToEasyMesh(Color color, Action <EasyMesh> updateCallback, Action <EasyMesh> endCallback = null, float wait = 0.1f) { int size = vertices.Count; Vector3[] verts = new Vector3[size]; Color[] colors = new Color[size]; int[] indices = new int[(size - 2) * 3]; //一時データと準備 List <PolygonVertex> temp = new List <PolygonVertex>(); for (int i = 0; i < size; ++i) { temp.Add(new PolygonVertex(vertices[i])); verts[i] = vertices[i].point; colors[i] = color; } //頂点処理ループ int index = mostFarIndex; int indicesCount = 0; Vector2 p0, p1, p2; int i0, i1, i2; int processNum = 0; int maxProcessNum = temp.Count * 2; while (temp.Count > 3 && processNum < maxProcessNum) { size = temp.Count; i0 = (index + size - 1) % size; p0 = temp[i0].point; i1 = index; p1 = temp[i1].point; i2 = (index + 1) % size; p2 = temp[i2].point; //外積の向きを調べる float cross = GeomUtil.CCW(p0, p1, p2); if (cross * mostFarCross >= 0f) { //三角形の中に他の頂点が混じってないか確認 bool contains = false; for (int i = 2; i < size - 1; ++i) { int j = (index + i) % size; if (GeomUtil.TriangleInPoint(p0, p1, p2, temp[j].point)) { contains = true; break; } } //インデックスの追加 if (!contains) { indices[indicesCount + 0] = temp[i0].index; indices[indicesCount + 1] = temp[i1].index; indices[indicesCount + 2] = temp[i2].index; indicesCount += 3; temp.RemoveAt(i1); size--; yield return(new WaitForSeconds(wait)); //コールバック if (updateCallback != null) { updateCallback(new EasyMesh(verts, colors, indices)); } } } index = (index + 1) % size; ++processNum; } if (processNum >= maxProcessNum) { throw new ArgumentException("Not create mesh"); } //最後の3点を加える indices[indicesCount + 0] = temp[0].index; indices[indicesCount + 1] = temp[1].index; indices[indicesCount + 2] = temp[2].index; yield return(new WaitForSeconds(wait)); //コールバック if (endCallback != null) { endCallback(new EasyMesh(verts, colors, indices)); } }