Example #1
0
        /// <summary>
        /// Checks if a given graph is planar and provides a planar embedding if so.
        /// </summary>
        /// <param name="graph">Graph</param>
        /// <param name="embedding">Planar embedding if a given graph is planar, null otherwise</param>
        /// <returns>True if planar, false otherwise</returns>
        public bool IsPlanar(IGraph <T> graph, out PlanarEmbedding <T> embedding)
        {
            // Transforms input graph
            TransformGraph(graph);

            // Init helper collections
            selfLoopsNew  = new List <IEdge <Vertex <T> > >();
            mergeStackNew = new Stack <MergeInfo>();

            // Use DFS traversal to add basic information to each of the vertices
            var visitor = new DFSTraversalVisitor <T>();

            DFSTraversal.Traverse(transformedGraph, visitor);

            // Sort vertices by dfs number ASC
            verticesByDFSNumberNew = BucketSort.Sort(transformedGraph.Vertices, x => x.DFSNumber, transformedGraph.VerticesCount);

            // Sort vertices by low point ASC
            verticesByLowPointNew = BucketSort.Sort(transformedGraph.Vertices, x => x.LowPoint, transformedGraph.VerticesCount);

            // Init vertex fields
            foreach (var vertex in transformedGraph.Vertices)
            {
                vertex.BackEdges    = new List <IEdge <Vertex <T> > >();
                vertex.Visited      = int.MaxValue;
                vertex.BackedgeFlag = transformedGraph.VerticesCount + 1;
                vertex.Flipped      = false;

                var dfsParent = vertex.Parent;

                if (vertex != dfsParent)
                {
                    var parentEdge = vertex.DFSEdge;
                    vertex.FaceHandle     = new FaceHandle <Vertex <T> >(vertex, parentEdge);
                    vertex.DFSChildHandle = new FaceHandle <Vertex <T> >(dfsParent, parentEdge);
                }
                else
                {
                    vertex.FaceHandle     = new FaceHandle <Vertex <T> >(vertex, (Vertex <T>)null);             // TODO: change
                    vertex.DFSChildHandle = new FaceHandle <Vertex <T> >(dfsParent, (Vertex <T>)null);
                }

                vertex.CanonicalDFSChild     = vertex;
                vertex.PertinentRoots        = new LinkedList <FaceHandle <Vertex <T> > >();
                vertex.SeparatedDFSChildList = new LinkedList <Vertex <T> >();
            }

            // Init separated dfs child lists
            //
            // Original Boost comment:
            // We need to create a list of not-yet-merged depth-first children for
            // each vertex that will be updated as bicomps get merged. We sort each
            // list by ascending lowpoint, which allows the externally_active
            // function to run in constant time, and we keep a pointer to each
            // vertex's representation in its parent's list, which allows merging
            //in constant time.
            foreach (var vertex in verticesByLowPointNew)
            {
                var dfsParent = vertex.Parent;

                if (vertex != dfsParent)
                {
                    var node = dfsParent.SeparatedDFSChildList.AddLast(vertex);
                    vertex.SeparatedNodeInParentList = node;
                }
            }

            // Call the main algorithm
            var isPlanar = IsPlanar();

            if (!isPlanar)
            {
                embedding = null;
                return(false);
            }

            embedding = GetPlanarEmbedding();
            return(true);
        }
Example #2
0
        /// <summary>
        /// Traverses planar face of a given embedding.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="graph"></param>
        /// <param name="embedding"></param>
        /// <param name="visitor"></param>
        public static void Traverse <T>(IGraph <T> graph, PlanarEmbedding <T> embedding, IPlanarFaceTraversalVisitor <T> visitor)
        {
            var nextEdge = new Dictionary <IEdge <T>, Dictionary <T, IEdge <T> > >();
            var visited  = new Dictionary <IEdge <T>, HashSet <T> >();

            foreach (var edge in graph.Edges)
            {
                nextEdge[edge] = new Dictionary <T, IEdge <T> >();
                visited[edge]  = new HashSet <T>();
            }

            visitor.BeginTraversal();

            foreach (var vertex in graph.Vertices)
            {
                var vertexEmbedding = embedding.GetEdgesAroundVertex(vertex);

                for (var i = 0; i < vertexEmbedding.Count; i++)
                {
                    var edge          = vertexEmbedding[i];
                    var followingEdge = i != vertexEmbedding.Count - 1 ? vertexEmbedding[i + 1] : vertexEmbedding[0];

                    if (nextEdge.ContainsKey(edge))
                    {
                        nextEdge[edge][vertex] = followingEdge;
                    }
                    else
                    {
                        nextEdge[SwitchEdge(edge)][vertex] = followingEdge;
                    }
                }
            }

            var selfLoops      = new List <IEdge <T> >();
            var edgesCache     = new List <IEdge <T> >();
            var verticesInEdge = new List <T>();

            foreach (var edge in graph.Edges)
            {
                edgesCache.Add(edge);

                if (edge.Source.Equals(edge.Target))
                {
                    selfLoops.Add(edge);
                }
            }

            foreach (var edge in edgesCache)
            {
                var e = edge;
                verticesInEdge.Clear();
                verticesInEdge.Add(e.Source);
                verticesInEdge.Add(e.Target);

                foreach (var vertex in verticesInEdge)
                {
                    var v           = vertex;
                    var edgeVisited = GetCorrectEdgeValue(visited, e);
                    var beginFace   = false;

                    if (!edgeVisited.Contains(v))
                    {
                        visitor.BeginFace();
                        beginFace = true;
                    }

                    while (!edgeVisited.Contains(v))
                    {
                        visitor.NextVertex(v);
                        visitor.NextEdge(e);
                        edgeVisited.Add(v);

                        v           = e.Source.Equals(v) ? e.Target : e.Source;
                        e           = GetCorrectEdgeValue(nextEdge, e)[v];
                        edgeVisited = GetCorrectEdgeValue(visited, e);
                    }

                    if (beginFace)
                    {
                        visitor.EndFace();
                    }
                }
            }

            // Iterate over all self-loops, visiting them once separately
            // (they've already been visited once, this visitation is for
            // the "inside" of the self-loop)

            foreach (var edge in selfLoops)
            {
                visitor.BeginFace();
                visitor.NextEdge(edge);
                visitor.NextVertex(edge.Source);
                visitor.EndFace();
            }

            visitor.EndTraversal();
        }