//*************************************************************************
        //  Method: LayOutGraphCore()
        //
        /// <summary>
        /// Lays out a graph synchronously or asynchronously.
        /// </summary>
        ///
        /// <param name="graph">
        /// Graph to lay out.  The graph is guaranteed to have at least one vertex.
        /// </param>
        ///
        /// <param name="verticesToLayOut">
        /// Vertices to lay out.  The collection is guaranteed to have at least one
        /// vertex.
        /// </param>
        ///
        /// <param name="layoutContext">
        /// Provides access to objects needed to lay out the graph.  The <see
        /// cref="LayoutContext.GraphRectangle" /> is guaranteed to have non-zero
        /// width and height.
        /// </param>
        ///
        /// <param name="backgroundWorker">
        /// <see cref="BackgroundWorker" /> whose worker thread called this method
        /// if the graph is being laid out asynchronously, or null if the graph is
        /// being laid out synchronously.
        /// </param>
        ///
        /// <returns>
        /// true if the layout was successfully completed, false if the layout was
        /// cancelled.  The layout can be cancelled only if the graph is being laid
        /// out asynchronously.
        /// </returns>
        ///
        /// <remarks>
        /// This method lays out the graph <paramref name="graph" /> either
        /// synchronously (if <paramref name="backgroundWorker" /> is null) or
        /// asynchronously (if (<paramref name="backgroundWorker" /> is not null)
        /// by setting the the <see cref="IVertex.Location" /> property on the
        /// vertices in <paramref name="verticesToLayOut" /> and optionally adding
        /// geometry metadata to the graph, vertices, or edges.
        ///
        /// <para>
        /// In the asynchronous case, the <see
        /// cref="BackgroundWorker.CancellationPending" /> property on the
        /// <paramref name="backgroundWorker" /> object should be checked before
        /// each layout iteration.  If it's true, the method should immediately
        /// return false.  Also, <see
        /// cref="AsyncLayoutBase.FireLayOutGraphIterationCompleted()" /> should be
        /// called after each iteration.
        /// </para>
        ///
        /// <para>
        /// The arguments have already been checked for validity.
        /// </para>
        ///
        /// </remarks>
        //*************************************************************************
        protected override Boolean LayOutGraphCore(
            IGraph graph,
            ICollection<IVertex> verticesToLayOut,
            LayoutContext layoutContext,
            BackgroundWorker backgroundWorker
            )
        {
            Debug.Assert(graph != null);
            Debug.Assert(verticesToLayOut != null);
            Debug.Assert(verticesToLayOut.Count > 0);
            Debug.Assert(layoutContext != null);
            AssertValid();

            if (backgroundWorker != null && backgroundWorker.CancellationPending)
            {
            return (false);
            }

            ICollection<IEdge> oEdgesToLayOut =
            GetEdgesToLayOut(graph, verticesToLayOut);

            Int32 iVertices = verticesToLayOut.Count;

            // The MultiScaleLayout class uses a simple scheme where the graph's
            // vertices consist of the integers 0 through N-1, where N is the
            // number of vertices in the graph.  NodeXL uses IVertex objects and
            // the vertex collection isn't indexed.  Work around this
            // incompatibility by creating a dictionary that maps vertices to
            // zero-based vertex indexes.

            Dictionary<IVertex, Int32> oVertexDictionary =
            new Dictionary<IVertex, Int32>(iVertices);

            Int32 iVertexIndex = 0;

            foreach (IVertex oVertex in verticesToLayOut)
            {
            oVertexDictionary.Add(oVertex, iVertexIndex);
            iVertexIndex++;
            }

            // Create and populate a MultiScaleLayout graph.

            MultiScaleLayout.Graph oMultiScaleLayoutGraph =
            new MultiScaleLayout.Graph(iVertices, String.Empty);

            foreach (IEdge oEdge in oEdgesToLayOut)
            {
            IVertex [] aoEdgeVertices = oEdge.Vertices;

            oMultiScaleLayoutGraph.AddEdge(
                oVertexDictionary[ aoEdgeVertices[0] ],
                oVertexDictionary[ aoEdgeVertices[1] ]
                );
            }

            // Lay it out.

            oMultiScaleLayoutGraph.PrepareForUse();

            MultiScaleLayout.GraphLayoutSettings oGraphLayoutSettings =
            new MultiScaleLayout.GraphLayoutSettings(m_iRad,
                m_iLocalIterations, m_iRatio, m_iMinSize);

            oMultiScaleLayoutGraph.MultiScaleLayout(
            ( new Random() ).Next(), oGraphLayoutSettings);

            // Retrieve the laid out vertex coordinates, which are normalized to
            // fall within the range [0,1].

            MultiScaleLayout.PointD [] oMultiScaleLayoutLocations =
            oMultiScaleLayoutGraph.vertexCoords;

            Rectangle oRectangle = layoutContext.GraphRectangle;

            Debug.Assert(oRectangle.Width > 0);
            Debug.Assert(oRectangle.Height > 0);

            Int32 iLeft = oRectangle.Left;
            Int32 iTop = oRectangle.Top;
            Int32 iWidth = oRectangle.Width;
            Int32 iHeight = oRectangle.Height;

            foreach (IVertex oVertex in verticesToLayOut)
            {
            if ( !VertexIsLocked(oVertex) )
            {
                // Convert the normalized coordinates to coordinates within the
                // layout rectangle.

                MultiScaleLayout.PointD oMultiScaleLayoutLocation =
                    oMultiScaleLayoutLocations[ oVertexDictionary[oVertex] ];

                oVertex.Location = new PointF(
                    iLeft + (Single)(oMultiScaleLayoutLocation.x * iWidth),
                    iTop + (Single)(oMultiScaleLayoutLocation.y * iHeight)
                    );
            }
            }

            return (true);
        }
Example #2
0
        LayOutGraphCore
        (
            IGraph graph,
            ICollection <IVertex> verticesToLayOut,
            LayoutContext layoutContext,
            BackgroundWorker backgroundWorker
        )
        {
            Debug.Assert(graph != null);
            Debug.Assert(verticesToLayOut != null);
            Debug.Assert(verticesToLayOut.Count > 0);
            Debug.Assert(layoutContext != null);
            AssertValid();

            if (backgroundWorker != null && backgroundWorker.CancellationPending)
            {
                return(false);
            }

            ICollection <IEdge> oEdgesToLayOut =
                GetEdgesToLayOut(graph, verticesToLayOut);

            Int32 iVertices = verticesToLayOut.Count;

            // The MultiScaleLayout class uses a simple scheme where the graph's
            // vertices consist of the integers 0 through N-1, where N is the
            // number of vertices in the graph.  NodeXL uses IVertex objects and
            // the vertex collection isn't indexed.  Work around this
            // incompatibility by creating a dictionary that maps vertices to
            // zero-based vertex indexes.

            Dictionary <IVertex, Int32> oVertexDictionary =
                new Dictionary <IVertex, Int32>(iVertices);

            Int32 iVertexIndex = 0;

            foreach (IVertex oVertex in verticesToLayOut)
            {
                oVertexDictionary.Add(oVertex, iVertexIndex);
                iVertexIndex++;
            }

            // Create and populate a MultiScaleLayout graph.

            MultiScaleLayout.Graph oMultiScaleLayoutGraph =
                new MultiScaleLayout.Graph(iVertices, String.Empty);

            foreach (IEdge oEdge in oEdgesToLayOut)
            {
                IVertex [] aoEdgeVertices = oEdge.Vertices;

                oMultiScaleLayoutGraph.AddEdge(
                    oVertexDictionary[aoEdgeVertices[0]],
                    oVertexDictionary[aoEdgeVertices[1]]
                    );
            }

            // Lay it out.

            oMultiScaleLayoutGraph.PrepareForUse();

            MultiScaleLayout.GraphLayoutSettings oGraphLayoutSettings =
                new MultiScaleLayout.GraphLayoutSettings(m_iRad,
                                                         m_iLocalIterations, m_iRatio, m_iMinSize);

            oMultiScaleLayoutGraph.MultiScaleLayout(
                (new Random()).Next(), oGraphLayoutSettings);

            // Retrieve the laid out vertex coordinates, which are normalized to
            // fall within the range [0,1].

            MultiScaleLayout.PointD [] oMultiScaleLayoutLocations =
                oMultiScaleLayoutGraph.vertexCoords;

            Rectangle oRectangle = layoutContext.GraphRectangle;

            Debug.Assert(oRectangle.Width > 0);
            Debug.Assert(oRectangle.Height > 0);

            Int32 iLeft   = oRectangle.Left;
            Int32 iTop    = oRectangle.Top;
            Int32 iWidth  = oRectangle.Width;
            Int32 iHeight = oRectangle.Height;

            foreach (IVertex oVertex in verticesToLayOut)
            {
                if (!VertexIsLocked(oVertex))
                {
                    // Convert the normalized coordinates to coordinates within the
                    // layout rectangle.

                    MultiScaleLayout.PointD oMultiScaleLayoutLocation =
                        oMultiScaleLayoutLocations[oVertexDictionary[oVertex]];

                    oVertex.Location = new PointF(
                        iLeft + (Single)(oMultiScaleLayoutLocation.x * iWidth),
                        iTop + (Single)(oMultiScaleLayoutLocation.y * iHeight)
                        );
                }
            }

            return(true);
        }