Ejemplo n.º 1
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;
		}
Ejemplo n.º 2
0
		public bool Arrange(IGraph graph, LayeredLayoutInfo info)
		{
			return Arrange(graph, info, null);
		}