/// <summary> /// Superimposes ONE hole group's ledge groups. /// There isn't much else to say, so check out that disgusting number of input parameters. /// Hopefully nobody on earth ever looks at this except me. /// </summary> /// <param name="ledgeCollMap"></param> /// <param name="ledgeGroupMap"></param> /// <param name="baseTileMap"></param> /// <param name="superTileMap"></param> /// <param name="preTileMap"></param> /// <param name="tileGroup"></param> /// <param name="holeGroup"></param> /// <returns></returns> private static (Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >, Dictionary <LedgeGroupKey, int>) _SuperimposeHoleGroup( IDictionary <LedgeCollKey, EdgeCollection <TileEdge> > ledgeCollMap, IDictionary <LedgeGroupKey, int> ledgeGroupMap, TileMap baseTileMap, TileMap superTileMap, TileMap preTileMap, int tileGroup, int holeGroup) { var ledgeCollMapClone = new Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >(ledgeCollMap); var ledgeGroupMapClone = new Dictionary <LedgeGroupKey, int>(ledgeGroupMap); int superLedgeGroup = 0; //Once superimposed, # of ledge groups CAN change int maxLedgeGroups = ledgeGroupMap[new LedgeGroupKey(baseTileMap, tileGroup, holeGroup, preTileMap)]; for (int ledgeGroup = 0; ledgeGroup < maxLedgeGroups; ledgeGroup++) { EdgeCollection <TileEdge> ledgeColl = ledgeCollMap[new LedgeCollKey(baseTileMap, tileGroup, holeGroup, preTileMap, ledgeGroup)]; EdgeCollection <TileEdge> validLedges = _BuildHoleGroupValidLedges(ledgeColl, preTileMap, superTileMap); while (validLedges.Count > 0) { //repeatedly GetOrderedGroup() on valid_ledges until no ledges are left behind EdgeCollection <TileEdge> orderedLedges = validLedges.GetOrderedCollection(); var validSet = new HashSet <TileEdge>(validLedges); validSet.ExceptWith(orderedLedges); validLedges = new EdgeCollection <TileEdge>(validSet); ledgeCollMapClone.Add(new LedgeCollKey(baseTileMap, tileGroup, holeGroup, superTileMap, superLedgeGroup), orderedLedges); superLedgeGroup++; } } ledgeGroupMapClone.Add(new LedgeGroupKey(baseTileMap, tileGroup, holeGroup, superTileMap), superLedgeGroup); return(ledgeCollMapClone, ledgeGroupMapClone); }
/// <summary> /// Given a single perimeter, separate it into different ledge groups as appropriate, separate its Edges /// into different EdgeCollections, one for each ledge group, then return both as dictionaries. /// </summary> /// <param name="ledgeCollMap">Dict which maps ledge group to EdgeCollection.</param> /// <param name="ledgeGroupMap">Dict which maps superimposed TileMap to ledge group.</param> /// The above two are here for copy-and-return purposes (maintaining object immutability). /// <param name="tileMaps">List of all TileMaps.</param> /// <param name="tileMap">TileMap that ledges are being filled for.</param> ///<param name="perimeter">EdgeCollection holding perimeter which will be separated in this func.</param> /// <param name="tileGroup">TileGroup that ledges are being filled for.</param> /// <param name="holeGroup">HoleGroup that ledges are being filled for.</param> /// <returns>Two dictionaries matching the two input dicts but with the new ledge data added to each.</returns> private static (Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >, Dictionary <LedgeGroupKey, int>) _FillLedges( IDictionary <LedgeCollKey, EdgeCollection <TileEdge> > ledgeCollMap, IDictionary <LedgeGroupKey, int> ledgeGroupMap, TileMapList tileMaps, TileMap tileMap, EdgeCollection <TileEdge> perimeter, int tileGroup, int holeGroup) { var ledgeCollMapClone = new Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >(ledgeCollMap); var ledgeGroupMapClone = new Dictionary <LedgeGroupKey, int>(ledgeGroupMap); var ledges = new EdgeCollection <TileEdge>(); int ledgeGroup = 0; foreach (TileEdge edge in perimeter) { Vector2 currentTile = edge.tileCoords; int currentLayer = tileMap.ZIndex; Vector2 adjTile = _GetAdjacentLowerTile(tileMaps, edge, currentLayer); if (adjTile == currentTile) { //no adjacent tile exists ledges.Add(edge); } else if (ledges.Count > 0) { //gap in ledges, finish current ledge group and move to next one ledgeCollMapClone.Add(new LedgeCollKey(tileMap, tileGroup, holeGroup, tileMap, ledgeGroup), new EdgeCollection <TileEdge>(ledges.GetOrderedCollection())); ledgeGroup++; ledges = new EdgeCollection <TileEdge>(); } } if (ledges.Count > 0) { //store ledges if not done already ledgeCollMapClone.Add(new LedgeCollKey(tileMap, tileGroup, holeGroup, tileMap, ledgeGroup), new EdgeCollection <TileEdge>(ledges.GetOrderedCollection())); ledgeGroup++; } ledgeGroupMapClone.Add(new LedgeGroupKey(tileMap, tileGroup, holeGroup, tileMap), ledgeGroup); return(ledgeCollMapClone, ledgeGroupMapClone); }
/// <summary> /// Attempts to get a collection of edges in CCW order that is a small cycle. Uses PolygonSplittingGraphNode to /// extract small cycles. /// </summary> /// <param name="edgeColl"></param> /// <returns>CCW collection of edges that forms a small loop(s).</returns> public static List <EdgeCollection <TileEdge> > GetSmallClosedLoops(this EdgeCollection <TileEdge> edgeColl) { if (edgeColl is null) { throw new ArgumentNullException(nameof(edgeColl)); } EdgeCollection <TileEdge> connectedColl = edgeColl.GetOrderedCollection(); Dictionary <PolyEdge, TileEdge> polyToTileMap = _InitTilePolyBiDict(connectedColl); SortedList <int, PolygonSplittingGraphNode> polygonNodes = _CreatePolygonGraphSplittingNodes(polyToTileMap); var graph = new PolygonSplittingGraph(polygonNodes.Values.ToList()); List <ChordlessPolygon> smallLoops = graph.GetMinCycles(); var allTileEdgeLoops = new List <EdgeCollection <TileEdge> >(); foreach (ChordlessPolygon poly in smallLoops) { List <TileEdge> smallLoopsEdges = _ConvertChordlessPolygonToPolyEdges(poly.outerPerimUnsimplified, polyToTileMap); allTileEdgeLoops.Add(new EdgeCollection <TileEdge>(smallLoopsEdges)); } return(allTileEdgeLoops); }