internal LayoutProgressEventArgs(LayoutProgress progress, string diagnostics) {
     this.progress = progress;
     this.diagnostics = diagnostics;
 }
Esempio n. 2
0
        public bool Arrange(IGraph graph,
                            GridLayoutInfo info, LayoutProgress progress)
        {
            _graph = new Graph(graph);
            _info  = info;

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

            Path path = null;

            // Find the longest path between the start and the end node
            if (_info.StartNode != null && _info.EndNode != null)
            {
                path = PathFinder.FindLongestPath(graph, _info.StartNode, _info.EndNode);
            }
            else
            {
                path = PathFinder.FindLongestPath(graph);
            }

            if (path == null)
            {
                return(false);
            }

            // Build path consisting of the corresponding GraphNode-s
            _backbone = new ArrayList();
            foreach (INode inode in path.Nodes)
            {
                foreach (GraphNode node in _graph.Nodes)
                {
                    if (node.Node == inode)
                    {
                        _backbone.Add(node);
                        break;
                    }
                }
            }

            GraphNode[,] bestGrid = InitGrid();
            float bestEstimation = float.MaxValue;
            int   maxShift       = Math.Max(4, _gridWidth / 10);

            // Update progress
            int   current = 0;
            int   total   = CountIterations(maxShift);
            float ffactor = total / 100;
            int   factor  = 1;

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

            while (maxShift > 0)
            {
                for (int iter = 0;
                     iter < (maxShift > 2 ?
                             _info.Iterations :
                             (_info.Iterations / 5 * maxShift * _graph.Nodes.Count));
                     ++iter)
                {
                    // Update progress
                    if (progress != null)
                    {
                        if (current % factor == 0)
                        {
                            progress(current / factor, total);
                        }
                        current++;
                    }

                    GraphNode[,] grid = ScrambleGrid(bestGrid, maxShift, iter);
                    float estimation = EvaluateGrid(grid, maxShift);

                    if (estimation < bestEstimation)
                    {
                        bestEstimation = estimation;
                        bestGrid       = grid;
                    }
                    else
                    {
                        ApplyGrid(bestGrid);
                    }
                }

                maxShift--;
            }

            PlaceObjects(bestGrid);

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

            return(true);
        }
Esempio n. 3
0
		public bool Arrange(IGraph graph,
			GridLayoutInfo info, LayoutProgress progress)
		{
			_graph = new Graph(graph);
			_info = info;

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

			Path path = null;

			// Find the longest path between the start and the end node
			if (_info.StartNode != null && _info.EndNode != null)
			{
				path = PathFinder.FindLongestPath(graph, _info.StartNode, _info.EndNode);
			}
			else
			{
				path = PathFinder.FindLongestPath(graph);
			}

			if (path == null)
				return false;

			// Build path consisting of the corresponding GraphNode-s
			_backbone = new ArrayList();
			foreach (INode inode in path.Nodes)
			{
				foreach (GraphNode node in _graph.Nodes)
				{
					if (node.Node == inode)
					{
						_backbone.Add(node);
						break;
					}
				}
			}

			GraphNode[,] bestGrid = InitGrid();
			float bestEstimation = float.MaxValue;
			int maxShift = Math.Max(4, _gridWidth / 10); 

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

			while (maxShift > 0)
			{
				for (int iter = 0;
					iter < (maxShift > 2 ?
						_info.Iterations :
						(_info.Iterations / 5 * maxShift * _graph.Nodes.Count));
					++iter)
				{
					// Update progress
					if (progress != null)
					{
						if (current % factor == 0)
							progress(current / factor, total);
						current++;
					}

					GraphNode[,] grid = ScrambleGrid(bestGrid, maxShift, iter);
					float estimation = EvaluateGrid(grid, maxShift);

					if (estimation < bestEstimation)
					{
						bestEstimation = estimation;
						bestGrid = grid;
					}
					else
					{
						ApplyGrid(bestGrid);
					}
				}

				maxShift--;
			}

			PlaceObjects(bestGrid);

			// Update progress
			if (progress != null)
				progress(total, total);

			return true;
		}
Esempio n. 4
0
		/// <summary>
		/// Performs the arrangement of the diagram.
		/// </summary>
		public bool Arrange(IGraph graph,
			LayeredLayoutInfo info, LayoutProgress progress)
		{
			_graph = new Graph(graph);
			_info = info;
			_progress = progress;
			_current = 0;
			_total = 
				1 /*path finding*/ + 
				1 /*layers splitting*/ +
				1 /*dummify*/ + 
				6 /*minimize crossings*/ +
				4 /*swap pairs*/ +
				1 /*layout*/ +
				1 /*apply*/ +
				1 /*compact*/ + 
				1 /*dedumify*/;

			// Update progress
			if (_progress != null)
				_progress(_current, _total);

			// Initialize nodes
			foreach (GraphNode node in _graph.Nodes)
			{
				node.SetData(_Layer, -1);
				node.SetData(_UBaryCenter, 0.0);
				node.SetData(_DBaryCenter, 0.0);
				node.SetData(_ULinkCount, 0);
				node.SetData(_DLinkCount, 0);
				node.SetData(_UPriority, 0);
				node.SetData(_DPriority, 0);
				node.SetData(_GridPosition, 0);
				node.SetData(_Dummy, false);
			}

			// Initialize links
			foreach (GraphLink link in _graph.Links)
			{
				link.SetData(_DummificationLevel, 0);
			}

			// Determine the layer depth
			Path longestPath = PathFinder.FindLongestPath(graph, info.TimeLimit);
			if (longestPath == null)
				return true; // No objects in the graph

			// Update progress
			if (_progress != null)
				_progress(_current++, _total);

			_layers = new ArrayList();
			for (int i = 0; i < longestPath.Nodes.Count; i++)
				_layers.Add(new ArrayList());

			// Distribute nodes to their appropriate layers,
			// starting with the nodes from the longest path
			for (int i = 0; i < longestPath.Nodes.Count; i++)
			{
				// Find the corresponding node in the internal graph
				GraphNode node = null;
				foreach (GraphNode n in _graph.Nodes)
				{
					if (n.Node == longestPath.Nodes[i])
					{
						node = n;
						break;
					}
				}

				node.SetData(_Layer, i);
				(_layers[i] as ArrayList).Add(node);
			}

			foreach (INode node in longestPath.Nodes)
			{
				// Find the corresponding node in the internal graph
				GraphNode gnode = null;
				foreach (GraphNode n in _graph.Nodes)
				{
					if (n.Node == node)
					{
						gnode = n;
						break;
					}
				}

				AddChildren(gnode);
			}

			// For all layers whose nodes are > 1 / 20 of the total ->
			// drop nodes. This will ensure that there are no
			// too wide layers, thus improving visibility of the graph.
			int total = 0;
			bool found;
			foreach (ArrayList layer in _layers)
				total += layer.Count;

			int threshold = total / 10;
			if (total > 50 && _info.SplitLayers)
			{
				found = true;
				while (found)
				{
					found = false;

					foreach (ArrayList layer in _layers)
					{
						if (layer.Count > threshold)
						{
							// Find candidates for dropping.
							// Good candidate is a node which
							// when moved downwards will be closer
							// to its children
							SortedList candidates = new SortedList();
							foreach (GraphNode node in layer)
							{
								// Calculate total child depth
								int factor = 0;
								int nodeLayer = (int)node.GetData(_Layer);
								foreach (GraphLink link in node.OutLinks)
								{
									int childLayer = (int)link.Destination.GetData(_Layer);
									if (childLayer <= nodeLayer)
										factor += 1;
									else
										factor -= 1;
								}
								foreach (GraphLink link in node.InLinks)
								{
									int childLayer = (int)link.Origin.GetData(_Layer);
									if (childLayer <= nodeLayer)
										factor += 1;
									else
										factor -= 1;
								}

								if (factor > 0)
									candidates[factor] = node;
							}

							if (candidates.Keys.Count == 0)
								continue;

							found = true;

							ArrayList nextLayer = null;
							int ilayer = _layers.IndexOf(layer);
							if (ilayer == _layers.Count - 1)
							{
								nextLayer = new ArrayList();
								_layers.Add(nextLayer);
							}
							else
							{
								nextLayer = _layers[ilayer + 1] as ArrayList;
							}

							while (layer.Count > threshold)
							{
								if (candidates.Keys.Count == 0)
									break;

								GraphNode node = candidates.GetByIndex(candidates.Count - 1) as GraphNode;
								candidates.RemoveAt(candidates.Count - 1);

								nextLayer.Add(node);
								layer.Remove(node);
								node.SetData(_Layer, (int)node.GetData(_Layer) + 1);
							}
						}

						if (found)
							break;
					}
				}
			}

			// Check if there are directly related nodes on the same layer
			found = true;
			while (found)
			{
				found = false;

				int ilayer = 0;
				ArrayList nodesToDrop = new ArrayList();
				foreach (ArrayList layer in _layers)
				{
					nodesToDrop.Clear();
					foreach (GraphNode node in layer)
					{
						foreach (GraphLink link in node.OutLinks)
						{
							if ((int)link.Destination.GetData(_Layer) == ilayer)
							{
								// The node's child is on the same layer.
								// Mark it for dropping
								if (!nodesToDrop.Contains(link.Destination))
									nodesToDrop.Add(link.Destination);
								found = true;
							}
						}
					}

					// Drop nodes downwards
					if (found)
					{
						ArrayList curLayer = _layers[ilayer] as ArrayList;
						ArrayList nextLayer = null;
						if (ilayer == _layers.Count - 1)
						{
							nextLayer = new ArrayList();
							_layers.Add(nextLayer);
						}
						else
						{
							nextLayer = _layers[ilayer + 1] as ArrayList;
						}

						foreach (GraphNode node in nodesToDrop)
						{
							if (curLayer.Count > 1)
							{
								nextLayer.Add(node);
								curLayer.Remove(node);
								node.SetData(_Layer, (int)node.GetData(_Layer) + 1);
							}
						}

						break;
					}

					ilayer++;
				}
			}


			// Calculate initial grid positions
			foreach (ArrayList layer in _layers)
				for (int i = 0; i < layer.Count; i++)
					(layer[i] as GraphNode).SetData(_GridPosition, (double)i);

			// Update progress
			if (_progress != null)
				_progress(_current++, _total);

			// Add dummy nodes for all links which cross one or more
			// layers. Add one dummy node for each crossed layer
			Dummify();

			// Reduce crossings
			MinimizeCrossings();

			// Further reduce crossings through pair swap
			SwapPairs();

			// Arrange nodes
			Layout();

			// Update progress
			if (_progress != null)
				_progress(_current++, _total);

			// Compact levels
			if (_info.ArrowsCompactFactor != 1)
				Compact();

			// Update progress
			if (_progress != null)
				_progress(_current++, _total);

			Apply();

			// Update progress
			if (_progress != null)
				_progress(_current++, _total);

			// Reverse dummification
			Dedummify();

			// Update progress
			if (_progress != null)
				_progress(_total, _total);

			// Update nodes positions
			foreach (GraphNode node in _graph.Nodes)
				if (node.Node != null)
					node.Node.Bounds = node.Bounds;

			// Update arrow points
			foreach (GraphLink link in _graph.Links)
			{
				if (link.Link != null)
				{
					object points = link.GetData(_LinkPoints);
					if (points != null)
						link.Link.SetPoints(points as ArrayList);
				}
			}

			return true;
		}
Esempio n. 5
0
        public bool Arrange(IGraph graph, AnnealLayoutInfo info, LayoutProgress progress)
        {
            _tempGraph = new Graph(graph);
            _info      = info;

            float nsize = 0;

            foreach (INode node in graph.Nodes)
            {
                nsize += node.Bounds.Width;
            }
            averageNodeSize = nsize / graph.Nodes.Count;

            // determine what the graph boundaries should be
            if (info.LayoutArea != RectangleF.Empty)
            {
                _drawingArea = info.LayoutArea;
            }
            else
            {
                double squareSize = averageNodeSize * Math.Ceiling(Math.Sqrt(graph.Nodes.Count));
                double width      = squareSize * info.WidthHeightRatio;
                double height     = squareSize / info.WidthHeightRatio;
                _drawingArea = new RectangleF(0, 0, (float)width * 4.5f, (float)height * 4.5f);
            }

            // start with random positions
            if (info.Randomize)
            {
                Random rnd = new Random();
                foreach (GraphNode node in _tempGraph.Nodes)
                {
                    node.Center = new PointF(
                        _drawingArea.Left + (float)rnd.NextDouble() * _drawingArea.Width,
                        _drawingArea.Top + (float)rnd.NextDouble() * _drawingArea.Height);
                }
            }

            if (progress != null)
            {
                progress(0, _info.Stages + 2);
            }

            SetGraphElements();
            SetInitStep();
            CalculateInitialState();

            _temperature = _info.Temperature;

            double totalCost = CostFunction();
            double previousCost;
            double stopIterCond;
            Random rand = new Random();

            // cool down for the specified number of annealing stages
            for (int stage = 0; stage < _info.Stages; stage++)
            {
                for (int iter = 0; iter < _info.IterationsPerStage; iter++)
                {
                    previousCost = totalCost;

                    for (int n = 0; n < _tempGraph.Nodes.Count; n++)
                    {
                        double oldNodeCost = evalCost(_nodes[n]);
                        foreach (int i in Enum.GetValues(typeof(ShiftTo)))
                        {
                            ShiftNode(_nodes[n], (ShiftTo)i, false);
                            if (!nodeInBounds(_nodes[n]))
                            {
                                ShiftNode(_nodes[n], (ShiftTo)i, true);
                                continue;
                            }

                            double newNodeCost  = evalCost(_nodes[n]);
                            double newTotalCost = totalCost - oldNodeCost + newNodeCost;

                            if (newNodeCost < oldNodeCost ||
                                Math.Pow(Math.E, (totalCost - newTotalCost) / _temperature) > rand.NextDouble())
                            {
                                totalCost = newTotalCost;
                                CommitMove(_nodes[n]);
                                break;
                            }
                            else
                            {
                                ShiftNode(_nodes[n], (ShiftTo)i, true);
                                RollbackMove(_nodes[n]);
                            }
                        }
                    }

                    stopIterCond = previousCost / totalCost;
                    if (stopIterCond > .98 && stopIterCond <= 1)
                    {
                        break;
                    }
                }

                SetTemperature();
                DecreaseMoveValue();

                if (progress != null)
                {
                    progress(stage + 1, _info.Stages + 2);
                }
            }

            FineTuning();

            if (progress != null)
            {
                progress(_info.Stages + 2, _info.Stages + 2);
            }

            foreach (GraphNode node in _tempGraph.Nodes)
            {
                node.Node.Bounds = node.Bounds;
            }

            return(true);
        }
Esempio n. 6
0
		public bool Arrange(IGraph graph, AnnealLayoutInfo info, LayoutProgress progress)
		{
			_tempGraph = new Graph(graph);
			_info = info;

			float nsize = 0;
			foreach (INode node in graph.Nodes)
				nsize += node.Bounds.Width;
			averageNodeSize = nsize / graph.Nodes.Count;

			// determine what the graph boundaries should be
			if (info.LayoutArea != RectangleF.Empty)
			{
				_drawingArea = info.LayoutArea;
			}
			else
			{
				double squareSize = averageNodeSize * Math.Ceiling(Math.Sqrt(graph.Nodes.Count));
				double width = squareSize * info.WidthHeightRatio;
				double height = squareSize / info.WidthHeightRatio;
				_drawingArea = new RectangleF(0, 0, (float)width * 4.5f, (float)height * 4.5f);
			}

			// start with random positions
			if (info.Randomize)
			{
				Random rnd = new Random();
				foreach (GraphNode node in _tempGraph.Nodes)
				{
					node.Center = new PointF(
						_drawingArea.Left + (float)rnd.NextDouble() * _drawingArea.Width,
						_drawingArea.Top + (float)rnd.NextDouble() * _drawingArea.Height);
				}
			}

			if (progress != null)
				progress(0, _info.Stages + 2);

			SetGraphElements();
			SetInitStep();
			CalculateInitialState();

			_temperature = _info.Temperature;

			double totalCost = CostFunction();
			double previousCost;
			double stopIterCond;
			Random rand = new Random();

			// cool down for the specified number of annealing stages
			for (int stage = 0; stage < _info.Stages; stage++)
			{
				for (int iter = 0; iter < _info.IterationsPerStage; iter++)
				{
					previousCost = totalCost;

					for (int n = 0; n < _tempGraph.Nodes.Count; n++)
					{
						double oldNodeCost = evalCost(_nodes[n]);
						foreach (int i in Enum.GetValues(typeof(ShiftTo)))
						{
							ShiftNode(_nodes[n], (ShiftTo)i, false);
							if (!nodeInBounds(_nodes[n]))
							{
								ShiftNode(_nodes[n], (ShiftTo)i, true);
								continue;
							}

							double newNodeCost = evalCost(_nodes[n]);
							double newTotalCost = totalCost - oldNodeCost + newNodeCost;

							if (newNodeCost < oldNodeCost ||
								Math.Pow(Math.E, (totalCost - newTotalCost) / _temperature) > rand.NextDouble())
							{
								totalCost = newTotalCost;
								CommitMove(_nodes[n]);
								break;
							}
							else
							{
								ShiftNode(_nodes[n], (ShiftTo)i, true);
								RollbackMove(_nodes[n]);
							}
						}
					} 

					stopIterCond = previousCost / totalCost;
					if (stopIterCond > .98 && stopIterCond <= 1)
						break;
				}

				SetTemperature();
				DecreaseMoveValue();

				if (progress != null)
					progress(stage + 1, _info.Stages + 2);
			}

			FineTuning();

			if (progress != null)
				progress(_info.Stages + 2, _info.Stages + 2);

			foreach (GraphNode node in _tempGraph.Nodes)
				node.Node.Bounds = node.Bounds;

			return true;
		}
Esempio n. 7
0
 internal LayoutProgressEventArgs(LayoutProgress progress, string diagnostics)
 {
     this.progress    = progress;
     this.diagnostics = diagnostics;
 }
Esempio n. 8
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;
		}
Esempio n. 9
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);
        }
Esempio n. 10
0
        public bool Arrange(INode rootNode,
                            TreeLayoutInfo info, LayoutProgress progress)
        {
            // Preserve the root position.
            RectangleF rcRoot = rootNode.Bounds;

            _tree = new Tree();
            if (!_tree.Build(rootNode))
            {
                return(false);
            }

            // Place the root at (0, 0)
            TreeNode root = _tree.Root;

            root.Center = new PointF(0, 0);

            // Set root's bisectors
            double deg = 0;

            switch (info.Direction)
            {
            case TreeLayoutDirection.TopToBottom:
                deg = 270;
                break;

            case TreeLayoutDirection.BottomToTop:
                deg = 90;
                break;

            case TreeLayoutDirection.LeftToRight:
                deg = 180;
                break;

            case TreeLayoutDirection.RightToLeft:
                deg = 0;
                break;
            }
            root.SetData(_LeftBisectorData, deg);
            root.SetData(_RightBisectorData, deg + 360);

            // Update progress
            int total   = _tree.TreeLevels.Count;
            int current = 0;

            if (progress != null)
            {
                progress(current++, total);
            }

            // Iterate through all levels and arrange them
            for (int l = 0; l < _tree.TreeLevels.Count - 1; l++)
            {
                // Update progress
                if (progress != null)
                {
                    progress(current++, total);
                }
                ArrangeLevel(l, info);
            }

            // Offset the whole tree structure
            float             xOff = 0;
            float             yOff = 0;
            MethodCallVisitor visitor;

            if (info.KeepRootPosition)
            {
                xOff = rcRoot.Left - root.Bounds.Left;
                yOff = rcRoot.Top - root.Bounds.Top;
            }
            else
            {
                // Calculate the bounding rect of the entire tree's
                visitor = new MethodCallVisitor(new VisitOperation(this.CalcBounds));
                _tree.WalkTree(root, visitor);
                RectangleF rc = (RectangleF)visitor.GetData(_CalcBoundsData);

                xOff = -rc.Left + info.XGap;
                yOff = -rc.Top + info.YGap;
            }
            visitor = new MethodCallVisitor(new VisitOperation(this.Offset));
            visitor.SetData(_XOffsetData, xOff);
            visitor.SetData(_YOffsetData, yOff);
            _tree.WalkTree(root, visitor);

            // Apply the stretch factor
            visitor = new MethodCallVisitor(new VisitOperation(this.Stretch));
            visitor.SetData(_StretchFactor, info.StretchFactor);
            if (info.KeepRootPosition)
            {
                visitor.SetData(_StretchCenter, _tree.Root.Center);
            }
            else
            {
                visitor.SetData(_StretchCenter, new PointF(info.XGap, info.YGap));
            }
            _tree.WalkTree(root, visitor);

            // Apply the arrangement
            visitor = new MethodCallVisitor(new VisitOperation(this.Apply));
            _tree.WalkTree(_tree.Root, visitor);

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

            return(true);
        }
Esempio n. 11
0
        public bool Arrange(INode rootNode,
                            TreeLayoutInfo info, LayoutProgress progress)
        {
            // Preserve the root position.
            RectangleF rcRoot = rootNode.Bounds;

            _tree = new Tree();
            if (!_tree.Build(rootNode))
            {
                return(false);
            }

            int   i, j;
            float sz, s = 0;

            // Calculate the size of each level.
            ArrayList levelSizes = new ArrayList();

            for (i = 0; i < _tree.TreeLevels.Count; i++)
            {
                ArrayList treeLevel = (ArrayList)_tree.TreeLevels[i];

                sz = 0;
                for (j = 0; j < treeLevel.Count; j++)
                {
                    if (info.Direction == TreeLayoutDirection.LeftToRight ||
                        info.Direction == TreeLayoutDirection.RightToLeft)
                    {
                        sz = Math.Max(sz, ((TreeNode)treeLevel[j]).Bounds.Width);
                    }
                    else
                    {
                        sz = Math.Max(sz, ((TreeNode)treeLevel[j]).Bounds.Height);
                    }
                }

                levelSizes.Add(sz);
            }

            // Arrange the bottommost level nodes at equal distance.
            ArrayList lastLevel = (ArrayList)_tree.TreeLevels[_tree.TreeLevels.Count - 1];

            for (i = 0; i < lastLevel.Count; i++)
            {
                TreeNode   node = (TreeNode)lastLevel[i];
                RectangleF rc   = node.Bounds;

                if (info.Direction == TreeLayoutDirection.LeftToRight ||
                    info.Direction == TreeLayoutDirection.RightToLeft)
                {
                    rc.Offset(0, s);
                    s += rc.Height + info.NodeDistance;
                }
                else
                {
                    rc.Offset(s, 0);
                    s += rc.Width + info.NodeDistance;
                }

                node.Bounds = rc;
            }

            // Update progress
            int total   = _tree.TreeLevels.Count;
            int current = 0;

            if (progress != null)
            {
                progress(current++, total);
            }

            // Skip the bottommost level of nodes during arrangement cycle.
            for (i = _tree.TreeLevels.Count - 2; i >= 0; i--)
            {
                // Update progress
                if (progress != null)
                {
                    progress(current++, total);
                }

                ArrayList treeLevel = (ArrayList)_tree.TreeLevels[i];
                for (j = 0; j < treeLevel.Count; j++)
                {
                    TreeNode node = (TreeNode)treeLevel[j];

                    // Make this node in the center of its children.
                    if (node.Children.Count > 0)
                    {
                        ArrayList  children = node.Children;
                        RectangleF rcTotal  = ((TreeNode)children[0]).Bounds;                        // First node's rectangle.
                        for (int c = 1; c < children.Count; c++)
                        {
                            rcTotal = Utilities.UnionRects(rcTotal,
                                                           ((TreeNode)children[c]).Bounds);
                        }

                        RectangleF rc = node.Bounds;
                        if (info.Direction == TreeLayoutDirection.LeftToRight ||
                            info.Direction == TreeLayoutDirection.RightToLeft)
                        {
                            rc.Offset(0,
                                      (rcTotal.Top + rcTotal.Bottom) / 2 - rc.Height / 2);
                        }
                        else
                        {
                            rc.Offset(
                                (rcTotal.Left + rcTotal.Right) / 2 - rc.Width / 2, 0);
                        }
                        node.Bounds = rc;
                    }
                }

                // Check if there is a need to offset branches.
                for (j = 0; j < treeLevel.Count - 1; j++)
                {
                    for (int k = j; k >= 0; k--)
                    {
                        float dist = BranchDistance(info, (TreeNode)treeLevel[k], (TreeNode)treeLevel[j + 1]);

                        if (dist < info.NodeDistance)
                        {
                            if (info.Direction == TreeLayoutDirection.LeftToRight ||
                                info.Direction == TreeLayoutDirection.RightToLeft)
                            {
                                OffsetBranch((TreeNode)treeLevel[j + 1], 0, info.NodeDistance - dist);
                            }
                            else
                            {
                                OffsetBranch((TreeNode)treeLevel[j + 1], info.NodeDistance - dist, 0);
                            }
                        }
                    }
                }
            }

            // Arrange the levels.
            float mh = 0;

            s = 0;

            int iStart;
            int iEnd;
            int iGrow;

            if (info.Direction == TreeLayoutDirection.LeftToRight ||
                info.Direction == TreeLayoutDirection.TopToBottom)
            {
                iStart = 0;
                iEnd   = _tree.TreeLevels.Count;
                iGrow  = +1;
            }
            else
            {
                iStart = _tree.TreeLevels.Count - 1;
                iEnd   = -1;
                iGrow  = -1;
            }

            for (i = iStart;
                 (info.Direction == TreeLayoutDirection.LeftToRight ||
                  info.Direction == TreeLayoutDirection.TopToBottom) ? i <iEnd : i> iEnd;
                 i += iGrow)
            {
                mh = 0;

                ArrayList treeLevel = (ArrayList)_tree.TreeLevels[i];
                for (j = 0; j < treeLevel.Count; j++)
                {
                    TreeNode node = (TreeNode)treeLevel[j];
                    float    o    = 0;

                    if (info.Direction == TreeLayoutDirection.LeftToRight ||
                        info.Direction == TreeLayoutDirection.RightToLeft)
                    {
                        o = node.Bounds.Width;

                        float xoff = 0;
                        if (info.Direction == TreeLayoutDirection.RightToLeft)
                        {
                            xoff = (float)levelSizes[i] - o;
                        }

                        node.Bounds = new RectangleF(
                            s + xoff + info.XGap,
                            node.Bounds.Top + info.YGap,
                            node.Bounds.Width, node.Bounds.Height);
                    }
                    else
                    {
                        o = node.Bounds.Height;

                        float yoff = 0;
                        if (info.Direction == TreeLayoutDirection.BottomToTop)
                        {
                            yoff = (float)levelSizes[i] - o;
                        }

                        node.Bounds = new RectangleF(
                            node.Bounds.Left + info.XGap,
                            s + yoff + info.YGap,
                            node.Bounds.Width, node.Bounds.Height);
                    }

                    mh = Math.Max(mh, o);
                }

                s += mh + info.LevelDistance;
            }

            // Offset the tree as though the root has persisted its position.
            if (info.KeepRootPosition)
            {
                RectangleF rcNewRoot = _tree.Root.Bounds;
                float      xoff      = rcRoot.Left - rcNewRoot.Left;
                float      yoff      = rcRoot.Top - rcNewRoot.Top;

                OffsetBranch(_tree.Root, xoff, yoff);
            }

            // Apply the arrangement
            MethodCallVisitor visitor =
                new MethodCallVisitor(new VisitOperation(this.Apply));

            _tree.WalkTree(_tree.Root, visitor);

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

            return(true);
        }
Esempio n. 12
0
        public bool Arrange(INode rootNode,
                            TreeLayoutInfo info, LayoutProgress progress)
        {
            // Preserve the root position.
            RectangleF rcRoot = rootNode.Bounds;

            _tree = new Tree();
            if (!_tree.Build(rootNode))
            {
                return(false);
            }

            if (info.KeepRootPosition)
            {
                _x = rcRoot.Left;
                _y = rcRoot.Top;
            }
            else
            {
                _x = info.XGap;
                _y = info.YGap;
            }

            _total    = 0;
            _current  = 0;
            _progress = progress;

            // Update progress
            MethodCallVisitor counter = new MethodCallVisitor(
                new VisitOperation(this.Counter));

            _tree.WalkTree(_tree.Root, counter);

            // Make sure total is within reasonable bounds
            float factor = _total / 100;

            if (factor > 1)
            {
                _factor = (int)Math.Floor((double)factor);
                _total  = _total / _factor + 1;
            }

            if (progress != null)
            {
                progress(_current++, _total);
            }

            // Arrange the tree.
            RArrange(_tree.Root, info);

            // Offset levels...

            // Calculate the size of each level.
            int       i, j;
            float     sz;
            ArrayList levelSizes = new ArrayList();

            for (i = 0; i < _tree.TreeLevels.Count; i++)
            {
                ArrayList treeLevel = (ArrayList)_tree.TreeLevels[i];

                sz = 0;
                for (j = 0; j < treeLevel.Count; j++)
                {
                    if (info.Direction == TreeLayoutDirection.LeftToRight ||
                        info.Direction == TreeLayoutDirection.RightToLeft)
                    {
                        sz = Math.Max(sz, ((TreeNode)treeLevel[j]).Bounds.Width);
                    }
                    else
                    {
                        sz = Math.Max(sz, ((TreeNode)treeLevel[j]).Bounds.Height);
                    }
                }

                levelSizes.Add(sz);
            }

            // Perform the offseting.
            float off = 0;

            if (info.KeepRootPosition)
            {
                if (info.Direction == TreeLayoutDirection.BottomToTop)
                {
                    off = rcRoot.Top;
                }
                if (info.Direction == TreeLayoutDirection.RightToLeft)
                {
                    off = rcRoot.Left;
                }
            }
            else
            {
                // Calculate the space needed.
                float size = 0;
                for (int l = 1; l < levelSizes.Count; l++)
                {
                    size += (float)levelSizes[l];
                    size += info.LevelDistance;
                }

                if (info.Direction == TreeLayoutDirection.LeftToRight ||
                    info.Direction == TreeLayoutDirection.RightToLeft)
                {
                    size += info.XGap;
                }
                else
                {
                    size += info.YGap;
                }

                if (info.Direction == TreeLayoutDirection.RightToLeft ||
                    info.Direction == TreeLayoutDirection.BottomToTop)
                {
                    off = size;
                }
            }

            for (i = 0; i < _tree.TreeLevels.Count; i++)
            {
                ArrayList treeLevel = (ArrayList)_tree.TreeLevels[i];
                for (j = 0; j < treeLevel.Count; j++)
                {
                    RectangleF rc = ((TreeNode)treeLevel[j]).Bounds;

                    if (info.Direction == TreeLayoutDirection.TopToBottom ||
                        info.Direction == TreeLayoutDirection.BottomToTop)
                    {
                        rc.Offset(0, off);
                    }
                    else
                    {
                        rc.Offset(off, 0);
                    }

                    ((TreeNode)treeLevel[j]).Bounds = rc;
                }

                switch (info.Direction)
                {
                case TreeLayoutDirection.LeftToRight:
                case TreeLayoutDirection.TopToBottom:
                    off += info.LevelDistance + (float)levelSizes[i];
                    break;

                case TreeLayoutDirection.BottomToTop:
                case TreeLayoutDirection.RightToLeft:
                    off += -(info.LevelDistance + (float)levelSizes[i]);
                    break;
                }
            }

            // Apply the arrangement
            MethodCallVisitor visitor =
                new MethodCallVisitor(new VisitOperation(this.Apply));

            _tree.WalkTree(_tree.Root, visitor);

            // Update progress
            if (progress != null)
            {
                progress(_total, _total);
            }

            return(true);
        }