private void SecondWalk(TVertex v, TVertex r, double x, double y, float l, float t)
        {
            Point pos = new Point(x, y);

            VertexPositions[v] = pos;
            visitedVertices.Add(v);
            BalloonData data = datas[v];

            float dd     = l * data.d;
            float p      = (float)(t + Math.PI);
            int   degree = VisitedGraph.OutDegree(v);
            float fs     = (degree == 0 ? 0 : data.f / degree);
            float pr     = 0;

            foreach (var edge in VisitedGraph.OutEdges(v))
            {
                var otherVertex = edge.Target;
                if (visitedVertices.Contains(otherVertex))
                {
                    continue;
                }

                var   otherData = datas[otherVertex];
                float aa        = data.c * otherData.a;
                float rr        = (float)(data.d * Math.Tan(aa) / (1 - Math.Tan(aa)));
                p += pr + aa + fs;

                float xx = (float)((l * rr + dd) * Math.Cos(p));
                float yy = (float)((l * rr + dd) * Math.Sign(p));
                pr = aa;;
                SecondWalk(otherVertex, v, x + xx, y + yy, l * data.c, p);
            }
        }
        //=======================================================================
        // The main purpose of this routine is to set distance[v]
        // to the smallest value allowed by the valid labeling constraints,
        // which are:
        // distance[t] = 0
        // distance[u] <= distance[v] + 1   for every residual edge (u,v)
        //
        private int RelabelDistance(IVertex u)
        {
            int minEdges = 0;

            workSinceLastUpdate += beta;

            int minDistance = VisitedGraph.VerticesCount;

            distances[u] = minDistance;

            // Examine the residual out-edges of vertex i, choosing the
            // edge whose target vertex has the minimal distance.
            for (int ai = 0; ai < VisitedGraph.OutDegree(u); ai++)
            {
                ++workSinceLastUpdate;
                IEdge   a = VisitedGraph.OutEdges(u)[ai];
                IVertex v = a.Target;
                if (IsResidualEdge(a) && distances[v] < minDistance)
                {
                    minDistance = distances[v];
                    minEdges    = ai;
                }
            }
            ++minDistance;

            if (minDistance < n)
            {
                distances[u] = minDistance;                             // this is the main action
                current[u]   = minEdges;
                maxDistance  = Math.Max(minDistance, maxDistance);
            }
            return(minDistance);
        }
        private void SecondWalk([NotNull] TVertex vertex, double x, double y, float l, float t)
        {
            Debug.Assert(vertex != null);

            var position = new Point(x, y);

            VerticesPositions[vertex] = position;
            _visitedVertices.Add(vertex);
            BalloonData data = _data[vertex];

            float dd     = l * data.D;
            float p      = (float)(t + Math.PI);
            int   degree = VisitedGraph.OutDegree(vertex);
            float fs     = degree == 0 ? 0 : data.F / degree;
            float pr     = 0;

            foreach (TEdge edge in VisitedGraph.OutEdges(vertex))
            {
                TVertex otherVertex = edge.Target;
                if (_visitedVertices.Contains(otherVertex))
                {
                    continue;
                }

                BalloonData otherData = _data[otherVertex];
                float       aa        = data.C * otherData.A;
                float       rr        = (float)(data.D * Math.Tan(aa) / (1 - Math.Tan(aa)));
                p += pr + aa + fs;

                float xx = (float)((l * rr + dd) * Math.Cos(p));
                float yy = (l * rr + dd) * Math.Sign(p);
                pr = aa;
                SecondWalk(otherVertex, x + xx, y + yy, l * data.C, p);
            }
        }
        public override void Compute(CancellationToken cancellationToken)
        {
            Sizes = new Dictionary <TVertex, Size>(VertexSizes);
            if (Parameters.Direction == LayoutDirection.LeftToRight || Parameters.Direction == LayoutDirection.RightToLeft)
            {
                //change the sizes
                foreach (var sizePair in Sizes.ToArray())
                {
                    Sizes[sizePair.Key] = new Size(sizePair.Value.Height, sizePair.Value.Width);
                }
            }

            if (Parameters.Direction == LayoutDirection.RightToLeft || Parameters.Direction == LayoutDirection.BottomToTop)
            {
                _direction = -1;
            }
            else
            {
                _direction = 1;
            }

            GenerateSpanningTree(cancellationToken);
            //DoWidthAndHeightOptimization();

            var graph = new UndirectedBidirectionalGraph <TVertex, TEdge>(VisitedGraph);
            var scca  = new QuickGraph.Algorithms.ConnectedComponents.ConnectedComponentsAlgorithm <TVertex, TEdge>(graph);

            scca.Compute();

            // Order connected components by their vertices count
            // Group vertices by connected component (they should be placed together)
            // Order vertices inside each conected component by in degree first, then out dregee
            // (roots should be placed in the first layer and leafs in the last layer)
            var components = from e in scca.Components
                             group e.Key by e.Value into c
                             orderby c.Count() descending
                             select c;

            foreach (var c in components)
            {
                var firstOfComponent = true;
                var vertices         = from v in c
                                       orderby VisitedGraph.InDegree(v), VisitedGraph.OutDegree(v) descending
                select v;

                foreach (var source in vertices)
                {
                    CalculatePosition(source, null, 0, firstOfComponent);

                    if (firstOfComponent)
                    {
                        firstOfComponent = false;
                    }
                }
            }

            AssignPositions(cancellationToken);
        }
        //=======================================================================
        // This function is called "push" in Goldberg's h_prf implementation,
        // but it is called "discharge" in the paper and in hi_pr.c.
        private void Discharge(IVertex u)
        {
            while (true)
            {
                int ai;
                for (ai = current[u]; ai < VisitedGraph.OutDegree(u); ai++)
                {
                    IEdge a = VisitedGraph.OutEdges(u)[ai];
                    if (IsResidualEdge(a))
                    {
                        IVertex v = a.Target;
                        if (IsAdmissible(u, v))
                        {
                            if (v != sink && excessFlow[v] == 0)
                            {
                                RemoveFromInactiveList(v);
                                AddToActiveList(v, layers[distances[v]]);
                            }
                            PushFlow(a);
                            if (excessFlow[u] == 0)
                            {
                                break;
                            }
                        }
                    }
                }

                PreflowLayer layer = layers[distances[u]];
                int          du    = distances[u];

                if (ai == VisitedGraph.OutDegree(u))                            // i must be relabeled
                {
                    RelabelDistance(u);
                    if (layer.ActiveVertices.Count == 0 &&
                        layer.InactiveVertices.Count == 0)
                    {
                        Gap(du);
                    }
                    if (distances[u] == n)
                    {
                        break;
                    }
                }
                else
                {                                                                               // i is no longer active
                    current[u] = ai;
                    AddToInactiveList(u, layer);
                    break;
                }
            }
        }
        //=======================================================================
        // remove excess flow, the "second phase"
        // This does a DFS on the reverse flow graph of nodes with excess flow.
        // If a cycle is found, cancel it.  Unfortunately it seems that we can't
        // easily take advantage of DepthFirstSearchAlgorithm
        // Return the nodes with excess flow in topological order.
        //
        // Unlike the prefl_to_flow() implementation, we use
        //   "color" instead of "distance" for the DFS labels
        //   "parent" instead of nl_prev for the DFS tree
        //   "topo_next" instead of nl_next for the topological ordering
        private void ConvertPreflowToFlow()
        {
            IVertex r, restart, u;
            IVertex bos = null, tos = null;

            VertexVertexDictionary parents = new VertexVertexDictionary();
            VertexVertexDictionary topoNext = new VertexVertexDictionary();

            foreach (IVertex v in VisitedGraph.Vertices)
            {
                //Handle self-loops
                foreach (IEdge a in VisitedGraph.OutEdges(v))
                {
                    if (a.Target == v)
                    {
                        ResidualCapacities[a] = Capacities[a];
                    }
                }

                //Initialize
                Colors[v]  = GraphColor.White;
                parents[v] = v;
                current[v] = 0;
            }

            // eliminate flow cycles and topologically order the vertices
            IVertexEnumerator vertices = VisitedGraph.Vertices.GetEnumerator();

            while (vertices.MoveNext())
            {
                u = vertices.Current;
                if (Colors[u] == GraphColor.White &&
                    excessFlow[u] > 0 &&
                    u != src && u != sink)
                {
                    r         = u;
                    Colors[r] = GraphColor.Gray;

                    while (true)
                    {
                        for (; current[u] < VisitedGraph.OutDegree(u); ++current[u])
                        {
                            IEdge a = VisitedGraph.OutEdges(u)[current[u]];

                            if (Capacities[a] == 0 && IsResidualEdge(a))
                            {
                                IVertex v = a.Target;
                                if (Colors[v] == GraphColor.White)
                                {
                                    Colors[v]  = GraphColor.Gray;
                                    parents[v] = u;
                                    u          = v;
                                    break;
                                }
                                else if (Colors[v] == GraphColor.Gray)
                                {
                                    //find minimum flow on the cycle
                                    double delta = ResidualCapacities[a];
                                    while (true)
                                    {
                                        IEdge e = VisitedGraph.OutEdges(v)[current[v]];
                                        delta = Math.Min(delta, ResidualCapacities[e]);
                                        if (v == u)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            v = e.Target;
                                        }
                                    }

                                    //remove delta flow units
                                    v = u;
                                    while (true)
                                    {
                                        a = VisitedGraph.OutEdges(v)[current[v]];
                                        ResidualCapacities[a] -= delta;
                                        ResidualCapacities[ReversedEdges[a]] += delta;
                                        v = a.Target;
                                        if (v == u)
                                        {
                                            break;
                                        }
                                    }

                                    // back-out of DFS to the first saturated edge
                                    restart = u;

                                    for (v = VisitedGraph.OutEdges(u)[current[u]].Target;
                                         v != u; v = a.Target)
                                    {
                                        a = VisitedGraph.OutEdges(v)[current[v]];

                                        if (Colors[v] == GraphColor.White ||
                                            IsSaturated(a))
                                        {
                                            Colors[VisitedGraph.OutEdges(v)[current[v]].Target] = GraphColor.White;
                                            if (Colors[v] != GraphColor.White)
                                            {
                                                restart = v;
                                            }
                                        }
                                    }

                                    if (restart != u)
                                    {
                                        u = restart;
                                        ++current[u];
                                        break;
                                    }
                                }
                            }
                        }

                        if (current[u] == VisitedGraph.OutDegree(u))
                        {
                            // scan of i is complete
                            Colors[u] = GraphColor.Black;

                            if (u != src)
                            {
                                if (bos == null)
                                {
                                    bos = u;
                                    tos = u;
                                }
                                else
                                {
                                    topoNext[u] = tos;
                                    tos         = u;
                                }
                            }
                            if (u != r)
                            {
                                u = parents[u];
                                ++current[u];
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
            }

            // return excess flows
            // note that the sink is not on the stack
            if (bos != null)
            {
                IEdgeEnumerator ai;

                for (u = tos; u != bos; u = topoNext[u])
                {
                    ai = VisitedGraph.OutEdges(u).GetEnumerator();

                    while (excessFlow[u] > 0 && ai.MoveNext())
                    {
                        if (Capacities[ai.Current] == 0 && IsResidualEdge(ai.Current))
                        {
                            PushFlow(ai.Current);
                        }
                    }
                }
                // do the bottom
                u  = bos;
                ai = VisitedGraph.OutEdges(u).GetEnumerator();
                while (excessFlow[u] > 0 && ai.MoveNext())
                {
                    if (Capacities[ai.Current] == 0 && IsResidualEdge(ai.Current))
                    {
                        PushFlow(ai.Current);
                    }
                }
            }
        }
        private void Initialize()
        {
            int m = 0;

            n = VisitedGraph.VerticesCount;
            foreach (IVertex u in VisitedGraph.Vertices)
            {
                m += VisitedGraph.OutDegree(u);
            }
            // Don't count the reverse edges
            m /= 2;
            nm = alpha * n + m;

            excessFlow.Clear();
            current.Clear();
            distances.Clear();

            layers = new PreflowLayer[n];
            for (int i = 0; i < n; i++)
            {
                layers[i] = new PreflowLayer();
            }

            // Initialize flow to zero which means initializing
            // the residual capacity to equal the capacity.
            foreach (IVertex u in VisitedGraph.Vertices)
            {
                foreach (IEdge e in VisitedGraph.OutEdges(u))
                {
                    this.ResidualCapacities[e] = this.Capacities[e];
                }

                excessFlow[u] = 0;
                current[u]    = 0;
            }

            bool   overflowDetected = false;
            double testExcess       = 0;

            foreach (IEdge a in VisitedGraph.OutEdges(src))
            {
                if (a.Target != src)
                {
                    testExcess += this.ResidualCapacities[a];
                }
            }

            if (testExcess >= double.MaxValue || double.IsPositiveInfinity(testExcess))
            {
                overflowDetected = true;
            }

            if (overflowDetected)
            {
                excessFlow[src] = double.MaxValue;
            }
            else
            {
                excessFlow[src] = 0;
                foreach (IEdge a in this.VisitedGraph.OutEdges(src))
                {
                    if (a.Target != src)
                    {
                        double delta = this.ResidualCapacities[a];
                        this.ResidualCapacities[a] -= delta;
                        this.ResidualCapacities[this.ReversedEdges[a]] += delta;
                        this.excessFlow[a.Target] += delta;
                    }
                }
            }

            maxDistance = VisitedGraph.VerticesCount - 1;
            maxActive   = 0;
            minActive   = n;

            foreach (IVertex u in this.VisitedGraph.Vertices)
            {
                if (u == sink)
                {
                    distances[u] = 0;
                    continue;
                }
                else if (u == src && !overflowDetected)
                {
                    distances[u] = n;
                }
                else
                {
                    distances[u] = 1;
                }

                if (excessFlow[u] > 0)
                {
                    this.AddToActiveList(u, layers[1]);
                }
                else if (distances[u] < n)
                {
                    this.AddToInactiveList(u, layers[1]);
                }
            }
        }
        private void FlushVisitQueue()
        {
            var cancelManager = this.Services.CancelManager;
            var oee           = this.OutEdgeEnumerator;

            while (this.rootQueue.Count > 0)
            {
                if (cancelManager.IsCancelling)
                {
                    return;
                }

                this.vertexQueue.Enqueue(this.rootQueue.Dequeue());

                while (this.vertexQueue.Count > 0)
                {
                    var u = this.vertexQueue.Dequeue();
                    this.OnExamineVertex(u);
                    var visited = _sorted ? oee(this.VisitedGraph.OutEdges(u)).OrderBy(e => VisitedGraph.OutDegree(e.Target)) :
                                  oee(this.VisitedGraph.OutEdges(u));
                    foreach (var e in visited)
                    {
                        TVertex v = e.Target;
                        this.OnExamineEdge(e);

                        var vColor = this.VertexColors[v];
                        if (vColor == GraphColor.White)
                        {
                            this.OnTreeEdge(e);
                            this.VertexColors[v] = GraphColor.Gray;
                            this.OnDiscoverVertex(v);
                            this.vertexQueue.Enqueue(v);
                        }
                        else
                        {
                            this.OnNonTreeEdge(e);
                            if (vColor == GraphColor.Gray)
                            {
                                this.OnGrayTarget(e);
                            }
                            else
                            {
                                this.OnBlackTarget(e);
                            }
                        }
                    }
                    this.VertexColors[u] = GraphColor.Black;
                    this.OnFinishVertex(u);
                }
            }
        }