/// <summary> /// Creates a large random graph to give the layout algorithms something to chew. /// </summary> private static void BuildGraph(IGraph graph) { graph.Clear(); // Create 400 nodes INode[] nodes = new INode[400]; for (int i = 0; i < nodes.Length; i++) { nodes[i] = graph.CreateNode(); } // Connect the nodes randomly Random random = new Random(0); for (int i = 0; i < nodes.Length; i++) { int edgeCount; if (random.Next(10) == 0) { edgeCount = 4 + random.Next(5); } else { edgeCount = random.Next(3); } for (int j = 0; j < edgeCount; j++) { graph.CreateEdge(nodes[i], nodes[random.Next(nodes.Length)]); } } // remove all components except the largest one var adapter = new YGraphAdapter(graph); NodeList[] components = GraphConnectivity.ConnectedComponents(adapter.YGraph); Array.Sort(components, (o1, o2) => o2.Count - o1.Count); for (int i = components.Length - 1; i > 0; i--) { foreach (var node in components[i]) { graph.Remove(adapter.GetOriginalNode(node)); } } // add labels int count = 0; foreach (var node in graph.Nodes) { graph.AddLabel(node, count++.ToString()); } RandomizeGraph(graph); }
/// <summary> /// Called once the move operation has been initialized /// </summary> /// <remarks> /// Calculates which components stay fixed and which nodes will be moved by the user. /// </remarks> private void OnMoveInitialized(object sender, EventArgs eventArgs) { if (layout != null) { CopiedLayoutGraph copy = this.copiedLayoutGraph; var componentNumber = copy.CreateNodeMap(); GraphConnectivity.ConnectedComponents(copy, componentNumber); System.Collections.Generic.HashSet <int> movedComponents = new System.Collections.Generic.HashSet <int>(); System.Collections.Generic.HashSet <Node> selectedNodes = new System.Collections.Generic.HashSet <Node>(); foreach (INode node in movedNodes) { Node copiedNode = copy.GetCopiedNode(node); if (copiedNode != null) { // remember that we nailed down this node selectedNodes.Add(copiedNode); // remember that we are moving this component movedComponents.Add(componentNumber.GetInt(copiedNode)); //Update the position of the node in the CLG to match the one in the IGraph layout.SetCenter(copiedNode, node.Layout.X + node.Layout.Width * 0.5, node.Layout.Y + node.Layout.Height * 0.5); //Actually, the node itself is fixed at the start of a drag gesture layout.SetInertia(copiedNode, 1.0); //Increasing has the effect that the layout will consider this node as not completely placed... // In this case, the node itself is fixed, but it's neighbors will wake up IncreaseHeat(copiedNode, layout, 0.5); } } // there are components that won't be moved - nail the nodes down so that they don't spread apart infinitely foreach (var copiedNode in copy.Nodes) { if (!movedComponents.Contains(componentNumber.GetInt(copiedNode))) { layout.SetInertia(copiedNode, 1); } else { if (!selectedNodes.Contains(copiedNode)) { // make it float freely layout.SetInertia(copiedNode, 0); } } } // dispose the map copy.DisposeNodeMap(componentNumber); //Notify the layout algorithm that there is new work to do... layout.WakeUp(); } }