Beispiel #1
0
        private void CountEdgeCrossings(GraphLink edge)
        {
            int crossings = 0;

            GraphNode v1 = edge.Origin;
            GraphNode v2 = edge.Destination;

            SpringVertexData v1D = (SpringVertexData)v1.GetData(_SpringVertex);
            SpringVertexData v2D = (SpringVertexData)v2.GetData(_SpringVertex);

            PointF pt = new PointF(0, 0), pt11, pt12, pt21, pt22;

            pt11 = v1.Center;
            pt12 = v2.Center;

            foreach (GraphLink test in _graph.Links)
            {
                if (edge == test)
                {
                    continue;
                }

                pt21 = test.Origin.Center;
                pt22 = test.Destination.Center;
                if (pt11 != pt21 && pt11 != pt22 && pt12 != pt21 && pt12 != pt22)
                {
                    if (new Line(pt11, pt12).IntersectSegment(pt21, pt22).X !=
                        float.PositiveInfinity)
                    {
                        crossings++;
                        v1D.Crossings++;
                        v2D.Crossings++;
                    }
                }
            }

            SpringEdgeData data = (SpringEdgeData)edge.GetData(_SpringEdge);

            data.Crossings = crossings;
        }
Beispiel #2
0
        Size CalcLinkDir(GraphNode node)
        {
            int   xEval = 0, yEval = 0;
            Point gridPos1 = (Point)node.GetData(_GridPos);

            foreach (GraphLink link in node.OutLinks)
            {
                Point gridPos2 = (Point)link.Destination.GetData(_GridPos);

                xEval += gridPos2.X - gridPos1.X;
                yEval += gridPos2.Y - gridPos1.Y;
            }

            foreach (GraphLink link in node.InLinks)
            {
                Point gridPos2 = (Point)link.Origin.GetData(_GridPos);

                xEval += gridPos2.X - gridPos1.X;
                yEval += gridPos2.Y - gridPos1.Y;
            }

            if (xEval > 0)
            {
                xEval = 1;
            }
            if (xEval < 0)
            {
                xEval = -1;
            }
            if (yEval > 0)
            {
                yEval = 1;
            }
            if (yEval < 0)
            {
                yEval = -1;
            }

            return(new Size(xEval, yEval));
        }
Beispiel #3
0
		Size CalcLinkDir(GraphNode node)
		{
			int xEval = 0, yEval = 0;
			Point gridPos1 = (Point)node.GetData(_GridPos);

			foreach (GraphLink link in node.OutLinks)
			{
				Point gridPos2 = (Point)link.Destination.GetData(_GridPos);

				xEval += gridPos2.X - gridPos1.X;
				yEval += gridPos2.Y - gridPos1.Y;
			}

			foreach (GraphLink link in node.InLinks)
			{
				Point gridPos2 = (Point)link.Origin.GetData(_GridPos);

				xEval += gridPos2.X - gridPos1.X;
				yEval += gridPos2.Y - gridPos1.Y;
			}

			if (xEval > 0) xEval = 1;
			if (xEval < 0) xEval = -1;
			if (yEval > 0) yEval = 1;
			if (yEval < 0) yEval = -1;

			return new Size(xEval, yEval);
		}
Beispiel #4
0
 private void RollbackMove(GraphNode node)
 {
     _glBordLinesCost = _glBordLinesCost + (double)node.GetData(BordLines) - _bordNewLocalValue;
 }
Beispiel #5
0
 private void CalcNewGlobalCost(GraphNode node)
 {
     _bordNewLocalValue = evalBoundaryCost(node);
     _glBordLinesCost   = _glBordLinesCost - (double)node.GetData(BordLines) + _bordNewLocalValue;
 }
Beispiel #6
0
		private void AddChildren(GraphNode node)
		{
			ArrayList next = new ArrayList();
			foreach (GraphLink link in node.OutLinks)
			{
				GraphNode child = link.Destination;
				int nodeLayer = (int)node.GetData(_Layer);
				int childLayer = (int)child.GetData(_Layer);
				if (childLayer == -1 && nodeLayer < _layers.Count - 1)
				{
					child.SetData(_Layer, nodeLayer + 1);
					(_layers[nodeLayer + 1] as ArrayList).Add(child);
					next.Add(child);
				}
				else if (childLayer == -1)
				{
					_layers.Add(new ArrayList());
					child.SetData(_Layer, nodeLayer + 1);
					(_layers[nodeLayer] as ArrayList).Add(child);
					next.Add(child);
				}
			}
			foreach (GraphLink link in node.InLinks)
			{
				GraphNode child = link.Origin;
				int nodeLayer = (int)node.GetData(_Layer);
				int childLayer = (int)child.GetData(_Layer);
				if (childLayer == -1 && nodeLayer > 0)
				{
					child.SetData(_Layer, nodeLayer - 1);
					(_layers[nodeLayer - 1] as ArrayList).Add(child);
					next.Add(child);
				}
				else if (childLayer == -1)
				{
					child.SetData(_Layer, 0);
					(_layers[0] as ArrayList).Add(child);
					next.Add(child);
				}
			}

			foreach (GraphNode child in next)
				AddChildren(child);
		}
Beispiel #7
0
		private bool MoveLeft(GraphNode node, ArrayList layer, double priority)
		{
			int index = layer.IndexOf(node);
			if (index == 0)
			{
				// This is the last node in the layer - 
				// so we can move to the left without troubles
				node.SetData(_GridPosition, (double)node.GetData(_GridPosition) - 0.5);
				return true;
			}

			GraphNode leftNode = layer[index - 1] as GraphNode;

			double leftNodePriority = ((double)leftNode.GetData(_UPriority) +
				(double)leftNode.GetData(_DPriority)) / 2;

			// Check if there is space
			// between the left and the current node
			if ((double)leftNode.GetData(_GridPosition) <
				(double)node.GetData(_GridPosition) - 1)
			{
				node.SetData(_GridPosition, (double)node.GetData(_GridPosition) - 0.5);
				return true;
			}

			// We have reached a node with higher priority - 
			// no movement is allowed
			if (leftNodePriority > priority ||
				Math.Abs(leftNodePriority - priority) < double.Epsilon)
				return false;

			// The left node has lower priority - try to move it
			if (MoveLeft(leftNode, layer, priority))
			{
				node.SetData(_GridPosition, (double)node.GetData(_GridPosition) - 0.5);
				return true;
			}

			return false;
		}
Beispiel #8
0
		/// <summary>
		/// Calculates the barycenter of a node.
		/// </summary>
		internal static double CalcBaryCenter(GraphNode node)
		{
			int uLinkCount = (int)node.GetData(_ULinkCount);
			int dLinkCount = (int)node.GetData(_DLinkCount);
			double uBaryCenter = (double)node.GetData(_UBaryCenter);
			double dBaryCenter = (double)node.GetData(_DBaryCenter);

			if (uLinkCount > 0 && dLinkCount > 0)
				return (uBaryCenter + dBaryCenter) / 2;
			if (uLinkCount > 0)
				return uBaryCenter;
			if (dLinkCount > 0)
				return dBaryCenter;

			return 0;
		}
Beispiel #9
0
		private void RollbackMove(GraphNode node)
		{
			_glBordLinesCost = _glBordLinesCost + (double)node.GetData(BordLines) - _bordNewLocalValue;
		}
Beispiel #10
0
		private void CalcNewGlobalCost(GraphNode node)
		{
			_bordNewLocalValue = evalBoundaryCost(node);
			_glBordLinesCost = _glBordLinesCost - (double)node.GetData(BordLines) + _bordNewLocalValue;
		}
Beispiel #11
0
        public bool Arrange(IGraph graph,
                            SpringLayoutInfo layoutInfo, LayoutProgress progress)
        {
            _info = layoutInfo;

            if (_info.RndSeed != 0)
            {
                // Use the randomization seed supplied by the user
                _r = new Random(_info.RndSeed);
            }

            // Build the internal graph
            _graph = new Graph(graph);

            RectangleF rcDoc    = CalcContentRect(_graph);
            float      minNodeX = rcDoc.Left - (50f * _info.NodeDistance);
            float      minNodeY = rcDoc.Top - (50f * _info.NodeDistance);
            float      maxNodeX = rcDoc.Right + (50f * _info.NodeDistance);
            float      maxNodeY = rcDoc.Bottom + (50f * _info.NodeDistance);

            // Initialize
            foreach (GraphNode node in _graph.Nodes)
            {
                node.SetData(_SpringVertex, new SpringVertexData());
            }
            foreach (GraphLink link in _graph.Links)
            {
                link.SetData(_SpringEdge, new SpringEdgeData());
            }

            // Calculate vertex radiuses
            foreach (GraphNode node in _graph.Nodes)
            {
                RectangleF rc = node.Bounds;
                node.SetData(_VertexRadius,
                             (double)(rc.Width + rc.Height) / 4);
            }

            // Update progress
            int   total   = layoutInfo.IterationCount;
            float ffactor = total / 100;
            int   factor  = 1;

            if (ffactor > 1)
            {
                factor = (int)Math.Floor((double)ffactor);
                total  = total / factor + 1;
            }
            if (progress != null)
            {
                progress(0, total);
            }

            // An iterative layout algorithm
            for (int step = 1; step <= layoutInfo.IterationCount; step++)
            {
                // Update progress
                if (progress != null)
                {
                    if (step % factor == 0)
                    {
                        progress(step / factor, total);
                    }
                }

                foreach (GraphNode node in _graph.Nodes)
                {
                    SpringVertexData data = (SpringVertexData)
                                            node.GetData(_SpringVertex);
                    data.DX         /= 4;
                    data.DY         /= 4;
                    data.EdgeDX      = data.EdgeDY = 0;
                    data.RepulsionDX = data.RepulsionDY = 0;
                }

                // here the "springs" confine nodes to the desired node distance
                foreach (GraphLink link in _graph.Links)
                {
                    // get incident nodes
                    GraphNode v1 = link.Origin;
                    GraphNode v2 = link.Destination;

                    // compute current distance between nodes
                    PointF v1Pos = v1.Center;
                    PointF v2Pos = v2.Center;
                    double vx    = v1Pos.X - v2Pos.X;
                    double vy    = v1Pos.Y - v2Pos.Y;
                    double dist  = Math.Sqrt(vx * vx + vy * vy);
                    dist = (dist == 0) ? 0.0001 : dist;

                    // get desired distance accomodated for node extents
                    double desiredDist = _info.NodeDistance;
                    desiredDist += ((double)v1.GetData(_VertexRadius) +
                                    (double)v2.GetData(_VertexRadius)) / 2;

                    // now handling cluster center nodes ?
                    bool masterNodes = _info.EnableClusters &&
                                       (v1.LinkCount > 4 && v2.LinkCount > 4);
                    desiredDist *= masterNodes ? 4 : link.Link.Weight;

                    // force factor: optimal length minus actual length,
                    // is made smaller as the current actual length gets larger.
                    double f = _ForceConstant * (desiredDist - dist) / dist;

                    // nodes with few links are moved easier than ones with more
                    double f1 = masterNodes ? f :
                                (f * Math.Pow(_stretch / 100.0, v1.LinkCount - 1));
                    double f2 = masterNodes ? f :
                                (f * Math.Pow(_stretch / 100.0, v2.LinkCount - 1));

                    // move first node towards the second one
                    SpringVertexData v1D = (SpringVertexData)v1.GetData(_SpringVertex);
                    v1D.EdgeDX += f1 * vx;
                    v1D.EdgeDY += f1 * vy;

                    // move second node towards the first one
                    SpringVertexData v2D = (SpringVertexData)v2.GetData(_SpringVertex);
                    v2D.EdgeDX += -f2 * vx;
                    v2D.EdgeDY += -f2 * vy;
                }

                // here nodes tend to run away one from another
                foreach (GraphNode node in _graph.Nodes)
                {
                    SpringVertexData svd = (SpringVertexData)node.GetData(_SpringVertex);
                    double           dx  = 0;
                    double           dy  = 0;

                    foreach (GraphNode node2 in _graph.Nodes)
                    {
                        if (node2 == node)
                        {
                            continue;
                        }

                        // now handling cluster center nodes ?
                        bool masterNodes = _info.EnableClusters &&
                                           (node.LinkCount > 4 && node2.LinkCount > 4);

                        // if distance is longer than this, ignore repulsion
                        double intrZone = _info.NodeDistance *
                                          (masterNodes ? 4.5 : _info.RepulsionFactor);

                        // if distance is shorter than this, randomize node positions
                        double tooClose = _info.NodeDistance / (masterNodes ? 1 : 5);

                        // distance to move when using random position
                        double moveRange = _info.NodeDistance * (masterNodes ? 5 : 1);

                        // compute current distance between nodes
                        double vx       = node.Center.X - node2.Center.X;
                        double vy       = node.Center.Y - node2.Center.Y;
                        double distance = vx * vx + vy * vy;

                        // kind of simmulated annealing, use random jumps for nodes
                        // that are close one to another; longer jumps for nodes that
                        // overlap completely and shorter for nodes that don't overlap
                        if (distance == 0)
                        {
                            dx += moveRange / 2 + _r.Next() % ((int)(moveRange * 3));
                            dy += moveRange / 2 + _r.Next() % ((int)(moveRange * 3));
                            if (_r.Next() % 2 == 1)
                            {
                                dx = -dx;
                            }
                            if (_r.Next() % 2 == 1)
                            {
                                dy = -dy;
                            }
                        }
                        else if (distance < tooClose * tooClose)
                        {
                            dx += moveRange / 2 + _r.Next((int)moveRange);
                            dy += moveRange / 2 + _r.Next((int)moveRange);
                            if (_r.Next() % 2 == 1)
                            {
                                dx = -dx;
                            }
                            if (_r.Next() % 2 == 1)
                            {
                                dy = -dy;
                            }
                        }
                        // if nodes are not that close, calculate normal repulsion
                        else if (distance < intrZone * intrZone)
                        {
                            float mf = masterNodes ?
                                       (node.LinkCount + node2.LinkCount) : 1;
                            dx += mf * vx / (distance * distance);
                            dy += mf * vy / (distance * distance);
                        }
                    }

                    // apply the summary repulsion of this node with all other nodes
                    double dlen = dx * dx + dy * dy;
                    if (dlen > 0)
                    {
                        dlen             = Math.Sqrt(dlen) / 2;
                        svd.RepulsionDX += dx / dlen;
                        svd.RepulsionDY += dy / dlen;
                    }
                }

                // sum repulsion and "spring" forces and move nodes
                foreach (GraphNode node in _graph.Nodes)
                {
                    // update node movement speed
                    SpringVertexData vd =
                        (SpringVertexData)node.GetData(_SpringVertex);
                    vd.DX += vd.RepulsionDX + vd.EdgeDX;
                    vd.DY += vd.RepulsionDY + vd.EdgeDY;

                    // move node
                    PointF xyd = node.Center;
                    xyd.X += (float)vd.DX;
                    xyd.Y += (float)vd.DY;

                    if (layoutInfo.EnableClusters &&
                        (((xyd.X < minNodeX) || (xyd.Y < minNodeY)) || ((xyd.X > maxNodeX) || (xyd.Y > maxNodeY))))
                    {
                        xyd    = node.Center;
                        vd.DX /= 4;
                        vd.DY /= 4;
                    }

                    node.Center = xyd;
                }

                // try to decrease crossings if that option is enabled
                if (_info.MinimizeCrossings &&
                    (step % 10 == 0) &&
                    (step < _info.IterationCount * 2 / 3))
                {
                    int currentCrossings = CountCrossings();
                    if (currentCrossings > 0)
                    {
                        TryDecreaseCrossings(graph.DocRect, _info.NodeDistance, currentCrossings);
                    }
                }
            }

            // offset the graph to its original location
            RectangleF rcDoc2 = CalcContentRect(_graph);
            float      pdx    = rcDoc2.Left - rcDoc.Left;
            float      pdy    = rcDoc2.Top - rcDoc.Top;

            foreach (GraphNode node in _graph.Nodes)
            {
                PointF xyd = node.Center;
                xyd.X      -= pdx;
                xyd.Y      -= pdy;
                node.Center = xyd;
            }

            // update flowchart nodes positions
            foreach (GraphNode node in _graph.Nodes)
            {
                node.Node.Bounds = node.Bounds;
            }

            // call progress delegate
            if (progress != null)
            {
                progress(total, total);
            }

            return(true);
        }
Beispiel #12
0
        private void TryDecreaseCrossings(RectangleF doc, float ddist, int crossings)
        {
            GraphNode node = NodeWithMostCrossings();

            if (node == null)
            {
                return;
            }

            SpringVertexData data   = (SpringVertexData)node.GetData(_SpringVertex);
            PointF           pos    = node.Center;
            PointF           minPos = pos;

            for (int c = 3; c >= 1; c--)
            {
                for (int h = -1; h <= 1; h++)
                {
                    for (int v = -1; v <= 1; v++)
                    {
                        if (h == 0 && v == 0)
                        {
                            continue;
                        }

                        PointF newPos = new PointF(0, 0);
                        newPos.X = pos.X + c * h * ddist;
                        newPos.Y = pos.Y + c * v * ddist;

                        if (newPos.X < doc.Left)
                        {
                            continue;
                        }
                        if (newPos.X > doc.Right)
                        {
                            continue;
                        }
                        if (newPos.Y < doc.Top)
                        {
                            continue;
                        }
                        if (newPos.Y > doc.Bottom)
                        {
                            continue;
                        }

                        node.Center = newPos;

                        int newCrossings = CountCrossings();
                        if (newCrossings < crossings)
                        {
                            minPos = newPos;
                        }
                    }
                }
            }

            if (minPos != pos)
            {
                node.Center = minPos;
            }
        }