예제 #1
0
    // 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);
    }
 // Constructor
 public SidedefsTracePath(SidedefsTracePath p, Sidedef add) : base(p)
 {
     // Initialize
     base.Add(add);
 }
예제 #3
0
    // 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);
    }