// This traces sector lines to create a polygon tree private static List <EarClipPolygon> DoTrace(Sector s) { Dictionary <Sidedef, bool> todosides = new Dictionary <Sidedef, bool>(s.Sidedefs.Count); Dictionary <Vertex, Vertex> ignores = new Dictionary <Vertex, Vertex>(); List <EarClipPolygon> root = new List <EarClipPolygon>(); // Fill the dictionary // The bool value is used to indicate lines which has been visited in the trace foreach (Sidedef sd in s.Sidedefs) { todosides.Add(sd, false); } // First remove all sides that refer to the same sector on both sides of the line RemoveDoubleSidedefReferences(todosides, s.Sidedefs); // Continue until all sidedefs have been processed while (todosides.Count > 0) { // Reset all visited indicators foreach (Sidedef sd in s.Sidedefs) { if (todosides.ContainsKey(sd)) { todosides[sd] = false; } } // Find the right-most vertex to start a trace with. // This guarantees that we start out with an outer polygon and we just // have to check if it is inside a previously found polygon. Vertex start = FindRightMostVertex(todosides, ignores); // No more possible start vertex found? // Then leave with what we have up till now. if (start == null) { break; } // Trace to find a polygon SidedefsTracePath path = DoTracePath(new SidedefsTracePath(), start, null, s, todosides); // If tracing is not possible (sector not closed?) // then add the start to the ignore list and try again later if (path == null) { // Ignore vertex as start ignores.Add(start, start); } else { // Remove the sides found in the path foreach (Sidedef sd in path) { todosides.Remove(sd); } // Create the polygon EarClipPolygon newpoly = path.MakePolygon(); // Determine where this polygon goes in our tree foreach (EarClipPolygon p in root) { // Insert if it belongs as a child if (p.InsertChild(newpoly)) { // Done newpoly = null; break; } } // Still not inserted in our tree? if (newpoly != null) { // Then add it at root level as outer polygon newpoly.Inner = false; root.Add(newpoly); } } } // Return result return(root); }
// This recursively traces a path // Returns the resulting TracePath when the search is complete // or returns null when no path found. private static SidedefsTracePath DoTracePath(SidedefsTracePath history, Vertex fromhere, Vertex findme, Sector sector, Dictionary <Sidedef, bool> sides) { // Found the vertex we are tracing to? if (fromhere == findme) { return(history); } // On the first run, findme is null (otherwise the trace would end // immeditely when it starts) so set findme here on the first run. if (findme == null) { findme = fromhere; } // Make a list of sides referring to the same sector List <Sidedef> allsides = new List <Sidedef>(fromhere.Linedefs.Count * 2); foreach (Linedef l in fromhere.Linedefs) { // Should we go along the front or back side? // This is very important for clockwise polygon orientation! if (l.Start == fromhere) { // Front side of line connected to sector? if ((l.Front != null) && (l.Front.Sector == sector)) { // Visit here when not visited yet if (sides.ContainsKey(l.Front) && !sides[l.Front]) { allsides.Add(l.Front); } } } else { // Back side of line connected to sector? if ((l.Back != null) && (l.Back.Sector == sector)) { // Visit here when not visited yet if (sides.ContainsKey(l.Back) && !sides[l.Back]) { allsides.Add(l.Back); } } } } // Previous line available? if (history.Count > 0) { // This is done to ensure the tracing works along vertices that are shared by // more than 2 lines/sides of the same sector. We must continue tracing along // the first next smallest delta angle! This sorts the smallest delta angle to // the top of the list. SidedefAngleSorter sorter = new SidedefAngleSorter(history[history.Count - 1], fromhere); allsides.Sort(sorter); } // Go for all lines connected to this vertex foreach (Sidedef s in allsides) { // Mark sidedef as visited and move to next vertex sides[s] = true; SidedefsTracePath nextpath = new SidedefsTracePath(history, s); Vertex nextvertex = (s.Line.Start == fromhere ? s.Line.End : s.Line.Start); SidedefsTracePath result = DoTracePath(nextpath, nextvertex, findme, sector, sides); if (result != null) { return(result); } } // Nothing found return(null); }
// Constructor public SidedefsTracePath(SidedefsTracePath p, Sidedef add) : base(p) { // Initialize base.Add(add); }