/// <summary> /// Collapse all children (outgoing nodes) for the target node /// </summary> /// <param name="targetNode"></param> private void CollapseNode(NodeViewModelBase targetNode) { List <INode> childNodes = new List <INode>(); List <IEdgeViewModel> edgesToBeRemoved = new List <IEdgeViewModel>(); List <IEdgeViewModel> edgesToBeAdded = new List <IEdgeViewModel>(); List <NodeViewModelBase> nodesToBeRemoved = new List <NodeViewModelBase>(); graph = Data.GraphManager.Instance.GetGraphComponents(targetNode.Scope); // Get all the chidren for the target node childNodes = GetChildren(targetNode.ParentNode); // Ensure we have any child nodes before continuing if (childNodes.Count > 0) { foreach (INode childNode in childNodes) { NodeViewModelBase nodeVM = graph.GetNodeViewModel(childNode) as NodeViewModelBase; foreach (IEdge edge in graph.GetEdges(childNode)) { IEdgeViewModel edgeVM = graph.GetEdgeViewModel(edge); // Determine if this is an incoming edge if (edge.Target == childNode) { // Existing incoming edges need to be removed // and new ones need to be added edgesToBeRemoved.Add(edgeVM); // Determine if this edge's source node is inside // of the child nodes being collapsed if (!childNodes.Contains(edge.Source) && edge.Source != targetNode.ParentNode) { IEdgeViewModel newEdgeVM = (edgeVM as EdgeViewModelBase).Copy(edge.Source, targetNode.ParentNode); edgesToBeAdded.Add(newEdgeVM); } } else // Handle the outgoing edges { // Outgoing edges need to be saved and removed edgesToBeRemoved.Add(edgeVM); } } // Remove (hide) the node //nodeVM.IsHidden = true; nodesToBeRemoved.Add(nodeVM); } graph.RemoveNodeViewModels(nodesToBeRemoved); // Remove (hide) the edges RemoveEdges(edgesToBeRemoved, targetNode); // Add new edges AddEdges(edgesToBeAdded, targetNode); } }
private static GraphMapData GetClusteredGraph(GraphMapData graphMapData, GraphComponents graphComponents) { GraphMapData graphComponentsMapData = new GraphMapData(); IEnumerable <INodeShape> clusteredComponents = graphComponents.GetNodeViewModels(); foreach (PartitionNode clusteredComponent in clusteredComponents) { NodeMapData nodeMapData = new TextNodeMapData(clusteredComponent.ID); graphComponentsMapData.Add(nodeMapData); // Properties object[] dimensionAndPosition = GetPartitionNodeDimensionAndPosition(graphMapData, clusteredComponent); nodeMapData.Dimension = (Size)dimensionAndPosition[0]; nodeMapData.Position = (Point)dimensionAndPosition[1]; nodeMapData.IsHidden = clusteredComponent.IsHidden; IEnumerable <IEdge> clusteredComponentEdges = graphComponents.GetEdges(clusteredComponent); foreach (IEdge clusteredComponentEdge in clusteredComponentEdges) { EdgeMapData edgeMapData = new EdgeMapData(clusteredComponentEdge.Source.ID, clusteredComponentEdge.Target.ID); graphComponentsMapData.Add(edgeMapData); } } return(graphComponentsMapData); }
/// <summary> /// Returns a new GraphComponents instance that represents connected nodes /// as partition nodes /// </summary> /// <param name="Scope">The scope of the graph data being partitioned</param> /// <returns>a GraphComponents instance</returns> public GraphComponents GetConnectedComponents(string _scope) { GraphComponents partitionedGraph = new GraphComponents(_scope); // Get all the node view models contained in the target scope List <NodeViewModelBase> nodeVMs = new List <NodeViewModelBase>(GetGraphComponents(_scope).GetNodeViewModels().Cast <NodeViewModelBase>().ToList()); PartitionNode connectedComponent = GetNextConnectedComponent(nodeVMs, _scope); // Continue getting the next connected component // as long as the last connected component was // not null while (connectedComponent != null) { // Instruct the partition node to calculate its dimensions connectedComponent.RecalculateDimensions(); // Add the partition node to the partion graph partitionedGraph.AddNodeViewModel(connectedComponent); //partitionedGraph.AddNode(connectedComponent); // Get the next connected component connectedComponent = GetNextConnectedComponent(nodeVMs, _scope); } return(partitionedGraph); }
public GraphComponents GetClusteredGraph() { IEnumerable <INodeShape> nodes = _sourceGraph.GetNodeViewModels(); _partitionedGraph = new GraphComponents(_sourceGraph.Scope); // Loop over all the nodes in the list foreach (NodeViewModelBase nodeVM in nodes) { // Create a partition node for clusters PartitionNode pn = GetClusterAsPartitionNode(nodeVM); // Add the partition node to the graph _partitionedGraph.AddNodeViewModel(pn); } // Loop over all of the partition nodes in our partition graph foreach (PartitionNode pn in _partitionNodes) { // Loop over all the external connections foreach (Edge edge in pn.ExternalConnections) { INodeShape targetNodeVM = GraphManager.Instance.GetGraphComponents(_sourceGraph.Scope).GetNodeViewModel(edge.Target); // Check if the edge's target node is in our partition collection if (_nodeToPartition.ContainsKey(targetNodeVM)) { IEdge newEdge = edge.Copy(pn, _nodeToPartition[targetNodeVM]); _partitionedGraph.Data.AddEdge(newEdge); } } } return(_partitionedGraph); }
/// <summary> /// Converts a GraphMapData instance, with data from an import operation, /// to a Graph (GraphComponents) /// </summary> /// <param name="graph">The mapping data to be imported into the Graph</param> /// <param name="graphComponents">The Graph that data is being imported into</param> /// <param name="creationType">The specified CreationType</param> public static void ImportGraph(this GraphMapData graph, GraphComponents graphComponents, CreationType creationType) { // Ensure that valid mapping data was provided if (graph == null) { throw new ArgumentNullException("graph", "No mapping data was provided"); } graphComponents.NodeType = NodeTypes.Text; foreach (NodeMapData objNode in graph.GetNodes()) { if (objNode is IconNodeMapData) { graphComponents.NodeType = NodeTypes.Icon; break; } } // TODO edgedefault? // Loop over the node mapping objects foreach (NodeMapData objNode in graph.GetNodes()) { AddNode(graphComponents, creationType, objNode); } // Edges foreach (EdgeMapData objEdge in graph.GetEdges()) { AddEdge(graphComponents, creationType, objEdge); } }
/// <summary> /// Calculates the rank for the graph specified by the provided scope. /// For ranks normalized between 0 and 1, use the CalculateNormalizedRank /// method. /// </summary> /// <param name="scope">The scope for the graph to be ranked</param> /// <returns>the ranking for the nodes on the graph in the form /// of a dictionary of nodes and their scores. The ranking is /// normalized between 0 and 1.</returns> public override Dictionary <INode, double> CalculateRank(string scope) { // Valid the scope parameter if (string.IsNullOrEmpty(scope)) { throw new ArgumentNullException("Scope", "No scope was provided"); } // Initialize the results dictionary Dictionary <INode, double> results = new Dictionary <INode, double>(); // Get the graph data using the provided scope _graph = GraphManager.Instance.GetGraphComponents(scope); // Iterate over the algorithm multiple times in order // to hone the results to the 'true' value for (int i = 0; i < NumIterations; i++) { // Loop over all the nodes in the graph foreach (INode node in _graph.Nodes) { // Get the degree for the current node results[node] = DetermineNodeRank(node, results); } } return(results); }
public void Directed_graph_components_cycle() { var nodes = new List <GraphNode <int> >() { new GraphNode <int>(0), new GraphNode <int>(1), new GraphNode <int>(2) }; var edges = new List <DirectedEdge <int> >() { new DirectedEdge <int>(nodes[0], nodes[1]), new DirectedEdge <int>(nodes[1], nodes[2]), new DirectedEdge <int>(nodes[2], nodes[0]) }; var graph = new DirectedGraph <int>(nodes, edges); var componentAlgorithms = new GraphComponents <int>(); var connectedComponents = componentAlgorithms.KosarajuScc(graph); Assert.Equal(0, connectedComponents[nodes[0]]); Assert.Equal(0, connectedComponents[nodes[1]]); Assert.Equal(0, connectedComponents[nodes[2]]); }
/// <summary> /// Positions the nodes /// </summary> /// <param name="isAnimated">Indicates whether or not the layout should be animated</param> /// <param name="graphComponents">The object containing the graph data</param> /// <param name="rootNode">Root node</param> public void ComputeLayout(bool isAnimated, GraphComponents graphComponents, INode rootNode) { nodeVMs = graphComponents.GetNodeViewModels().Where(node => !node.IsHidden).ToArray(); positions = new Point[nodeVMs.Length]; edgeCounts = new int[nodeVMs.Length]; nodeIDToIndex = new Dictionary <string, int>(); for (int i = 0; i < nodeVMs.Length; i++) { // Save this nodes position positions[i] = nodeVMs[i].Position; if (nodeVMs[i] is PartitionNode) { nodeIDToIndex[(nodeVMs[i] as PartitionNode).ID] = i; } else { nodeIDToIndex[(nodeVMs[i] as NodeViewModelBase).ParentNode.ID] = i; } // Get a count of all the edges for this node //testcount += GraphComponents.GetNumberOfEdges(nodeVMs[i].ParentNode); List <INodeShape> visitedNeighbors = new List <INodeShape>(); Model.INode currentNode = null; if (nodeVMs[i] is PartitionNode) { currentNode = nodeVMs[i] as Model.INode; } else { currentNode = (nodeVMs[i] as NodeViewModelBase).ParentNode; } // Loop over all the edges for this node foreach (Model.IEdge edge in graphComponents.GetEdges(currentNode)) { // Get the node at the opposite end of this edge INodeShape oppositeNode = graphComponents.GetOppositeNode(edge, currentNode); // Ensure that this edge is not a similarity edge and that // the opposite node has not been visited already if (!(edge is Model.SimilarityDataEdge) && !visitedNeighbors.Contains(oppositeNode)) { edgeCounts[i]++; visitedNeighbors.Add(oppositeNode); } } } // Old version is doing this next call asynchronously if (nodeVMs.Length > 1) { CalculatePositions(graphComponents); } }
public void AddNode(ScriptableNodeMapData scriptableNode) { NodeMapData objNode = ScriptableMapper.GetNode(scriptableNode); GraphComponents graphComponents = GraphManager.Instance.DefaultGraphComponentsInstance; MappingExtensions.AddNode(graphComponents, CreationType.Live, objNode); }
public void RemoveNode(string nodeId) { GraphComponents graphComponents = GraphManager.Instance.DefaultGraphComponentsInstance; GraphData graphData = graphComponents.Data; INode node = graphData.GetNode(nodeId); INodeShape nodeShape = graphComponents.GetNodeViewModel(node); graphComponents.RemoveNodeViewModel(nodeShape); }
/// <summary> /// Performs the actual layout algorithm. This will execute on a background thread. /// </summary> /// <param name="isAnimated">Indicates whether or not the layout should be animated</param> /// <param name="graphComponents">The object containing the graph data</param> /// <param name="rootNode">Root node</param> public void ComputeLayout(bool isAnimated, GraphComponents graphComponents, INode rootNode) { //TODO: NEED TO DECOUPLE THIS GraphViewModel graphVM = ViewModelLocator.GraphDataStatic; List <INodeShape> nodeVMs = graphComponents.GetNodeViewModels().ToList(); // Get all the node view models // Reset the new node position collection nodeToNewPositions.Clear(); // First we determine the amount of space that we are dealing with double totalArea = 0; foreach (INodeShape nodeVMBase in nodeVMs) { double nodeWidth = nodeVMBase.Width + this.margin.Left + this.margin.Right; double nodeHeight = nodeVMBase.Height + this.margin.Top + this.margin.Bottom; totalArea += nodeWidth * nodeHeight; } nodeVMs.Sort(NodeSizeComparer); // Calculate the bounding height and width of our square double boundingHeight = CalculateWidthAndHeight(totalArea); double boundingWidth = boundingHeight * (graphVM.Width / graphVM.Height); boundingHeight = boundingHeight / (graphVM.Width / graphVM.Height); //TODO: THE LINES ABOVE ARE THE ONLY REASON WE ARE COUPLED TO THE GRAPH VIEW MODEL double currentX = 0; double currentY = 0; double maxColumnWidth = 0; double maxHeight = nodeVMs.Max(nodeVM => nodeVM.Height) + margin.Top + margin.Bottom; int columnSize = (int)Math.Round(boundingHeight / maxHeight); //var column = nodeVMs.Take(columnSize); foreach (INodeShape nodeVM in nodeVMs) { if (currentY > boundingHeight) { currentX += maxColumnWidth + margin.Left + margin.Right; maxColumnWidth = 0; currentY = 0; } maxColumnWidth = Math.Max(nodeVM.Width, maxColumnWidth); nodeToNewPositions.Add(nodeVM, new Point(currentX, currentY)); currentY += maxHeight; //currentX += nodeVM.Width + margin.Left + margin.Right; } }
public void RemoveEdge(string sourceId, string targetId) { GraphComponents graphComponents = GraphManager.Instance.DefaultGraphComponentsInstance; GraphData graphData = graphComponents.Data; INode sourceNode = graphData.GetNode(sourceId); IEnumerable <IEdge> sourceNodeEdges = graphData.Edges(sourceNode); IEdge edge = sourceNodeEdges.First <IEdge>(e => e.Source.ID.Equals(sourceId) && e.Target.ID.Equals(targetId)); graphComponents.RemoveEdgeViewModel(edge); }
/// <summary> /// Performs the actual layout algorithm. This will execute on a background thread. /// </summary> /// <param name="isAnimated">Indicates whether or not the layout should be animated</param> /// <param name="graphComponents">The object containing the graph data</param> /// <param name="rootNode">Root node</param> public void ComputeLayout(bool isAnimated, GraphComponents graphComponents, INode rootNode) { //TODO: NEED TO DECOUPLE THIS GraphViewModel graphVM = ViewModelLocator.GraphDataStatic; List<INodeShape> nodeVMs = graphComponents.GetNodeViewModels().ToList(); // Get all the node view models // Reset the new node position collection nodeToNewPositions.Clear(); // First we determine the amount of space that we are dealing with double totalArea = 0; foreach (INodeShape nodeVMBase in nodeVMs) { double nodeWidth = nodeVMBase.Width + this.margin.Left + this.margin.Right; double nodeHeight = nodeVMBase.Height + this.margin.Top + this.margin.Bottom; totalArea += nodeWidth * nodeHeight; } nodeVMs.Sort(NodeSizeComparer); // Calculate the bounding height and width of our square double boundingHeight = CalculateWidthAndHeight(totalArea); double boundingWidth = boundingHeight * (graphVM.Width / graphVM.Height); boundingHeight = boundingHeight / (graphVM.Width / graphVM.Height); //TODO: THE LINES ABOVE ARE THE ONLY REASON WE ARE COUPLED TO THE GRAPH VIEW MODEL double currentX = 0; double currentY = 0; double maxColumnWidth = 0; double maxHeight = nodeVMs.Max(nodeVM => nodeVM.Height) + margin.Top + margin.Bottom; int columnSize = (int)Math.Round(boundingHeight / maxHeight); //var column = nodeVMs.Take(columnSize); foreach (INodeShape nodeVM in nodeVMs) { if (currentY > boundingHeight) { currentX += maxColumnWidth + margin.Left + margin.Right; maxColumnWidth = 0; currentY = 0; } maxColumnWidth = Math.Max(nodeVM.Width, maxColumnWidth); nodeToNewPositions.Add(nodeVM, new Point(currentX, currentY)); currentY += maxHeight; //currentX += nodeVM.Width + margin.Left + margin.Right; } }
public string PerformExport() { // the following is not available because it attempts to open a save file dialog // which can only be initiated via a user clicking a button; security feature of silverlight //GraphManager.Instance.PerformExport(graphComponents.Scope); GraphMLGraphDataFormat graphMlFormat = new GraphMLGraphDataFormat(); GraphComponents graphComponents = GraphManager.Instance.DefaultGraphComponentsInstance; string exportedData = graphMlFormat.Export(graphComponents.Scope); return(exportedData); }
/// <summary> /// Handles the DataLoaded event /// </summary> /// <param name="args">The arguments for the event</param> public void DataLoadedEventHandler(DataLoadedEventArgs args) { GraphComponents graph = GraphManager.Instance.GetGraphComponents(args.Scope); if (graph != null && graph.Data.Order > 0) { IsEnabled = true; } else { IsEnabled = false; } }
/// <summary> /// Performs the actual layout algorithm. /// </summary> /// <param name="graph">The object containing the graph data</param> /// <param name="rootNode">Root node</param> protected override void PerformLayout(GraphMapData graph, INode rootNode) { // this ensures that the end result will remain the same across multiple runs // because each node will have the same starting position new GridLayout().CalculateLayout(graph); System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } // Create a GraphComponents instance that is a partitioned // representation of the original graph. Each node in this // graph is a partition node. GraphComponents connectedGraphComponents = GraphManager.Instance.GetConnectedComponents(GraphManager.Instance.DefaultGraphComponentsInstance.Scope); IEnumerable <INodeShape> connectedComponents = connectedGraphComponents.GetNodeViewModels(); System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } foreach (PartitionNode connectedComponent in connectedComponents) { using (GraphComponents connectedGraph = connectedComponent.GetGraph()) { LayoutByClusters(graph, connectedGraph); } } // Layout the overall graph GraphMapData connectedGraphMapData = GetClusteredGraph(graph, connectedGraphComponents); IDictionary <string, Point> originalPositions = GetOriginalPositions(connectedGraphMapData); GridLayout gridLayout = new GridLayout(); gridLayout.CalculateLayout(connectedGraphMapData); ApplyOffsetToSubGraphs(graph, connectedGraphComponents, originalPositions, connectedGraphMapData); connectedGraphComponents.Dispose(); System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } }
public void Wikipedia_example() { var nodes = new List <GraphNode <char> >() { new GraphNode <char>('a'), new GraphNode <char>('b'), new GraphNode <char>('c'), new GraphNode <char>('d'), new GraphNode <char>('e'), new GraphNode <char>('f'), new GraphNode <char>('g'), new GraphNode <char>('h') }; var edges = new List <DirectedEdge <char> >() { new DirectedEdge <char>(nodes[0], nodes[1]), new DirectedEdge <char>(nodes[1], nodes[2]), new DirectedEdge <char>(nodes[1], nodes[4]), new DirectedEdge <char>(nodes[1], nodes[5]), new DirectedEdge <char>(nodes[2], nodes[3]), new DirectedEdge <char>(nodes[2], nodes[6]), new DirectedEdge <char>(nodes[3], nodes[2]), new DirectedEdge <char>(nodes[3], nodes[7]), new DirectedEdge <char>(nodes[4], nodes[5]), new DirectedEdge <char>(nodes[4], nodes[0]), new DirectedEdge <char>(nodes[5], nodes[6]), new DirectedEdge <char>(nodes[6], nodes[5]), new DirectedEdge <char>(nodes[7], nodes[3]), new DirectedEdge <char>(nodes[7], nodes[6]), }; var graph = new DirectedGraph <char>(nodes, edges); var componentAlgorithms = new GraphComponents <char>(); var connectedComponents = componentAlgorithms.KosarajuScc(graph); Assert.Equal('a', connectedComponents[nodes[0]]); Assert.Equal('a', connectedComponents[nodes[1]]); Assert.Equal('a', connectedComponents[nodes[4]]); Assert.Equal('c', connectedComponents[nodes[2]]); Assert.Equal('c', connectedComponents[nodes[3]]); Assert.Equal('c', connectedComponents[nodes[7]]); Assert.Equal('g', connectedComponents[nodes[5]]); Assert.Equal('g', connectedComponents[nodes[6]]); }
/// <summary> /// Imports the provided data /// </summary> /// <param name="data">The data (in string format) to be imported</param> /// <param name="components">The GraphComponents instance</param> /// <param name="sourceMechanism">Specifies the mechanism for which objects on the graph were imported</param> /// <returns>true if the import was successfull (and contained /// data); otherwise false</returns> public bool Import(string data, GraphComponents components, CreationType sourceMechanism) { _logger.WriteLogEntry(LogLevel.DEBUG, "Import started", null, null); SnaglEventAggregator.DefaultInstance.GetEvent <DataImportingEvent>().Publish(new DataLoadedEventArgs(components.Scope, CreationType.Imported)); // Cal the abstract ImportData method GraphMapData graph = ImportData(data); // Convert the mapping data to GraphComponents graph.ImportGraph(components, sourceMechanism); //MappingExtensions.ImportGraph(graph, components, sourceMechanism); _logger.WriteLogEntry(LogLevel.DEBUG, "Import completed", null, null); SnaglEventAggregator.DefaultInstance.GetEvent <DataImportedEvent>().Publish(new DataLoadedEventArgs(components.Scope, CreationType.Imported)); return(true); }
public void NoEdge_undirected_graph_components() { var nodes = new List <GraphNode <int> >() { new GraphNode <int>(0), new GraphNode <int>(1), new GraphNode <int>(2) }; var edges = new List <UndirectedEdge <int> >(); var graph = new UndirectedGraph <int>(nodes, edges); var componentAlgorithms = new GraphComponents <int>(); var connectedComponents = componentAlgorithms.DfsConnectedComponents(graph); Assert.Equal(0, connectedComponents[nodes[0]]); Assert.Equal(1, connectedComponents[nodes[1]]); Assert.Equal(2, connectedComponents[nodes[2]]); }
/// <summary> /// /// </summary> /// <returns></returns> public GraphComponents GetGraph() { // Validate the internal nodes collection if (nodes.Count == 0) { return(null); } // Get the scope from the first node in the // nodes collection string scope = nodes[0].Scope; // Create a new instance of GraphComponents using the scope // previously obtained from one of the node view models that // is part of this partition node GraphComponents graphComponents = new GraphComponents(scope); List <IEdge> edges = new List <IEdge>(); // Loop over all the node view models, contained in // this partition node, and add them to the new graph foreach (NodeViewModelBase nodeVM in nodes) { // Add this node view model to the graph graphComponents.AddNodeViewModel(nodeVM); // Get all the edges for this node edges.AddRange(GraphManager.Instance.GetGraphComponents(nodeVM.Scope).Data.Edges(nodeVM.ParentNode).ToList()); } // Loop over the edges that were found for all the // nodes in the graph foreach (IEdge edge in edges) { // Ensure that both ends of the edge are in this graph if (graphComponents.Data.ContainsNode(edge.Source) && graphComponents.Data.ContainsNode(edge.Target)) { graphComponents.Data.AddEdge(edge); } } return(graphComponents); }
/// <summary> /// Determines whether there is any data for the given scope /// </summary> /// <param name="scope">The scope of the data being requested</param> /// <returns>true if there is any data present; otherwise false</returns> public bool HasData(string scope) { GraphComponents components = GetGraphComponents(scope); // Check if there are any components present if (components == null) { return(false); } // Check if we have any nodes in the data if (components.Data.Order > 0) { return(true); } else { return(false); } }
private static void ApplyOffsetToSubGraphs(GraphMapData graph, GraphComponents clusteredGraphComponents, IDictionary <string, Point> originalPositions, GraphMapData partitionGraph) { IEnumerable <INodeShape> clusteredComponents = clusteredGraphComponents.GetNodeViewModels(); foreach (PartitionNode clusteredComponent in clusteredComponents) { Point originalPosition = originalPositions[clusteredComponent.ID]; double xOffset = partitionGraph.Nodes[clusteredComponent.ID].Position.X - originalPosition.X; double yOffset = partitionGraph.Nodes[clusteredComponent.ID].Position.Y - originalPosition.Y; IList <NodeViewModelBase> viewModelNodes = clusteredComponent.Nodes; foreach (NodeViewModelBase viewModelNode in viewModelNodes) { NodeMapData nodeMapData = graph.Nodes[viewModelNode.ParentNode.ID]; Point offsetPosition = new Point(nodeMapData.Position.X + xOffset, nodeMapData.Position.Y + yOffset); nodeMapData.Position = offsetPosition; } } }
/// <summary> /// Returns bare-bone graph needed for layouts /// </summary> /// <param name="graphComponents">GraphComponents</param> /// <returns>GraphMapData</returns> public static GraphMapData GetGraph(GraphComponents graphComponents) { GraphMapData graph = new GraphMapData(); // Nodes IEnumerable <INodeShape> uiNodeViewModels = graphComponents.GetNodeViewModels(); foreach (NodeViewModelBase uiNodeVM in uiNodeViewModels) { NodeMapData objNode = new TextNodeMapData(uiNodeVM.ParentNode.ID); graph.Add(objNode); // Properties Size dimension = new Size(uiNodeVM.Width, uiNodeVM.Height); objNode.Dimension = dimension; objNode.Position = uiNodeVM.Position; objNode.IsHidden = uiNodeVM.IsHidden; } // Edges IEnumerable <IEdgeViewModel> uiEdgeViewModels = graphComponents.GetEdgeViewModels(); foreach (EdgeViewModelBase uiEdgeVM in uiEdgeViewModels) { EdgeMapData objEdge = new EdgeMapData(uiEdgeVM.ParentEdge.Source.ID, uiEdgeVM.ParentEdge.Target.ID); graph.Add(objEdge); // Properties objEdge.Type = uiEdgeVM.ParentEdge.Type; SimilarityDataEdge uiSDE = uiEdgeVM.ParentEdge as SimilarityDataEdge; if (uiSDE != null) { objEdge.Weight = uiSDE.Weight; } } return(graph); }
/// <summary> /// Adds a highlight to the graph to indicate which data is clustered together /// </summary> /// <returns>A collection of polygron of clustered highlights on the graph</returns> public ICollection <Polygon> HighlightClusters() { RemoveHighlights(); _cluster = new Cluster(GraphManager.Instance.GetGraphComponents(_scope)); _cluster.EdgePredicate = delegate(Model.IEdge e) { return(e is Model.SimilarityDataEdge); }; GraphComponents clusteredGraph = _cluster.GetClusteredGraph(); foreach (PartitionNode pn in clusteredGraph.GetNodeViewModels()) { if (pn.Nodes.Count > 1) { Polygon highlightPolygon = CreateHighlightPolygon(pn); _clusterPolygons[highlightPolygon] = pn; } } clusteredGraph.Dispose(); _highlightPolygons = _clusterPolygons.Keys; return(_highlightPolygons); }
/// <summary> /// Returns bare-bone graph needed for layouts /// </summary> /// <param name="graphComponents">GraphComponents</param> /// <returns>GraphMapData</returns> public static GraphMapData GetGraph(GraphComponents graphComponents) { GraphMapData graph = new GraphMapData(); // Nodes IEnumerable<INodeShape> uiNodeViewModels = graphComponents.GetNodeViewModels(); foreach (NodeViewModelBase uiNodeVM in uiNodeViewModels) { NodeMapData objNode = new TextNodeMapData(uiNodeVM.ParentNode.ID); graph.Add(objNode); // Properties Size dimension = new Size(uiNodeVM.Width, uiNodeVM.Height); objNode.Dimension = dimension; objNode.Position = uiNodeVM.Position; objNode.IsHidden = uiNodeVM.IsHidden; } // Edges IEnumerable<IEdgeViewModel> uiEdgeViewModels = graphComponents.GetEdgeViewModels(); foreach (EdgeViewModelBase uiEdgeVM in uiEdgeViewModels) { EdgeMapData objEdge = new EdgeMapData(uiEdgeVM.ParentEdge.Source.ID, uiEdgeVM.ParentEdge.Target.ID); graph.Add(objEdge); // Properties objEdge.Type = uiEdgeVM.ParentEdge.Type; SimilarityDataEdge uiSDE = uiEdgeVM.ParentEdge as SimilarityDataEdge; if (uiSDE != null) { objEdge.Weight = uiSDE.Weight; } } return graph; }
/// <summary> /// Converts the provided GraphComponents instance to a GraphMapData /// instance that can be exported to a target file format /// </summary> /// <param name="graphComponents">The graph to be exported</param> /// <returns>A GraphMapData instance ready to be exported to the target format</returns> public static GraphMapData ExportGraph(this GraphComponents graphComponents) { GraphMapData graph = new GraphMapData(); // Nodes IEnumerable <INodeShape> uiNodeViewModels = graphComponents.GetNodeViewModels(); foreach (NodeViewModelBase uiNodeVM in uiNodeViewModels) { NodeMapData objNode = GetNode(uiNodeVM); graph.Add(objNode); } // Edges IEnumerable <IEdgeViewModel> edgeViewModels = graphComponents.GetEdgeViewModels(); foreach (EdgeViewModelBase uiEdge in edgeViewModels) { EdgeMapData objEdge = GetEdge(uiEdge); graph.Add(objEdge); } return(graph); }
private static GraphMapData GetGraph(GraphMapData graphMapData, GraphComponents clusteredGraph) { GraphMapData clusteredGraphMapData = new GraphMapData(); // Nodes IEnumerable <INodeShape> uiNodeViewModels = clusteredGraph.GetNodeViewModels(); foreach (NodeViewModelBase uiNodeVM in uiNodeViewModels) { NodeMapData nodeMapData = graphMapData.Nodes[uiNodeVM.ParentNode.ID]; clusteredGraphMapData.Add(nodeMapData); // Edges IEnumerable <IEdge> uiEdgeViewModels = clusteredGraph.GetEdges(uiNodeVM.ParentNode); foreach (IEdge uiEdgeVM in uiEdgeViewModels) { string edgeKey = uiEdgeVM.Source.ID + uiEdgeVM.Target.ID; EdgeMapData edgeMapData = graphMapData.Edges[edgeKey]; clusteredGraphMapData.Add(edgeMapData); } } return(clusteredGraphMapData); }
/// <summary> /// Collapse all children (outgoing nodes) for the target node /// </summary> /// <param name="targetNode"></param> private void CollapseNode(NodeViewModelBase targetNode) { List<INode> childNodes = new List<INode>(); List<IEdgeViewModel> edgesToBeRemoved = new List<IEdgeViewModel>(); List<IEdgeViewModel> edgesToBeAdded = new List<IEdgeViewModel>(); List<NodeViewModelBase> nodesToBeRemoved = new List<NodeViewModelBase>(); graph = Data.GraphManager.Instance.GetGraphComponents(targetNode.Scope); // Get all the chidren for the target node childNodes = GetChildren(targetNode.ParentNode); // Ensure we have any child nodes before continuing if (childNodes.Count > 0) { foreach (INode childNode in childNodes) { NodeViewModelBase nodeVM = graph.GetNodeViewModel(childNode) as NodeViewModelBase; foreach (IEdge edge in graph.GetEdges(childNode)) { IEdgeViewModel edgeVM = graph.GetEdgeViewModel(edge); // Determine if this is an incoming edge if (edge.Target == childNode) { // Existing incoming edges need to be removed // and new ones need to be added edgesToBeRemoved.Add(edgeVM); // Determine if this edge's source node is inside // of the child nodes being collapsed if (!childNodes.Contains(edge.Source) && edge.Source != targetNode.ParentNode) { IEdgeViewModel newEdgeVM = (edgeVM as EdgeViewModelBase).Copy(edge.Source, targetNode.ParentNode); edgesToBeAdded.Add(newEdgeVM); } } else // Handle the outgoing edges { // Outgoing edges need to be saved and removed edgesToBeRemoved.Add(edgeVM); } } // Remove (hide) the node //nodeVM.IsHidden = true; nodesToBeRemoved.Add(nodeVM); } graph.RemoveNodeViewModels(nodesToBeRemoved); // Remove (hide) the edges RemoveEdges(edgesToBeRemoved, targetNode); // Add new edges AddEdges(edgesToBeAdded, targetNode); } }
/// <summary> /// Calculates the rank for the graph specified by the provided scope. /// For ranks normalized between 0 and 1, use the CalculateNormalizedRank /// method. /// </summary> /// <param name="scope">The scope for the graph to be ranked</param> /// <returns>the ranking for the nodes on the graph in the form /// of a dictionary of nodes and their scores. The ranking is /// normalized between 0 and 1.</returns> public override Dictionary<INode, double> CalculateRank(string scope) { // Valid the scope parameter if (string.IsNullOrEmpty(scope)) throw new ArgumentNullException("Scope", "No scope was provided"); // Initialize the results dictionary Dictionary<INode, double> results = new Dictionary<INode, double>(); // Get the graph data using the provided scope _graph = GraphManager.Instance.GetGraphComponents(scope); // Iterate over the algorithm multiple times in order // to hone the results to the 'true' value for (int i = 0; i < NumIterations; i++) { // Loop over all the nodes in the graph foreach (INode node in _graph.Nodes) { // Get the degree for the current node results[node] = DetermineNodeRank(node, results); } } return results; }
/// <summary> /// Imports the provided data /// </summary> /// <param name="data">The data (in string format) to be imported</param> /// <param name="components">The GraphComponents instance</param> /// <param name="sourceMechanism">Specifies the mechanism for which objects on the graph were imported</param> /// <returns>true if the import was successfull (and contained /// data); otherwise false</returns> public bool Import(string data, GraphComponents components, CreationType sourceMechanism) { _logger.WriteLogEntry(LogLevel.DEBUG, "Import started", null, null); SnaglEventAggregator.DefaultInstance.GetEvent<DataImportingEvent>().Publish(new DataLoadedEventArgs(components.Scope, CreationType.Imported)); // Cal the abstract ImportData method GraphMapData graph = ImportData(data); // Convert the mapping data to GraphComponents graph.ImportGraph(components, sourceMechanism); //MappingExtensions.ImportGraph(graph, components, sourceMechanism); _logger.WriteLogEntry(LogLevel.DEBUG, "Import completed", null, null); SnaglEventAggregator.DefaultInstance.GetEvent<DataImportedEvent>().Publish(new DataLoadedEventArgs(components.Scope, CreationType.Imported)); return true; }
/// <summary> /// /// </summary> /// <returns></returns> public GraphComponents GetGraph() { // Validate the internal nodes collection if (nodes.Count == 0) return null; // Get the scope from the first node in the // nodes collection string scope = nodes[0].Scope; // Create a new instance of GraphComponents using the scope // previously obtained from one of the node view models that // is part of this partition node GraphComponents graphComponents = new GraphComponents(scope); List<IEdge> edges = new List<IEdge>(); // Loop over all the node view models, contained in // this partition node, and add them to the new graph foreach (NodeViewModelBase nodeVM in nodes) { // Add this node view model to the graph graphComponents.AddNodeViewModel(nodeVM); // Get all the edges for this node edges.AddRange(GraphManager.Instance.GetGraphComponents(nodeVM.Scope).Data.Edges(nodeVM.ParentNode).ToList()); } // Loop over the edges that were found for all the // nodes in the graph foreach (IEdge edge in edges) { // Ensure that both ends of the edge are in this graph if (graphComponents.Data.ContainsNode(edge.Source) && graphComponents.Data.ContainsNode(edge.Target)) graphComponents.Data.AddEdge(edge); } return graphComponents; }
private static GraphMapData GetClusteredGraph(GraphMapData graphMapData, GraphComponents graphComponents) { GraphMapData graphComponentsMapData = new GraphMapData(); IEnumerable<INodeShape> clusteredComponents = graphComponents.GetNodeViewModels(); foreach (PartitionNode clusteredComponent in clusteredComponents) { NodeMapData nodeMapData = new TextNodeMapData(clusteredComponent.ID); graphComponentsMapData.Add(nodeMapData); // Properties object[] dimensionAndPosition = GetPartitionNodeDimensionAndPosition(graphMapData, clusteredComponent); nodeMapData.Dimension = (Size)dimensionAndPosition[0]; nodeMapData.Position = (Point)dimensionAndPosition[1]; nodeMapData.IsHidden = clusteredComponent.IsHidden; IEnumerable<IEdge> clusteredComponentEdges = graphComponents.GetEdges(clusteredComponent); foreach (IEdge clusteredComponentEdge in clusteredComponentEdges) { EdgeMapData edgeMapData = new EdgeMapData(clusteredComponentEdge.Source.ID, clusteredComponentEdge.Target.ID); graphComponentsMapData.Add(edgeMapData); } } return graphComponentsMapData; }
/// <summary> /// Creates a new random graph /// </summary> private void CreateRandomGraph(string _scope) { StopWatch stopWatch = StopWatch.StartNew(); GraphComponents components = null; // Check if the provided scope is null or empty if (string.IsNullOrEmpty(_scope)) { // This is a new graph so we will generate new GraphComponents // for it components = new GraphComponents(); } else { // Attempt to get the graph components instance for // the given scope components = GetGraphComponents(_scope); // If we were unable to get an instance, create a // new one if (components == null) components = new GraphComponents(_scope); } // Generate the graph components.GenerateGraph(500, 200); stopWatch.Stop(); System.Diagnostics.Debug.WriteLine("Graph Generated: {0} seconds", stopWatch.Elapsed.Seconds); //TODO: THE NEXT PORTION OF CODE (THAT ADDS OR UPDATES THE COMPONENTS) SHOULD BE RELOCATED TO ITS OWN METHOD // Check if the default instance (which is the first instance // created) has been initialized yet if (this.defaultComponentInstanceScope == string.Empty) { // TODO: ENSURE THIS IS VALID IN THE FUTURE AS THE MAIN GRAPH MAY NOT ALWAYS POPULATE FIRST (BUT SHOULD BE) // Save the newly created components as the default this.defaultComponentInstanceScope = _scope; } // Now we need to update or add the components to the collection of components // Check if the collection has never been initialized if (this.graphComponentsInstances == null) { // Initialize the collection this.graphComponentsInstances = new Dictionary<string, GraphComponents>(); } // Check if we have no items if (this.graphComponentsInstances.Count == 0) { // Add the components instance to the collection this.graphComponentsInstances.Add(components.Scope, components); } else { // Ensure that the scope doesn't already exist if (this.graphComponentsInstances.ContainsKey(components.Scope)) { // Update the components instance for the specified scope this.graphComponentsInstances[components.Scope] = components; } else { // Add the new instance for the specified scope this.graphComponentsInstances.Add(components.Scope, components); } } }
/// <summary> /// /// </summary> public Cluster(GraphComponents graphComponents) { _sourceGraph = graphComponents; }
public GraphComponents GetClusteredGraph() { IEnumerable<INodeShape> nodes = _sourceGraph.GetNodeViewModels(); _partitionedGraph = new GraphComponents(_sourceGraph.Scope); // Loop over all the nodes in the list foreach (NodeViewModelBase nodeVM in nodes) { // Create a partition node for clusters PartitionNode pn = GetClusterAsPartitionNode(nodeVM); // Add the partition node to the graph _partitionedGraph.AddNodeViewModel(pn); } // Loop over all of the partition nodes in our partition graph foreach (PartitionNode pn in _partitionNodes) { // Loop over all the external connections foreach (Edge edge in pn.ExternalConnections) { INodeShape targetNodeVM = GraphManager.Instance.GetGraphComponents(_sourceGraph.Scope).GetNodeViewModel(edge.Target); // Check if the edge's target node is in our partition collection if (_nodeToPartition.ContainsKey(targetNodeVM)) { IEdge newEdge = edge.Copy(pn, _nodeToPartition[targetNodeVM]); _partitionedGraph.Data.AddEdge(newEdge); } } } return _partitionedGraph; }
/// <summary> /// Local attractive force between 2 connected nodesnode /// </summary> /// <param name="distance"></param> /// <param name="neighborCount"></param> /// <param name="edge"></param> /// <param name="graphComponents"></param> /// <returns></returns> protected double LocalForce(double distance, double neighborCount, Model.IEdge edge, GraphComponents graphComponents) { double bigDistanceApart = 60000; double length = K; double stiffness = defaultStiffness; if (neighborCount == 0) { neighborCount = 1; } // Check if the edge we are dealing with is a similarity edge if (edge is Model.SimilarityDataEdge) { Model.SimilarityDataEdge forceDirectedEdge = edge as Model.SimilarityDataEdge; length = forceDirectedEdge.SpringLength; stiffness = forceDirectedEdge.SpringStiffness; } double sourceNodeWidth = 0; double targetNodeWidth = 0; // Get the width for the source node. How we get this depends on // the type of node that we are dealing with. if (edge.Source is PartitionNode) { sourceNodeWidth = (edge.Source as PartitionNode).Width; } else { DispatcherHelper.UIDispatcher.BeginInvoke(() => sourceNodeWidth = graphComponents.GetNodeViewModel(edge.Source).Width); } // Get the width for the target node. How we get this depends on // the type of node that we are dealing with. if (edge.Target is PartitionNode) { targetNodeWidth = (edge.Target as PartitionNode).Width; } else { //targetNodeWidth = GraphComponents.GetNodeViewModel(edge.Target).Width; DispatcherHelper.UIDispatcher.BeginInvoke(() => targetNodeWidth = graphComponents.GetNodeViewModel(edge.Target).Width); } double edgeLength = length + sourceNodeWidth + targetNodeWidth; double distanceMultiplier = Math.Max(Math.Abs(distance - edgeLength) / bigDistanceApart, 1); return((stiffness * distanceMultiplier) * ((distance - edgeLength) / neighborCount)); }
protected void CalculatePositions(GraphComponents graphComponents) { double deltaNorm; double otherNorm; bool converged = false; double T = K; double tolerance = 0.02; double coolingConstant = 0.99; Point tempDelta = new Point(); Point displacement = new Point(); TimeSpan globalForceTimespan = new TimeSpan(); TimeSpan localForceTimespan = new TimeSpan(); TimeSpan indexOfTime = new TimeSpan(); DateTime start; Model.INode currentNode = null; List <int> listOfAllNodeIndices = new List <int>(); // If we aren't partitioning into grids then use all the nodes every time if (!useGraphPartitioning) { for (int i = 0; i < nodeVMs.Length; i++) { listOfAllNodeIndices.Add(i); } } for (int loop = 0; loop < maxIterations && !converged; loop++) { double max = 200; double min = 65; double R = max - ((loop / maxIterations) * (max - min) + min); if (useGraphPartitioning) { // Put all vertices into appropraite cells CalculateNodeCells(R); } converged = true; // Loop over nodes for (int currentNodeIndex = 0; currentNodeIndex < nodeVMs.Length; currentNodeIndex++) { if (nodeVMs[currentNodeIndex] is PartitionNode) { currentNode = nodeVMs[currentNodeIndex] as Model.INode; } else { currentNode = (nodeVMs[currentNodeIndex] as NodeViewModelBase).ParentNode; } displacement = new Point(0, 0); // global repulsive force (huh??) start = DateTime.Now; IList <int> repulsionNodes = null; if (useGraphPartitioning) { // Find all nodes, within a certain distance, to perform repulstion on. // Get nodes within maxDistance from this node. double maxDistance = 50; //TODO: MAKE THIS CONFIGURABLE repulsionNodes = FindNodesForRepulsion(currentNodeIndex, R, maxDistance); } else { // Just repulse all nodes repulsionNodes = listOfAllNodeIndices; } // Loop over all nodes in repulsion list foreach (int i in repulsionNodes) { // We skip this calculation for the current node if (i != currentNodeIndex) { tempDelta.X = positions[i].X - positions[currentNodeIndex].X; tempDelta.Y = positions[i].Y - positions[currentNodeIndex].Y; if (tempDelta.X == 0) { tempDelta.X = random.NextDouble() * .001 * K; } if (tempDelta.Y == 0) { tempDelta.Y = random.NextDouble() * .001 * K; } deltaNorm = Math.Max(1, Math.Abs(tempDelta.X) + Math.Abs(tempDelta.Y)); otherNorm = Math.Abs(positions[i].X + Math.Abs(positions[i].Y)); double globalForce = GlobalForce(deltaNorm, otherNorm); displacement.X += (tempDelta.X / deltaNorm) * globalForce; displacement.Y += (tempDelta.Y / deltaNorm) * globalForce; } } globalForceTimespan += (DateTime.Now - start); // Local forces start = DateTime.Now; // Loop over all the edges for this node foreach (Model.IEdge edge in graphComponents.GetEdges(currentNode)) { DateTime startIndex = DateTime.Now; int index = -1; string nodeID = string.Empty; INodeShape oppositeNode = graphComponents.GetOppositeNode(edge, currentNode); //NodeViewModelBase oppositeNodeVM = GraphComponents.GetOppositeNode(edgeVM.ParentEdge, nodeVMs[currentNode].ParentNode); // Get the ID for the opposite node. How we do this depends // on the type of node that we are dealing with. if (oppositeNode is PartitionNode) { nodeID = (oppositeNode as PartitionNode).ID; } else { nodeID = (oppositeNode as NodeViewModelBase).ParentNode.ID; } if (!nodeIDToIndex.TryGetValue(nodeID, out index)) { continue; } indexOfTime += DateTime.Now - startIndex; if (index != -1) { tempDelta = new Point(positions[index].X - positions[currentNodeIndex].X, positions[index].Y - positions[currentNodeIndex].Y); if (tempDelta.X == 0) { tempDelta.X = random.NextDouble() * .001 * K; } if (tempDelta.Y == 0) { tempDelta.Y = random.NextDouble() * .001 * K; } deltaNorm = Math.Max(Math.Sqrt((tempDelta.X * tempDelta.X) + (tempDelta.Y * tempDelta.Y)), 1); otherNorm = Math.Max(Math.Sqrt((oppositeNode.Position.X * oppositeNode.Position.X) + (oppositeNode.Position.Y * oppositeNode.Position.Y)), 1); double localForce = LocalForce(deltaNorm, edgeCounts[currentNodeIndex], edge, graphComponents); displacement.X += (tempDelta.X / deltaNorm) * localForce; displacement.Y += (tempDelta.Y / deltaNorm) * localForce; } } localForceTimespan += (DateTime.Now - start); // Reposition node (huh??) if (displacement.X == 0) { displacement.X = 1; } double displacementNorm = Math.Sqrt((displacement.X * displacement.X) + (displacement.Y * displacement.Y)); double newX = positions[currentNodeIndex].X + (displacement.X / displacementNorm) * Math.Min(T, displacementNorm); double newY = positions[currentNodeIndex].Y + (displacement.Y / displacementNorm) * Math.Min(T, displacementNorm); tempDelta = new Point(newX - positions[currentNodeIndex].X, newY - positions[currentNodeIndex].Y); positions[currentNodeIndex].X = newX; positions[currentNodeIndex].Y = newY; // no clue what this is doing if (Math.Sqrt((tempDelta.X * tempDelta.X) + (tempDelta.Y * tempDelta.Y)) > K * tolerance) { converged = false; } } // cool (huh??) T *= coolingConstant; } //System.Diagnostics.Debug.WriteLine(globalForceTimespan); //System.Diagnostics.Debug.WriteLine(localForceTimespan); //System.Diagnostics.Debug.WriteLine(indexOfTime); }
/// <summary> /// Adds the specificed node /// </summary> /// <param name="graphComponents">The Graph that data is being imported into</param> /// <param name="creationType">The specified CreationType</param> /// <param name="objNode">Node to be added</param> public static void AddNode(GraphComponents graphComponents, CreationType creationType, NodeMapData objNode) { // Create new node Node uiNode = new Node(objNode.Id); uiNode.SourceMechanism = creationType; // TODO as NodeMapData types expands, this needs to be adjusted NodeTypes uiNodeType = NodeTypes.Simple; if (objNode is IconNodeMapData) { uiNodeType = NodeTypes.Icon; } else if (objNode is TextNodeMapData) { uiNodeType = NodeTypes.Text; } NodeViewModelBase uiNodeVM = NodeViewModelBase.GetNodeViewModel(uiNodeType, uiNode, graphComponents.Scope); // Properties if (uiNodeType == NodeTypes.Icon) { IconNodeMapData objIconNode = (IconNodeMapData)objNode; if (objIconNode.ImageSource != null) { ((IconNodeViewModel)uiNodeVM).ImageSource = objIconNode.ImageSource.ToString(); } } uiNodeVM.Description = objNode.Description; uiNodeVM.DisplayValue = objNode.Label; uiNodeVM.Width = objNode.Dimension.Width; uiNodeVM.Height = objNode.Dimension.Height; uiNodeVM.Position = objNode.Position; uiNodeVM.IsHidden = objNode.IsHidden; SolidColorBrush uiBackgroundColorBrush = new SolidColorBrush(objNode.BackgroundColor); uiNodeVM.BackgroundColor = uiBackgroundColorBrush; SolidColorBrush uiSelectionColorBrush = new SolidColorBrush(objNode.SelectionColor); uiNodeVM.SelectionColor = uiSelectionColorBrush; if (uiNodeVM.Height == 0) { uiNodeVM.Height = 45; } if (uiNodeVM.Width == 0) { uiNodeVM.Width = 45; } // Add the node to the graph graphComponents.AddNodeViewModel(uiNodeVM); // Attributes foreach (KeyValuePair<string, AttributeMapData> objNodeAttrKVP in objNode.Attributes) { Attributes.Attribute uiNodeAttribute = new Attributes.Attribute(objNodeAttrKVP.Value.Name); AttributeValue uiNodeAttributeValue = new AttributeValue(objNodeAttrKVP.Value.Value); uiNode.Attributes.Add(uiNodeAttribute.Name, uiNodeAttributeValue); GlobalAttributeCollection.GetInstance(graphComponents.Scope).Add(uiNodeAttribute, uiNodeAttributeValue); uiNodeAttribute.SemanticType = objNodeAttrKVP.Value.SemanticType; uiNodeAttribute.PreferredSimilarityMeasure = objNodeAttrKVP.Value.SimilarityMeasure; uiNodeAttribute.Visible = !objNodeAttrKVP.Value.IsHidden; } }
private void RankingCompletedHandler(object sender, RankingEventArgs e) { // Remove event handler for currently selected ranker SelectedRanker.RankingCompleted -= RankingCompletedHandler; GraphComponents graph = GraphManager.Instance.DefaultGraphComponentsInstance; List <RankingData> data = new List <RankingData>(); if (_colorVisualizer == null) { _colorVisualizer = new ColorVisualizer(e.Results.Values.Min(), e.Results.Values.Max()); } else { _colorVisualizer.Reset(e.Results.Values.Min(), e.Results.Values.Max()); } _scaleVisualizer = new ScaleVisualizer(); foreach (INode node in e.Results.Keys) { RankingData rankingData = new RankingData { Score = e.Results[node], NodeCount = 1 }; if (data.Contains(rankingData)) { data[data.IndexOf(rankingData)].NodeCount += 1; } else { data.Add(rankingData); } NodeViewModelBase nodeVM = graph.GetNodeViewModel(node) as NodeViewModelBase; if (nodeVM != null) { if ((VisualizationOption & VisualizationOptions.Color) == VisualizationOptions.Color) { _colorVisualizer.Visualize(nodeVM, e.Results[node]); } else { _colorVisualizer.ClearVisualization(nodeVM); } if ((VisualizationOption & VisualizationOptions.Scale) == VisualizationOptions.Scale) { _scaleVisualizer.Visualize(nodeVM, e.Results[node]); } else { _scaleVisualizer.ClearVisualization(nodeVM); } } } Scores = new ObservableCollection <RankingData>(data.OrderBy(rankData => rankData.Score)); IsActive = true; }
/// <summary> /// Returns a new GraphComponents instance that represents connected nodes /// as partition nodes /// </summary> /// <param name="Scope">The scope of the graph data being partitioned</param> /// <returns>a GraphComponents instance</returns> public GraphComponents GetConnectedComponents(string _scope) { GraphComponents partitionedGraph = new GraphComponents(_scope); // Get all the node view models contained in the target scope List<NodeViewModelBase> nodeVMs = new List<NodeViewModelBase>(GetGraphComponents(_scope).GetNodeViewModels().Cast<NodeViewModelBase>().ToList()); PartitionNode connectedComponent = GetNextConnectedComponent(nodeVMs, _scope); // Continue getting the next connected component // as long as the last connected component was // not null while (connectedComponent != null) { // Instruct the partition node to calculate its dimensions connectedComponent.RecalculateDimensions(); // Add the partition node to the partion graph partitionedGraph.AddNodeViewModel(connectedComponent); //partitionedGraph.AddNode(connectedComponent); // Get the next connected component connectedComponent = GetNextConnectedComponent(nodeVMs, _scope); } return partitionedGraph; }
/// <summary> /// Imports GraphML into SnagL on a new graph /// </summary> /// <param name="data">The graph data to place on the graph</param> /// <param name="scope">Specifies the graphs scope</param> /// <param name="format">Specifies the graph data format</param> public void ImportData(string data, string scope, GraphDataFormatBase format) { SnaglEventAggregator.DefaultInstance.GetEvent<UI.TimeConsumingTaskExecutingEvent>().Publish(new UI.TimeConsumingTaskEventArgs()); GraphComponents components = null; // Check if the provided scope is null or empty if (string.IsNullOrEmpty(scope)) { // This is a new graph so we will generate new GraphComponents // for it components = new GraphComponents(); } else { // Attempt to get the graph components instance for // the given scope components = GetGraphComponents(scope); // If we were unable to get an instance, create a // new one if (components == null) components = new GraphComponents(); } components.Clear(); GlobalAttributeCollection.GetInstance(scope).Clear(); // Import the data into the provided components format.Import(data, components, CreationType.Imported); // Check if the default instance (which is the first instance // created) has been initialized yet if (this.defaultComponentInstanceScope == string.Empty) { // TODO: ENSURE THIS IS VALID IN THE FUTURE AS THE MAIN GRAPH MAY NOT ALWAYS POPULATE FIRST (BUT SHOULD BE) // Save the newly created components as the default this.defaultComponentInstanceScope = components.Scope; } // Now we need to update or add the components to the collection of components // Check if the collection has never been initialized if (this.graphComponentsInstances == null) { // Initialize the collection this.graphComponentsInstances = new Dictionary<string, GraphComponents>(); } // Check if we have no items if (this.graphComponentsInstances.Count == 0) { // Add the components instance to the collection this.graphComponentsInstances.Add(components.Scope, components); } else { // Ensure that the scope doesn't already exist if (this.graphComponentsInstances.ContainsKey(components.Scope)) { // Update the components instance for the specified scope this.graphComponentsInstances[components.Scope] = components; } else { // Add the new instance for the specified scope this.graphComponentsInstances.Add(components.Scope, components); } } //TODO MAKE SURE THAT WE HAVE DATA // Fire the DataLoaded event DispatcherHelper.UIDispatcher.BeginInvoke(() => SnaglEventAggregator.DefaultInstance.GetEvent<DataLoadedEvent>().Publish(new DataLoadedEventArgs(components.Scope, CreationType.Imported)) ); SnaglEventAggregator.DefaultInstance.GetEvent<TimeConsumingTaskCompletedEvent>().Publish(new TimeConsumingTaskEventArgs()); }
/// <summary> /// Clusters and lays out the provided graph /// </summary> /// <param name="graphMapData">The graph to update</param> /// <param name="connectedGraph">The graph that needs to be clustered and layed out</param> private static void LayoutByClusters(GraphMapData graphMapData, GraphComponents connectedGraph) { System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } // Create a Cluster instance for the graph //Cluster clusterer = new Cluster(connectedGraph); // Specify the predicate to be used by the Cluster class. In this case // we are determining clusters based on edges createdf during similarity // clustering. //clusterer.EdgePredicate = delegate(IEdge edge) //{ // bool isSimilarityDataEdge = edge is SimilarityDataEdge; // return isSimilarityDataEdge; //}; // Create the clusters and return a new graph. Each node on the // graph will be represented as a PartitionNode //GraphComponents clusteredGraphComponents = clusterer.GetClusteredGraph(); //bool isAttributeLayout = true; // If there is no different between the initial graph that was provided and // out clustered graph, we didn't really find clusters (most likely because // similarity clustering was not performed). //int clusteredNodesCount = clusteredGraphComponents.GetNodeViewModels().Count(); //int connectedNodesCount = connectedGraph.GetNodeViewModels().Count(); //if (clusteredNodesCount == connectedNodesCount) //{ // TODO handle this better than just re-running // Rerun clustering without a predicate. This means that clusters will // be based on regular edges. Cluster clusterer = new Cluster(connectedGraph); GraphComponents clusteredGraphComponents = clusterer.GetClusteredGraph(); bool isAttributeLayout = false; //} System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } // Get all the nodes that are in the clustered graph. Remember that these are partition nodes. IEnumerable<INodeShape> clusteredComponents = clusteredGraphComponents.GetNodeViewModels(); foreach (PartitionNode clusteredComponent in clusteredComponents) { // Create an appropriate layout to use for this cluster AsynchronousLayoutBase clusterLayout = GetClusterLayout(isAttributeLayout); using (GraphComponents clusteredGraph = clusteredComponent.GetGraph()) { GraphMapData clusteredGraphMapData = GetGraph(graphMapData, clusteredGraph); // Run the layout. This is laying out the individual cluster itself clusterLayout.CalculateLayout(clusteredGraphMapData); } System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } } System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } // Now we need to layout the entired clustered graph so it looks more organized GraphMapData clusteredGraphComponentsGraphMapData = GetClusteredGraph(graphMapData, clusteredGraphComponents); IDictionary<string, Point> originalPositions = GetOriginalPositions(clusteredGraphComponentsGraphMapData); FRLayout frLayout = new FRLayout(); frLayout.CalculateLayout(clusteredGraphComponentsGraphMapData); ApplyOffsetToSubGraphs(graphMapData, clusteredGraphComponents, originalPositions, clusteredGraphComponentsGraphMapData); clusteredGraphComponents.Dispose(); System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } }
private static void ApplyOffsetToSubGraphs(GraphMapData graph, GraphComponents clusteredGraphComponents, IDictionary<string, Point> originalPositions, GraphMapData partitionGraph) { IEnumerable<INodeShape> clusteredComponents = clusteredGraphComponents.GetNodeViewModels(); foreach (PartitionNode clusteredComponent in clusteredComponents) { Point originalPosition = originalPositions[clusteredComponent.ID]; double xOffset = partitionGraph.Nodes[clusteredComponent.ID].Position.X - originalPosition.X; double yOffset = partitionGraph.Nodes[clusteredComponent.ID].Position.Y - originalPosition.Y; IList<NodeViewModelBase> viewModelNodes = clusteredComponent.Nodes; foreach (NodeViewModelBase viewModelNode in viewModelNodes) { NodeMapData nodeMapData = graph.Nodes[viewModelNode.ParentNode.ID]; Point offsetPosition = new Point(nodeMapData.Position.X + xOffset, nodeMapData.Position.Y + yOffset); nodeMapData.Position = offsetPosition; } } }
/// <summary> /// Local attractive force between 2 connected nodesnode /// </summary> /// <param name="distance"></param> /// <param name="neighborCount"></param> /// <param name="edge"></param> /// <param name="graphComponents"></param> /// <returns></returns> protected double LocalForce(double distance, double neighborCount, Model.IEdge edge, GraphComponents graphComponents) { double bigDistanceApart = 60000; double length = K; double stiffness = defaultStiffness; if (neighborCount == 0) neighborCount = 1; // Check if the edge we are dealing with is a similarity edge if (edge is Model.SimilarityDataEdge) { Model.SimilarityDataEdge forceDirectedEdge = edge as Model.SimilarityDataEdge; length = forceDirectedEdge.SpringLength; stiffness = forceDirectedEdge.SpringStiffness; } double sourceNodeWidth = 0; double targetNodeWidth = 0; // Get the width for the source node. How we get this depends on // the type of node that we are dealing with. if (edge.Source is PartitionNode) sourceNodeWidth = (edge.Source as PartitionNode).Width; else DispatcherHelper.UIDispatcher.BeginInvoke(() => sourceNodeWidth = graphComponents.GetNodeViewModel(edge.Source).Width); // Get the width for the target node. How we get this depends on // the type of node that we are dealing with. if (edge.Target is PartitionNode) targetNodeWidth = (edge.Target as PartitionNode).Width; else { //targetNodeWidth = GraphComponents.GetNodeViewModel(edge.Target).Width; DispatcherHelper.UIDispatcher.BeginInvoke(() => targetNodeWidth = graphComponents.GetNodeViewModel(edge.Target).Width); } double edgeLength = length + sourceNodeWidth + targetNodeWidth; double distanceMultiplier = Math.Max(Math.Abs(distance - edgeLength) / bigDistanceApart, 1); return (stiffness * distanceMultiplier) * ((distance - edgeLength) / neighborCount); }
private static GraphMapData GetGraph(GraphMapData graphMapData, GraphComponents clusteredGraph) { GraphMapData clusteredGraphMapData = new GraphMapData(); // Nodes IEnumerable<INodeShape> uiNodeViewModels = clusteredGraph.GetNodeViewModels(); foreach (NodeViewModelBase uiNodeVM in uiNodeViewModels) { NodeMapData nodeMapData = graphMapData.Nodes[uiNodeVM.ParentNode.ID]; clusteredGraphMapData.Add(nodeMapData); // Edges IEnumerable<IEdge> uiEdgeViewModels = clusteredGraph.GetEdges(uiNodeVM.ParentNode); foreach (IEdge uiEdgeVM in uiEdgeViewModels) { string edgeKey = uiEdgeVM.Source.ID + uiEdgeVM.Target.ID; EdgeMapData edgeMapData = graphMapData.Edges[edgeKey]; clusteredGraphMapData.Add(edgeMapData); } } return clusteredGraphMapData; }
/// <summary> /// Adds the specificed edge /// </summary> /// <param name="graphComponents">The Graph that data is being imported into</param> /// <param name="creationType">The specified CreationType</param> /// <param name="objEdge">Edge to be added</param> public static void AddEdge(GraphComponents graphComponents, CreationType creationType, EdgeMapData objEdge) { INode uiSourceNode = graphComponents.Data.GetNode(objEdge.Source); if (uiSourceNode == null && creationType == CreationType.Imported) { throw new Exception("Missing Source Node"); } else if (uiSourceNode == null)// && creationType == CreationType.Live { uiSourceNode = new GhostNode(objEdge.Source); } INode uiTargetNode = graphComponents.Data.GetNode(objEdge.Target); if (uiTargetNode == null && creationType == CreationType.Imported) { throw new Exception("Missing Target Node"); } else if (uiTargetNode == null)// && creationType == CreationType.Live { uiTargetNode = new GhostNode(objEdge.Target); } if (string.IsNullOrEmpty(objEdge.Label) && objEdge.Attributes.Count == 0) { Berico.SnagL.Model.Edge uiEdge = new Berico.SnagL.Model.Edge(uiSourceNode, uiTargetNode); uiEdge.SourceMechanism = creationType; // Properties uiEdge.Type = objEdge.Type; // the EdgeViewModel must be created after uiEdge has had a Type specified IEdgeViewModel uiEdgeVM = EdgeViewModelBase.GetEdgeViewModel(uiEdge, graphComponents.Scope); graphComponents.AddEdgeViewModel(uiEdgeVM); } else { DataEdge uiEdge = new DataEdge(uiSourceNode, uiTargetNode); uiEdge.SourceMechanism = creationType; // Properties uiEdge.Type = objEdge.Type; uiEdge.DisplayValue = objEdge.Label; // the EdgeViewModel must be created after uiEdge has had a Type specified IEdgeViewModel uiEdgeVM = EdgeViewModelBase.GetEdgeViewModel(uiEdge, graphComponents.Scope); graphComponents.AddEdgeViewModel(uiEdgeVM); uiEdgeVM.Thickness = objEdge.Thickness; uiEdgeVM.Color = new SolidColorBrush(objEdge.Color); uiEdgeVM.EdgeLine.Text = objEdge.Label; uiEdgeVM.EdgeLine.LabelTextUnderline = objEdge.IsLabelTextUnderlined; uiEdgeVM.EdgeLine.LabelBackgroundColor = new SolidColorBrush(objEdge.LabelBackgroundColor); uiEdgeVM.EdgeLine.LabelForegroundColor = new SolidColorBrush(objEdge.LabelForegroundColor); uiEdgeVM.EdgeLine.LabelFontStyle = objEdge.LabelFontStyle; uiEdgeVM.EdgeLine.LabelFontWeight = objEdge.LabelFontWeight; if (objEdge.LabelFont != null) { uiEdgeVM.EdgeLine.LabelFont = objEdge.LabelFont; } // Attributes foreach (KeyValuePair<string, AttributeMapData> objEdgeAttrKVP in objEdge.Attributes) { Attributes.Attribute uiEdgeAttribute = new Attributes.Attribute(objEdgeAttrKVP.Value.Name); AttributeValue uiEdgeAttributeValue = new AttributeValue(objEdgeAttrKVP.Value.Value); uiEdge.Attributes.Add(uiEdgeAttribute.Name, uiEdgeAttributeValue); //GlobalAttributeCollection.GetInstance(graphComponents.Scope).Add(uiEdgeAttribute, uiEdgeAttributeValue); uiEdgeAttribute.SemanticType = objEdgeAttrKVP.Value.SemanticType; uiEdgeAttribute.PreferredSimilarityMeasure = objEdgeAttrKVP.Value.SimilarityMeasure; uiEdgeAttribute.Visible = !objEdgeAttrKVP.Value.IsHidden; } } }
protected void CalculatePositions(GraphComponents graphComponents) { double deltaNorm; double otherNorm; bool converged = false; double T = K; double tolerance = 0.02; double coolingConstant = 0.99; Point tempDelta = new Point(); Point displacement = new Point(); TimeSpan globalForceTimespan = new TimeSpan(); TimeSpan localForceTimespan = new TimeSpan(); TimeSpan indexOfTime = new TimeSpan(); DateTime start; Model.INode currentNode = null; List<int> listOfAllNodeIndices = new List<int>(); // If we aren't partitioning into grids then use all the nodes every time if (!useGraphPartitioning) { for (int i = 0; i < nodeVMs.Length; i++) { listOfAllNodeIndices.Add(i); } } for (int loop = 0; loop < maxIterations && !converged; loop++) { double max = 200; double min = 65; double R = max - ((loop / maxIterations) * (max - min) + min); if (useGraphPartitioning) { // Put all vertices into appropraite cells CalculateNodeCells(R); } converged = true; // Loop over nodes for (int currentNodeIndex = 0; currentNodeIndex < nodeVMs.Length; currentNodeIndex++) { if (nodeVMs[currentNodeIndex] is PartitionNode) currentNode = nodeVMs[currentNodeIndex] as Model.INode; else currentNode = (nodeVMs[currentNodeIndex] as NodeViewModelBase).ParentNode; displacement = new Point(0, 0); // global repulsive force (huh??) start = DateTime.Now; IList<int> repulsionNodes = null; if (useGraphPartitioning) { // Find all nodes, within a certain distance, to perform repulstion on. // Get nodes within maxDistance from this node. double maxDistance = 50; //TODO: MAKE THIS CONFIGURABLE repulsionNodes = FindNodesForRepulsion(currentNodeIndex, R, maxDistance); } else { // Just repulse all nodes repulsionNodes = listOfAllNodeIndices; } // Loop over all nodes in repulsion list foreach (int i in repulsionNodes) { // We skip this calculation for the current node if (i != currentNodeIndex) { tempDelta.X = positions[i].X - positions[currentNodeIndex].X; tempDelta.Y = positions[i].Y - positions[currentNodeIndex].Y; if (tempDelta.X == 0) tempDelta.X = random.NextDouble() * .001 * K; if (tempDelta.Y == 0) tempDelta.Y = random.NextDouble() * .001 * K; deltaNorm = Math.Max(1, Math.Abs(tempDelta.X) + Math.Abs(tempDelta.Y)); otherNorm = Math.Abs(positions[i].X + Math.Abs(positions[i].Y)); double globalForce = GlobalForce(deltaNorm, otherNorm); displacement.X += (tempDelta.X / deltaNorm) * globalForce; displacement.Y += (tempDelta.Y / deltaNorm) * globalForce; } } globalForceTimespan += (DateTime.Now - start); // Local forces start = DateTime.Now; // Loop over all the edges for this node foreach (Model.IEdge edge in graphComponents.GetEdges(currentNode)) { DateTime startIndex = DateTime.Now; int index = -1; string nodeID = string.Empty; INodeShape oppositeNode = graphComponents.GetOppositeNode(edge, currentNode); //NodeViewModelBase oppositeNodeVM = GraphComponents.GetOppositeNode(edgeVM.ParentEdge, nodeVMs[currentNode].ParentNode); // Get the ID for the opposite node. How we do this depends // on the type of node that we are dealing with. if (oppositeNode is PartitionNode) nodeID = (oppositeNode as PartitionNode).ID; else nodeID = (oppositeNode as NodeViewModelBase).ParentNode.ID; if (!nodeIDToIndex.TryGetValue(nodeID, out index)) { continue; } indexOfTime += DateTime.Now - startIndex; if (index != -1) { tempDelta = new Point(positions[index].X - positions[currentNodeIndex].X, positions[index].Y - positions[currentNodeIndex].Y); if (tempDelta.X == 0) tempDelta.X = random.NextDouble() * .001 * K; if (tempDelta.Y == 0) tempDelta.Y = random.NextDouble() * .001 * K; deltaNorm = Math.Max(Math.Sqrt((tempDelta.X * tempDelta.X) + (tempDelta.Y * tempDelta.Y)), 1); otherNorm = Math.Max(Math.Sqrt((oppositeNode.Position.X * oppositeNode.Position.X) + (oppositeNode.Position.Y * oppositeNode.Position.Y)), 1); double localForce = LocalForce(deltaNorm, edgeCounts[currentNodeIndex], edge, graphComponents); displacement.X += (tempDelta.X / deltaNorm) * localForce; displacement.Y += (tempDelta.Y / deltaNorm) * localForce; } } localForceTimespan+=(DateTime.Now - start); // Reposition node (huh??) if (displacement.X == 0) displacement.X = 1; double displacementNorm = Math.Sqrt((displacement.X * displacement.X) + (displacement.Y * displacement.Y)); double newX = positions[currentNodeIndex].X + (displacement.X / displacementNorm) * Math.Min(T, displacementNorm); double newY = positions[currentNodeIndex].Y + (displacement.Y / displacementNorm) * Math.Min(T, displacementNorm); tempDelta = new Point(newX - positions[currentNodeIndex].X, newY - positions[currentNodeIndex].Y); positions[currentNodeIndex].X = newX; positions[currentNodeIndex].Y = newY; // no clue what this is doing if (Math.Sqrt((tempDelta.X * tempDelta.X) + (tempDelta.Y * tempDelta.Y)) > K * tolerance) converged=false; } // cool (huh??) T *= coolingConstant; } //System.Diagnostics.Debug.WriteLine(globalForceTimespan); //System.Diagnostics.Debug.WriteLine(localForceTimespan); //System.Diagnostics.Debug.WriteLine(indexOfTime); }
/// <summary> /// Clusters and lays out the provided graph /// </summary> /// <param name="graphMapData">The graph to update</param> /// <param name="connectedGraph">The graph that needs to be clustered and layed out</param> private static void LayoutByClusters(GraphMapData graphMapData, GraphComponents connectedGraph) { System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } // Create a Cluster instance for the graph //Cluster clusterer = new Cluster(connectedGraph); // Specify the predicate to be used by the Cluster class. In this case // we are determining clusters based on edges createdf during similarity // clustering. //clusterer.EdgePredicate = delegate(IEdge edge) //{ // bool isSimilarityDataEdge = edge is SimilarityDataEdge; // return isSimilarityDataEdge; //}; // Create the clusters and return a new graph. Each node on the // graph will be represented as a PartitionNode //GraphComponents clusteredGraphComponents = clusterer.GetClusteredGraph(); //bool isAttributeLayout = true; // If there is no different between the initial graph that was provided and // out clustered graph, we didn't really find clusters (most likely because // similarity clustering was not performed). //int clusteredNodesCount = clusteredGraphComponents.GetNodeViewModels().Count(); //int connectedNodesCount = connectedGraph.GetNodeViewModels().Count(); //if (clusteredNodesCount == connectedNodesCount) //{ // TODO handle this better than just re-running // Rerun clustering without a predicate. This means that clusters will // be based on regular edges. Cluster clusterer = new Cluster(connectedGraph); GraphComponents clusteredGraphComponents = clusterer.GetClusteredGraph(); bool isAttributeLayout = false; //} System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } // Get all the nodes that are in the clustered graph. Remember that these are partition nodes. IEnumerable <INodeShape> clusteredComponents = clusteredGraphComponents.GetNodeViewModels(); foreach (PartitionNode clusteredComponent in clusteredComponents) { // Create an appropriate layout to use for this cluster AsynchronousLayoutBase clusterLayout = GetClusterLayout(isAttributeLayout); using (GraphComponents clusteredGraph = clusteredComponent.GetGraph()) { GraphMapData clusteredGraphMapData = GetGraph(graphMapData, clusteredGraph); // Run the layout. This is laying out the individual cluster itself clusterLayout.CalculateLayout(clusteredGraphMapData); } System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } } System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } // Now we need to layout the entired clustered graph so it looks more organized GraphMapData clusteredGraphComponentsGraphMapData = GetClusteredGraph(graphMapData, clusteredGraphComponents); IDictionary <string, Point> originalPositions = GetOriginalPositions(clusteredGraphComponentsGraphMapData); FRLayout frLayout = new FRLayout(); frLayout.CalculateLayout(clusteredGraphComponentsGraphMapData); ApplyOffsetToSubGraphs(graphMapData, clusteredGraphComponents, originalPositions, clusteredGraphComponentsGraphMapData); clusteredGraphComponents.Dispose(); System.Diagnostics.Debug.WriteLine(""); foreach (Delegate d in ContextMenuManager.Instance.GetContextMenuOpeningInvocationList()) { System.Diagnostics.Debug.WriteLine((d.Target as GraphComponents).Scope); } }
/// <summary> /// Positions the nodes /// </summary> /// <param name="isAnimated">Indicates whether or not the layout should be animated</param> /// <param name="graphComponents">The object containing the graph data</param> /// <param name="rootNode">Root node</param> public void ComputeLayout(bool isAnimated, GraphComponents graphComponents, INode rootNode) { nodeVMs = graphComponents.GetNodeViewModels().Where(node => !node.IsHidden).ToArray(); positions = new Point[nodeVMs.Length]; edgeCounts = new int[nodeVMs.Length]; nodeIDToIndex = new Dictionary<string, int>(); for (int i = 0; i < nodeVMs.Length; i++) { // Save this nodes position positions[i] = nodeVMs[i].Position; if (nodeVMs[i] is PartitionNode) nodeIDToIndex[(nodeVMs[i] as PartitionNode).ID] = i; else nodeIDToIndex[(nodeVMs[i] as NodeViewModelBase).ParentNode.ID] = i; // Get a count of all the edges for this node //testcount += GraphComponents.GetNumberOfEdges(nodeVMs[i].ParentNode); List<INodeShape> visitedNeighbors = new List<INodeShape>(); Model.INode currentNode = null; if (nodeVMs[i] is PartitionNode) currentNode = nodeVMs[i] as Model.INode; else currentNode = (nodeVMs[i] as NodeViewModelBase).ParentNode; // Loop over all the edges for this node foreach (Model.IEdge edge in graphComponents.GetEdges(currentNode)) { // Get the node at the opposite end of this edge INodeShape oppositeNode = graphComponents.GetOppositeNode(edge, currentNode); // Ensure that this edge is not a similarity edge and that // the opposite node has not been visited already if (!(edge is Model.SimilarityDataEdge) && !visitedNeighbors.Contains(oppositeNode)) { edgeCounts[i]++; visitedNeighbors.Add(oppositeNode); } } } // Old version is doing this next call asynchronously if (nodeVMs.Length > 1) CalculatePositions(graphComponents); }