/// Разделить текущее ребро на два, очистив при этом инфу о текущем ребре internal graphLine[] Split(graphPoint graphPoint) { var edge1 = new graphLine { a = a, b = b}; var edge2 = new graphLine { a = a, b = b }; edge1.p1 = p1; edge1.p2 = graphPoint; edge2.p1 = graphPoint; edge2.p2 = p2; p1 = null; p2 = null; edge1.aMain = aMain; edge2.aMain = aMain; return new[] { edge1, edge2 }; }
public static graphLine[] calculateLines(Vector3[] aPoints, Vector3[] bPoints) { //Create triangles and reverse if unclockwise var aPoints2D = getClockwisePoint2D(aPoints); var bPoints2D = getClockwisePoint2D(bPoints); //Create edges var aEdges = new List<graphLine>(aPoints.Length); for (int i = 0; i < aPoints2D.Length; i++) { var edge = new graphLine { aMain = true, a = true, p1 = aPoints2D[i], p2 = aPoints2D[(i + 1) % aPoints2D.Length] }; aEdges.Add(edge); } var bEdges = new List<graphLine>(bPoints.Length); for (int i = 0; i < bPoints2D.Length; i++) { var edge = new graphLine { aMain = false, b = true, p1 = bPoints2D[i], p2 = bPoints2D[(i + 1) % bPoints2D.Length] }; bEdges.Add(edge); } //Phase 1: Split & cross int aFirstCrossIndex = -1, bFirstCrossIndex = -1; for (int i1 = 0; i1 < aEdges.Count; i1++) { for (int i2 = 0; i2 < bEdges.Count; i2++) { graphLine[] aOut, bOut; if (_detectIntersectionsIfNeed(aEdges[i1], bEdges[i2], out aOut, out bOut)) { aEdges.RemoveAt(i1); bEdges.RemoveAt(i2); aEdges.InsertRange(i1, aOut); bEdges.InsertRange(i2, bOut); aFirstCrossIndex = i1 + 1; bFirstCrossIndex = i2 + 1; i2++; } } } //Phase 2: Fill if (aFirstCrossIndex != -1) { bool cursor = aEdges[aFirstCrossIndex].b; for (int i = 0; i < aEdges.Count; i++) { var index = (i + aFirstCrossIndex)%aEdges.Count; var edge = aEdges[index]; edge.b = cursor; if (edge.p2.isCross) cursor = !cursor; } } if (bFirstCrossIndex != -1) { bool cursor = bEdges[bFirstCrossIndex].a; for (int i = 0; i < bEdges.Count; i++) { var index = (i + bFirstCrossIndex) % bEdges.Count; var edge = bEdges[index]; edge.a = cursor; if (edge.p2.isCross) cursor = !cursor; } } if (aFirstCrossIndex == -1 && bFirstCrossIndex == -1) { //contains triangle area var aV2 = aPoints.Select(x => (Vector2) x).ToArray(); var bV2 = bPoints.Select(x => (Vector2) x).ToArray(); if (isConvexPolygon(aV2) && isConvexPolygon(bV2)) { if (contain.convex(aV2, bV2[0], true)) { bEdges.ForEach(x => x.a = true); var advancedEdge = new graphLine { a = true, aMain = true, b = false, p1 = MaxYItem(aPoints2D), p2 = MaxYItem(bPoints2D)}; aEdges.Add(advancedEdge); } else if (contain.convex(bV2, aV2[0], true)) { aEdges.ForEach(x => x.b = true); var advancedEdge = new graphLine { b = true, aMain = false, a = false, p1 = MaxYItem(aPoints2D), p2 = MaxYItem(bPoints2D)}; bEdges.Add(advancedEdge); } } else //if not convex { if (contain.nonzeroRule(aV2, bV2[0])) { bEdges.ForEach(x => x.a = true); var advancedEdge = new graphLine { a = true, aMain = true, b = false, p1 = MaxYItem(aPoints2D), p2 = MaxYItem(bPoints2D) }; aEdges.Add(advancedEdge); } else if (contain.nonzeroRule(bV2, aV2[0])) { aEdges.ForEach(x => x.b = true); var advancedEdge = new graphLine { b = true, aMain = false, a = false, p1 = MaxYItem(aPoints2D), p2 = MaxYItem(bPoints2D) }; bEdges.Add(advancedEdge); } } } return aEdges.Concat(bEdges).ToArray(); }
/// Проверяет факт пересечения, и возвращает помеченные ребра, если пересечение есть private static bool _detectIntersectionsIfNeed(graphLine a, graphLine b, out graphLine[] aOut, out graphLine[] bOut) { var a1 = a.p1.point; var a2 = a.p2.point; var b1 = b.p1.point; var b2 = b.p2.point; Vector2 cross; if (m.intersect.trySegments(a1, a2, b1, b2, false, out cross)) { var B1_isRight_of_A1A2 = isRight(a1, a2, b1); var A1_isRight_of_B1B2 = isRight(b1, b2, a1); float z; if (a1.z != 0 && a2.z != 0) { var fullDistance = ((Vector2) a2 - (Vector2) a1).magnitude; var partDistance = (cross - (Vector2) a1).magnitude; var t = partDistance/fullDistance; z = Mathf.Lerp(a1.z, a2.z, t); } else z = 0f; var crossEx = new graphPoint(new Vector3(cross.x, cross.y, z), true); aOut = a.Split(crossEx); bOut = b.Split(crossEx); aOut[0].b = A1_isRight_of_B1B2; aOut[1].b = !A1_isRight_of_B1B2; bOut[0].a = B1_isRight_of_A1A2; bOut[1].a = !B1_isRight_of_A1A2; return true; } aOut = null; bOut = null; return false; }
public static List<polygon> calculatePolygons(graphLine[] edges) { var directedLines = new directedLine[edges.Length*2]; //Создаем вектора for (int i = 0; i < edges.Length; i++) { var edge = edges[i]; edge.ab = new directedLine { a = edge.p1, b = edge.p2, line = edge }; edge.ba = new directedLine { a = edge.p2, b = edge.p1, line = edge }; directedLines[i] = edge.ab; directedLines[edges.Length + i] = edge.ba; } //Связываем правые стороны векторов for (int i = 0; i < edges.Length; i++) { var edge = edges[i]; directedLines[i] = edge.ab; directedLines[edges.Length + i] = edge.ba; var nextAEdge = edge.GetRightEdge(edge.p1); var nextBEdge = edge.GetRightEdge(edge.p2); edge.ba.nextRightLine = nextAEdge.p1 == edge.p1 ? nextAEdge.ab : nextAEdge.ba; edge.ab.nextRightLine = nextBEdge.p1 == edge.p2 ? nextBEdge.ab : nextBEdge.ba; } //Находим полигоны var polygons = new List<polygon>(); for (int i = 0; i < directedLines.Length; i++) { var dir = directedLines[i]; if (dir.used) continue; var path = new List<directedLine>(); int error = 0; while (true) { dir.used = true; path.Add(dir); if (dir.nextRightLine.used)//exit { var firstIndex = path.IndexOf(dir.nextRightLine); if (firstIndex == -1) break; var polygon = new polygon(); for (int j = firstIndex; j < path.Count; j++) { var e = path[j].line; polygon.a &= e.a; polygon.b &= e.b; polygon.points.Add(path[j].b.point); } if (area.simplePolygon(polygon.points.Select(x => (Vector2)x).ToArray()) < 0f && (polygon.a || polygon.b)) polygons.Add(polygon); break; } dir = dir.nextRightLine; if (error >= directedLines.Length) { Debug.LogWarning("Error"); break; } error++; } } return polygons; }