Ejemplo n.º 1
0
        /// <summary>
        /// Runs the force-directed layout algorithm on this Diagram, using the specified parameters.
        /// </summary>
        /// <param name="damping">Value between 0 and 1 that slows the motion of the nodes during layout.</param>
        /// <param name="springLength">Value in pixels representing the length of the imaginary springs that run along the connectors.</param>
        /// <param name="maxIterations">Maximum number of iterations before the algorithm terminates.</param>
        /// <param name="deterministic">Whether to use a random or deterministic layout.</param>
        public void Arrange(double damping, int springLength, int maxIterations, bool deterministic)
        {
            // random starting positions can be made deterministic by seeding System.Random with a constant
            Random rnd = deterministic ? new Random(0) : new Random();

            // copy nodes into an array of metadata and randomise initial coordinates for each node
            NodeLayoutInfo[] layout = new NodeLayoutInfo[mNodes.Count];
            for (int i = 0; i < mNodes.Count; i++)
            {
                layout[i] = new NodeLayoutInfo(mNodes[i], new Layv(), Point.Empty);
                layout[i].Layn.Location = new Point(rnd.Next(-50, 50), rnd.Next(-50, 50));
            }

            int stopCount  = 0;
            int iterations = 0;

            while (true)
            {
                double totalDisplacement = 0;

                for (int i = 0; i < layout.Length; i++)
                {
                    NodeLayoutInfo current = layout[i];

                    // express the node's current position as a vector, relative to the origin
                    Layv currentPosition = new Layv(CalcDistance(Point.Empty, current.Layn.Location), GetBearingAngle(Point.Empty, current.Layn.Location));
                    Layv netForce        = new Layv(0, 0);

                    // determine repulsion between nodes
                    foreach (Layn other in mNodes)
                    {
                        if (other != current.Layn)
                        {
                            netForce += CalcRepulsionForce(current.Layn, other);
                        }
                    }

                    // determine attraction caused by connections
                    foreach (Layn child in current.Layn.Connections)
                    {
                        netForce += CalcAttractionForce(current.Layn, child, springLength);
                    }
                    foreach (Layn parent in mNodes)
                    {
                        if (parent.Connections.Contains(current.Layn))
                        {
                            netForce += CalcAttractionForce(current.Layn, parent, springLength);
                        }
                    }

                    // apply net force to node velocity
                    current.Velocity = (current.Velocity + netForce) * damping;

                    // apply velocity to node position
                    current.NextPosition = (currentPosition + current.Velocity).ToPoint();
                }

                // move nodes to resultant positions (and calculate total displacement)
                for (int i = 0; i < layout.Length; i++)
                {
                    NodeLayoutInfo current = layout[i];

                    totalDisplacement    += CalcDistance(current.Layn.Location, current.NextPosition);
                    current.Layn.Location = current.NextPosition;
                }

                iterations++;
                if (totalDisplacement < 10)
                {
                    stopCount++;
                }
                if (stopCount > 15)
                {
                    break;
                }
                if (iterations > maxIterations)
                {
                    break;
                }
            }

            // center the diagram around the origin
            Rectangle logicalBounds = GetDiagramBounds();
            Point     midPoint      = new Point(logicalBounds.X + (logicalBounds.Width / 2), logicalBounds.Y + (logicalBounds.Height / 2));

            foreach (Layn node in mNodes)
            {
                node.Location -= (Size)midPoint;
            }
        }
Ejemplo n.º 2
0
            public Point NextPosition;  // the node's position after the next iteration

            /// <summary>
            /// Initialises a new instance of the Diagram.NodeLayoutInfo class, using the specified parameters.
            /// </summary>
            /// <param name="layn"></param>
            /// <param name="velocity"></param>
            /// <param name="nextPosition"></param>
            public NodeLayoutInfo(Layn layn, Layv velocity, Point nextPosition)
            {
                Layn         = layn;
                Velocity     = velocity;
                NextPosition = nextPosition;
            }