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 void MergeWithDistrict(DistrictGenerator other, AdjacencyInfo adjacency) { MergeWith(other, adjacency); foreach (var yetAnother in other.AdjacentDistricts) { yetAnother.AdjacentDistricts.Remove(other); if (yetAnother != this && !yetAnother.AdjacentDistricts.Contains(this)) { yetAnother.AdjacentDistricts.Add(this); } } var toAdd = other.AdjacentDistricts .Where(d => d != this && !AdjacentDistricts.Contains(d)); foreach (var district in toAdd) { AdjacentDistricts.Add(district); } }
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); }
private bool MergeDistricts(List <DistrictGenerator> districts, Func <DistrictGenerator, bool> districtFilter, Func <DistrictGenerator, bool> targetFilter) { bool addedAny = false; for (int iPolygon = 0; iPolygon < districts.Count; iPolygon++) { var testPolygon = districts[iPolygon]; if (!districtFilter(testPolygon)) { continue; } // This polygon should be merged onto the adjacent polygon that shares its longest edge AdjacencyInfo bestAdjacency = null; DistrictGenerator bestPolygon = null; foreach (var polygon in districts) { if (polygon == testPolygon) { continue; // don't merge with self } if (!targetFilter(polygon)) { continue; } if (!testPolygon.AdjacentDistricts.Contains(polygon)) { continue; // filter out non-adjacent districts quickly } var adjacency = testPolygon.GetAdjacencyInfo(polygon); if (adjacency == null) { continue; // don't merge if not adjacent } if (bestAdjacency != null && adjacency.Length < bestAdjacency.Length) { continue; // don't merge if we already have a polygon we share longer edge(s) with } bestAdjacency = adjacency; bestPolygon = polygon; } if (bestPolygon == null) { continue; } bestPolygon.MergeWithDistrict(testPolygon, bestAdjacency); districts.RemoveAt(iPolygon); iPolygon--; addedAny = true; } return(addedAny); }