private static int RemoveMidPoints(PolygonF polygon, int startIndexExclusive, int endIndexExclusive, bool forward) { if (forward) { if (startIndexExclusive < endIndexExclusive - 1) { PrepareForMidPointRemoval(polygon.Vertices, ref startIndexExclusive, ref endIndexExclusive); } } else { if (startIndexExclusive > endIndexExclusive + 1) { PrepareForMidPointRemoval(polygon.Vertices, ref endIndexExclusive, ref startIndexExclusive); } var tmp = endIndexExclusive; endIndexExclusive = startIndexExclusive; startIndexExclusive = tmp; } if (startIndexExclusive < endIndexExclusive) { polygon.Vertices.RemoveRange(startIndexExclusive + 1, endIndexExclusive - startIndexExclusive - 1); return(startIndexExclusive + 1); } else { polygon.Vertices.RemoveRange(startIndexExclusive + 1, polygon.Vertices.Count - startIndexExclusive - 1); polygon.Vertices.RemoveRange(0, endIndexExclusive); return(0); } }
private static void CompareAdjacency(PolygonF polygon, AdjacencyInfo adjacencyInfo, out int startIndex, out int endIndex, out bool forward) { var index2 = polygon.Vertices.IndexOf(adjacencyInfo.Vertices[1]); startIndex = polygon.Vertices.LastIndexOf(adjacencyInfo.Vertices[0], index2); if (startIndex == -1) { startIndex = polygon.Vertices.IndexOf(adjacencyInfo.Vertices[0], index2); if (startIndex > 0) { // if the one vertex is repeated multiple times, find the closest copy var tmp1 = polygon.Vertices.IndexOf(adjacencyInfo.Vertices[1], startIndex - 1); var tmp2 = polygon.Vertices.IndexOf(adjacencyInfo.Vertices[1], startIndex + 1); if (tmp1 != -1) { if (tmp2 != -1) { index2 = Math.Abs(startIndex - tmp1) < Math.Abs(startIndex - tmp2) ? tmp1 : tmp2; } else { index2 = tmp1; } } else if (tmp2 != -1) { index2 = tmp2; } } } endIndex = adjacencyInfo.Vertices.Length > 2 ? polygon.Vertices.IndexOf(adjacencyInfo.Vertices[adjacencyInfo.Vertices.Length - 1]) : index2; forward = Math.Abs(index2 - startIndex) == 1 ? startIndex <index2 : startIndex> index2; }
public AdjacencyInfo GetAdjacencyInfo(PolygonF other) { // if any two consecutive points from this match any two consecutive points on that, either way round, they're adjacent for (var startLocalIndex = Vertices.Count - 1; startLocalIndex >= 0; startLocalIndex--) { var firstVertex = Vertices[startLocalIndex]; var otherIndex = other.Vertices.IndexOf(firstVertex); if (otherIndex == -1) { continue; } var startOtherIndex = otherIndex; var sharedVertices = new List <PointF>(); sharedVertices.Add(firstVertex); // The two polygons share a vertex. See if they share 2 or more adjacent vertices! int testOtherIndex1 = WrapIndex(otherIndex, other.Vertices.Count, false); int testOtherIndex2 = WrapIndex(otherIndex, other.Vertices.Count, true); bool localGoingForwards = false, otherGoingForwards = false; int testLocalIndex = WrapIndex(startLocalIndex, Vertices.Count, localGoingForwards); var secondVertex = Vertices[testLocalIndex]; if (other.Vertices[testOtherIndex1] == secondVertex) { sharedVertices.Add(secondVertex); otherIndex = testOtherIndex1; otherGoingForwards = false; } else if (other.Vertices[testOtherIndex2] == secondVertex) { sharedVertices.Add(secondVertex); otherIndex = testOtherIndex2; otherGoingForwards = true; } else { localGoingForwards = true; testLocalIndex = WrapIndex(startLocalIndex, Vertices.Count, localGoingForwards); secondVertex = Vertices[testLocalIndex]; if (other.Vertices[testOtherIndex1] == secondVertex) { sharedVertices.Add(secondVertex); otherIndex = testOtherIndex1; otherGoingForwards = false; } else if (other.Vertices[testOtherIndex2] == secondVertex) { sharedVertices.Add(secondVertex); otherIndex = testOtherIndex2; otherGoingForwards = true; } else { continue; } } var lastLocalIndex = testLocalIndex; var lastOtherIndex = otherIndex; // These may share more than just two vertices, so keep going as long as they keep being shared. while (true) { testLocalIndex = WrapIndex(testLocalIndex, Vertices.Count, localGoingForwards); otherIndex = WrapIndex(otherIndex, other.Vertices.Count, otherGoingForwards); var localVertex = Vertices[testLocalIndex]; if (localVertex != other.Vertices[otherIndex]) { break; } sharedVertices.Add(localVertex); lastLocalIndex = testLocalIndex; lastOtherIndex = otherIndex; } // now try this same extension in the opposite direction too testLocalIndex = startLocalIndex; otherIndex = startOtherIndex; localGoingForwards = !localGoingForwards; otherGoingForwards = !otherGoingForwards; while (true) { testLocalIndex = WrapIndex(testLocalIndex, Vertices.Count, localGoingForwards); otherIndex = WrapIndex(otherIndex, other.Vertices.Count, otherGoingForwards); if (testLocalIndex == lastLocalIndex && otherIndex == lastOtherIndex) { break; } var localVertex = Vertices[testLocalIndex]; if (localVertex != other.Vertices[otherIndex]) { break; } sharedVertices.Insert(0, localVertex); } return(new AdjacencyInfo(sharedVertices)); } return(null); }
public void MergeWith(PolygonF otherPolygon, AdjacencyInfo adjacencyInfo) { if (Area == 0) { Vertices.Clear(); Vertices.AddRange(otherPolygon.Vertices); Area = otherPolygon.Area; return; } if (otherPolygon.Area == 0) { return; } Area += otherPolygon.Area; if (adjacencyInfo.Vertices.Length >= otherPolygon.Vertices.Count) { // Other polygon is entirely contained in this one. // If it's fully wrapped, remove all its vertices, otherwise remove all but the first and last adjacent vertices. bool firstLastEqual = adjacencyInfo.Vertices[0] == adjacencyInfo.Vertices[adjacencyInfo.Vertices.Length - 1]; var toRemove = adjacencyInfo.Vertices.Skip(1); if (!firstLastEqual) { toRemove = toRemove.Take(adjacencyInfo.Vertices.Length - 2); } foreach (var vertex in toRemove) { Vertices.Remove(vertex); } return; } else if (adjacencyInfo.Vertices.Length >= Vertices.Count) { // This polygon is entirely contained the other one one. // If it's fully wrapped, remove all its vertices, otherwise remove all but the first and last adjacent vertices. bool firstLastEqual = adjacencyInfo.Vertices[0] == adjacencyInfo.Vertices[adjacencyInfo.Vertices.Length - 1]; var toRemove = adjacencyInfo.Vertices.Skip(1); if (!firstLastEqual) { toRemove = toRemove.Take(adjacencyInfo.Vertices.Length - 2); } foreach (var vertex in toRemove) { otherPolygon.Vertices.Remove(vertex); } // and then use those on this one Vertices.Clear(); Vertices.AddRange(otherPolygon.Vertices); return; } CompareAdjacency(this, adjacencyInfo, out int localStartIndex, out int localEndIndex, out bool localForward); CompareAdjacency(otherPolygon, adjacencyInfo, out int otherStartIndex, out int otherEndIndex, out bool otherForward); // remove any "mid" points in the adjacent edge array from this polygon int insertIndex = RemoveMidPoints(this, localStartIndex, localEndIndex, localForward); // remove ALL points in the adjacent edge array from the other polygon otherStartIndex = WrapIndex(otherStartIndex, otherPolygon.Vertices.Count, !otherForward); otherEndIndex = WrapIndex(otherEndIndex, otherPolygon.Vertices.Count, otherForward); RemoveMidPoints(otherPolygon, otherStartIndex, otherEndIndex, otherForward); // add all remaining vertices from the other polgyon, reversing them if necessary if (localForward == otherForward) { otherPolygon.Vertices.Reverse(); } Vertices.InsertRange(insertIndex, otherPolygon.Vertices); }