// 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.
                allsides.Sort(new SidedefAngleSorter(history[history.Count - 1], fromhere));
            }

            // 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;
                var nextpath   = new SidedefsTracePath(history, s);
                var nextvertex = (s.Line.Start == fromhere ? s.Line.End : s.Line.Start);

                var result = DoTracePath(nextpath, nextvertex, findme, sector, sides);
                if (result != null)
                {
                    return(result);
                }
            }

            // Nothing found
            return(null);
        }
Exemple #3
0
 // Constructor
 public SidedefsTracePath(SidedefsTracePath p, Sidedef add) : base(p)
 {
     // Initialize
     base.Add(add);
 }