/// <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) { double currentAngle = 0D; // Represents the current angle int numNodes = graph.Nodes.Count; double angle = GetAngle(numNodes); double radius = GetRadius(numNodes); // The computed radius of the circle // Loop through each node, perform the appropriate calculations, // then move it to the correct position on the graph. foreach (NodeMapData node in graph.GetNodes()) { if (rootNode != null && node.Id.Equals(rootNode.ID)) { Point position = new Point(0D, 0D); node.Position = position; } else { //Calculate radians double radians = Math.PI * currentAngle / 180D; double x = Math.Cos(radians) * radius; double y = Math.Sin(radians) * radius; Point position = new Point(x, y); node.Position = position; currentAngle += angle; } } }
// GraphML output is not supported, this only outputs SnaglML internal override string ExportData(GraphMapData graph) { string graphMLDocument = string.Empty; using (TextWriter stringWriter = new StringWriter()) { XmlWriterSettings settings = new XmlWriterSettings { CloseOutput = true, ConformanceLevel = ConformanceLevel.Document, Encoding = Encoding.UTF8, Indent = true, IndentChars = " ", NewLineChars = Environment.NewLine, NewLineHandling = NewLineHandling.Replace }; using (XmlWriter writer = XmlWriter.Create(stringWriter, settings)) { WriteHeader(writer, graph); WriteGraphContent(writer, graph); WriteFooter(writer); writer.Flush(); } graphMLDocument = stringWriter.ToString(); } return graphMLDocument; }
/// <summary> /// Performs the actual layout algorithm. This will execute on a background thread. /// </summary> /// <param name="graphData">The object containing the graph data</param> /// <param name="rootNode">Root node</param> protected override Dictionary<INodeShape, NodePosition> PerformLayout(GraphMapData graphData, INode rootNode) { IList<NodeMapData> nodeVMs = new List<NodeMapData>(graphData.GetNodes()); IDictionary<INodeShape, NodePosition> nodes = new Dictionary<INodeShape, NodePosition>(); double currentAngle = 0; // Represents the current angle double radius = GetRadius(nodeVMs); // The computed radius of the circle // Loop through each visible node, perform the appropriate calculations, // then move it to the correct position on the graph. bool firstPass = true; foreach (NodeMapData nodeVM in nodeVMs) { // Determine the angle for the current node if (!firstPass) currentAngle += GetAngle(nodeVM, radius); //Calculate radians (radians = degrees * PI/180) double radians = currentAngle * Math.PI / 180; double x = Math.Cos(radians) * radius; double y = Math.Sin(radians) * radius; // We're no longer on the first pass firstPass = false; // Return the node position nodes.Add(nodeVM, new NodePosition(new Point(x, y), currentAngle)); } return nodes; }
/// <summary> /// Removes node overlap occurring in the input graph /// </summary> /// <param name="graph">GraphMapData</param> public static void FSAOverlapRemoval(GraphMapData graph) { ICollection<NodeMapData> nodes = graph.GetNodes(); IDictionary<string, Rect> rectangles = new Dictionary<string, Rect>(nodes.Count); foreach (NodeMapData node in nodes) { Point location = new Point(node.Position.X, node.Position.Y); Rect rect = new Rect(location, node.Dimension); rectangles[node.Id] = rect; } OverlapRemovalParameters overlapRemovalParameters = new OverlapRemovalParameters() { HorizontalGap = 0F, VerticalGap = 0F }; FSAAlgorithm<string> overlapRemoval = new FSAAlgorithm<string>(rectangles, overlapRemovalParameters); overlapRemoval.Compute(); foreach (NodeMapData node in nodes) { Rect rect = overlapRemoval.Rectangles[node.Id]; Point pos = new Point(rect.X, rect.Y); node.Position = pos; } }
/// <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) { BidirectionalGraph<string, WeightedEdge<string>> bGraph = GraphSharpUtility.GetBidirectionalGraph(graph); IDictionary<string, Vector> nodePositions = GraphSharpUtility.GetNodePositions(graph); KKLayoutParameters kkLayoutParameters = new KKLayoutParameters(); KKLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>> kkLayoutAlgorithm = new KKLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>>(bGraph, nodePositions, kkLayoutParameters); kkLayoutAlgorithm.Compute(); GraphSharpUtility.SetNodePositions(graph, kkLayoutAlgorithm.VertexPositions); GraphSharpUtility.FSAOverlapRemoval(graph); }
/// <summary> /// Performs the actual layout algorithm. /// </summary> /// <param name="graph">The object containing the graph data</param> /// <param name="selectedNode">selected node</param> protected override void PerformLayout(GraphMapData graph, INode selectedNode) { BidirectionalGraph<string, WeightedEdge<string>> bGraph = GraphSharpUtility.GetBidirectionalGraph(graph); IDictionary<string, Vector> nodePositions = GraphSharpUtility.GetNodePositions(graph); IDictionary<string, Size> nodeSizes = GraphSharpUtility.GetNodeSizes(graph); BalloonTreeLayoutParameters balloonTreeLayoutParameters = new BalloonTreeLayoutParameters(); BalloonTreeLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>> balloonTreeLayoutAlgorithm = new BalloonTreeLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>>(bGraph, nodePositions, nodeSizes, balloonTreeLayoutParameters, selectedNode.ID); balloonTreeLayoutAlgorithm.Compute(); GraphSharpUtility.SetNodePositions(graph, balloonTreeLayoutAlgorithm.VertexPositions); }
/// <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) { BidirectionalGraph<string, WeightedEdge<string>> bGraph = GraphSharpUtility.GetBidirectionalGraph(graph); IDictionary<string, Size> nodeSizes = GraphSharpUtility.GetNodeSizes(graph); IDictionary<string, Vector> nodePositions = GraphSharpUtility.GetNodePositions(graph); CompoundFDPLayoutParameters compoundFDPLayoutParameters = new CompoundFDPLayoutParameters(); CompoundFDPLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>> compoundFDPLayoutAlgorithm = new CompoundFDPLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>>(bGraph, nodeSizes, null, null, nodePositions, compoundFDPLayoutParameters); compoundFDPLayoutAlgorithm.Compute(); GraphSharpUtility.SetNodePositions(graph, compoundFDPLayoutAlgorithm.VertexPositions); }
/// <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) { AdjacencyGraph<string, Edge<string>> adjacencyGraph = GraphSharpUtility.GetAdjacencyGraph(graph); IDictionary<string, Size> nodeSizes = GraphSharpUtility.GetNodeSizes(graph); IDictionary<string, Vector> nodePositions = GraphSharpUtility.GetNodePositions(graph); SugiyamaLayoutParameters sugiyamaLayoutParameters = new SugiyamaLayoutParameters(); SugiyamaLayoutAlgorithm<string, Edge<string>, AdjacencyGraph<string, Edge<string>>> sugiyamaLayoutAlgorithm = new SugiyamaLayoutAlgorithm<string, Edge<string>, AdjacencyGraph<string, Edge<string>>>(adjacencyGraph, nodeSizes, nodePositions, sugiyamaLayoutParameters, GetEdgeType); sugiyamaLayoutAlgorithm.Compute(); GraphSharpUtility.SetNodePositions(graph, sugiyamaLayoutAlgorithm.VertexPositions); }
/// <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) { ICollection<NodeMapData> nodes = graph.GetNodes(); // First we determine the amount of space that we are dealing with double totalArea = 0D; foreach (NodeMapData node in nodes) { double nodeWidth = node.Dimension.Width + MARGIN.Left + MARGIN.Right; double nodeHeight = node.Dimension.Height + MARGIN.Top + MARGIN.Bottom; totalArea += nodeWidth * nodeHeight; } // TODO NEED TO DECOUPLE THIS GraphViewModel graphVM = ViewModelLocator.GraphDataStatic; // Calculate the bounding height and width of our square double boundingHeight = Math.Sqrt(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 = 0D; double currentY = 0D; double maxColumnWidth = 0D; double maxHeight = nodes.Max(node => node.Dimension.Height) + MARGIN.Top + MARGIN.Bottom; int columnSize = (int)Math.Round(boundingHeight / maxHeight); List<NodeMapData> nodesList = nodes.ToList<NodeMapData>(); nodesList.Sort(NodeSizeComparer); foreach (NodeMapData node in nodesList) { if (currentY > boundingHeight) { currentX += maxColumnWidth + MARGIN.Left + MARGIN.Right; maxColumnWidth = 0D; currentY = 0D; } maxColumnWidth = Math.Max(node.Dimension.Width, maxColumnWidth); Point position = new Point(currentX, currentY); node.Position = position; currentY += maxHeight; } }
public static Chart GraphToAnb(GraphMapData graph) { Chart chart = new Chart(); chart.chartItemCollection = new ChartItemCollection(); chart.chartItemCollection.chartItems = new Collection<ChartItem>(); foreach (IconNodeMapData node in graph.GetNodes()) { ChartItem chartItem = new ChartItem(); chart.chartItemCollection.chartItems.Add(chartItem); chartItem.attrLabel = node.Label; string hexBackgroundColor = String.Format("#{0:x2}{1:x2}{2:x2}{3:x2}", node.BackgroundColor.A, node.BackgroundColor.R, node.BackgroundColor.G, node.BackgroundColor.B); chartItem.ciStyle = new CIStyle(); chartItem.ciStyle.font = new Font(); chartItem.ciStyle.font.attrBackColour = hexBackgroundColor; chartItem.end = new End(); chartItem.end.entity = new Entity(); chartItem.end.entity.icon = new Icon(); chartItem.end.entity.icon.iconStyle = new IconStyle(); chartItem.attributeCollection = new AttributeCollection(); chartItem.attributeCollection.attributes = new Collection<Anb.Attribute>(); foreach (KeyValuePair<string, AttributeMapData> kvp in node.Attributes) { Anb.Attribute attribute = new Anb.Attribute(); chartItem.attributeCollection.attributes.Add(attribute); attribute.attrAttributeClass = kvp.Key; attribute.attrValue = kvp.Value.Value; } } foreach (EdgeMapData edge in graph.GetEdges()) { ChartItem chartItem = new ChartItem(); chart.chartItemCollection.chartItems.Add(chartItem); chartItem.link = new Link(); chartItem.link.attrEnd1Id = edge.Source; chartItem.link.attrEnd2Id = edge.Target; chartItem.link.linkStyle = new LinkStyle(); chartItem.link.linkStyle.attrType = edge.Label; } return chart; }
/// <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) { AdjacencyGraph<string, Edge<string>> adjacencyGraph = GraphSharpUtility.GetAdjacencyGraph(graph); IDictionary<string, Vector> nodePositions = GraphSharpUtility.GetNodePositions(graph); FreeFRLayoutParameters freeFRLayoutParameters = new FreeFRLayoutParameters() { IdealEdgeLength = 125D }; FRLayoutAlgorithm<string, Edge<string>, AdjacencyGraph<string, Edge<string>>> frLayoutAlgorithm = new FRLayoutAlgorithm<string, Edge<string>, AdjacencyGraph<string, Edge<string>>>(adjacencyGraph, nodePositions, freeFRLayoutParameters); frLayoutAlgorithm.Compute(); GraphSharpUtility.SetNodePositions(graph, frLayoutAlgorithm.VertexPositions); GraphSharpUtility.FSAOverlapRemoval(graph); }
/// <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) { BidirectionalGraph<string, WeightedEdge<string>> bGraph = GraphSharpUtility.GetBidirectionalGraph(graph); IDictionary<string, Vector> nodePositions = GraphSharpUtility.GetNodePositions(graph); LinLogLayoutParameters linLogLayoutParameters = new LinLogLayoutParameters() { AttractionExponent = 2D // Default is 1D }; LinLogLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>> linLogLayoutAlgorithm = new LinLogLayoutAlgorithm<string, WeightedEdge<string>, BidirectionalGraph<string, WeightedEdge<string>>>(bGraph, nodePositions, linLogLayoutParameters); linLogLayoutAlgorithm.Compute(); GraphSharpUtility.SetNodePositions(graph, linLogLayoutAlgorithm.VertexPositions); GraphSharpUtility.FSAOverlapRemoval(graph); }
/// <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); } }
/// <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) { NodeMapData nodeToProcess = null; if (rootNode != null) { nodeToProcess = graph.Nodes[rootNode.ID]; } // Loop over the nodes until they have all been positioned while (processedNodes.Count != graph.Nodes.Count) { // Get the highest rank node that has not already been // positioned if (nodeToProcess == null) { double maxRanking = double.MinValue; // Loop over the nodes looking for the highest ranked one foreach (NodeMapData node in graph.GetNodes()) { double currentRanking = GetNodeRanking(graph, node); if (!processedNodes.Contains(node.Id) && (nodeToProcess == null || maxRanking < currentRanking)) { maxRanking = currentRanking; nodeToProcess = node; } } } // Position the node SaveNodePosition(nodeToProcess, maxXPosition, 0D); processedNodes.Add(nodeToProcess.Id); AddToLayer(nodeToProcess, 0); // Layer the graph CalulateSubtreePosition(graph, nodeToProcess, 1); nodeToProcess = null; } // reset for next run maxXPosition = 0D; processedNodes.Clear(); layers.Clear(); layerSpans.Clear(); }
public static GraphMapData JsonToGraph(TracWrapper tracWrapper) { if (tracWrapper == null) { throw new ArgumentNullException(); } GraphMapData graph = new GraphMapData(); IconNodeMapData seedNode = SeedToNode(tracWrapper.trac.result.seed); graph.Add(seedNode); // by definition Data are guaranteed to not have been seen yet foreach (Data data in tracWrapper.trac.result.datas) { IconNodeMapData dataNode = DataToNode(data); graph.Add(dataNode); EdgeMapData edgeToSeed = new EdgeMapData(seedNode.Id, dataNode.Id); graph.Add(edgeToSeed); // by definition Contact may have already been seen if (data.contacts != null) { foreach (Data contact in data.contacts) { if (!contact.address.Equals(seedNode.Id)) { NodeMapData contactNode; bool nodeAlreadyExists = graph.TryGetNode(contact.address, out contactNode); if (!nodeAlreadyExists) { contactNode = DataToNode(contact); graph.Add(contactNode); } EdgeMapData edgeToData = new EdgeMapData(dataNode.Id, contactNode.Id); graph.Add(edgeToData); } } } } return graph; }
/// <summary> /// Get adjacency graph from input graph /// </summary> /// <param name="graph">GraphMapData</param> /// <returns>AdjacencyGraph</returns> public static AdjacencyGraph<string, Edge<string>> GetAdjacencyGraph(GraphMapData graph) { ICollection<NodeMapData> nodes = graph.GetNodes(); AdjacencyGraph<string, Edge<string>> adjacencyGraph = new AdjacencyGraph<string, Edge<string>>(true, nodes.Count); foreach (NodeMapData node in nodes) { adjacencyGraph.AddVertex(node.Id); } foreach (EdgeMapData edge in graph.GetEdges()) { Edge<string> quickGraphEdge = new Edge<string>(edge.Source, edge.Target); adjacencyGraph.AddEdge(quickGraphEdge); } return adjacencyGraph; }
public static GraphMapData AnbToGraph(Chart chart) { if (chart == null) { throw new ArgumentNullException(); } GraphMapData graph = new GraphMapData(); foreach (ChartItem chartItem in chart.chartItemCollection.chartItems) { if (chartItem.end != null) { IconNodeMapData node = new IconNodeMapData(chartItem.end.entity.attrEntityId); graph.Add(node); node.Label = chartItem.attrLabel; SolidColorBrush backgroundColor = Conversion.HexColorToBrush(chartItem.ciStyle.font.attrBackColour); node.BackgroundColor = backgroundColor.Color; foreach (Anb.Attribute attribute in chartItem.attributeCollection.attributes) { AttributeMapData objAttribute = new AttributeMapData(attribute.attrAttributeClass, attribute.attrValue); node.Attributes.Add(objAttribute.Name, objAttribute); } } else { EdgeMapData edge = new EdgeMapData(chartItem.link.attrEnd1Id, chartItem.link.attrEnd2Id); graph.Add(edge); edge.Label = chartItem.link.linkStyle.attrType; } } return graph; }
/// <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; }
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; } } }
private NodeMapData GetOppositeNode(GraphMapData graph, EdgeMapData edge, NodeMapData node) { if (edge.Source.Equals(node.Id)) { return graph.Nodes[edge.Target]; } else { return graph.Nodes[edge.Source]; } }
/// <summary> /// Determines the ranking of the provided node /// </summary> /// <param name="graph">The object containing the graph data</param> /// <param name="node">The node to get the rank for</param> /// <returns>the rank for this node</returns> private double GetNodeRanking(GraphMapData graph, NodeMapData node) { // Check if we have a custom ranker to use. A custom ranker // is a custom delegate that is used to determine the nodes // rank. if (CustomRootRanker != null) { return CustomRootRanker(node); } else { // As a fallback, determine the nodes rank base on the // number of edges that it has return GetNumberOfEdges(graph, node); } }
/// <summary> /// Calulates the subtrees overall position /// </summary> /// <param name="graph">The object containing the graph data</param> /// <param name="node">The root node view model for this tree</param> /// <param name="layer">The layer (or row in the tree) being analyzed</param> private void CalulateSubtreePosition(GraphMapData graph, NodeMapData node, int layer) { IList<NodeMapData> children = new List<NodeMapData>(); double totalWidth = 0D; //TODO: MAYBE REVISE TO USE GET NEIGHBORS // Loop over the provided nodes edges in order to get its children foreach (EdgeMapData edge in GetNodesEdges(graph, node)) { // TODO: HANDLE EDGE VISIBILITY // Get the node at the opposite end of this edge NodeMapData childNode = GetOppositeNode(graph, edge, node); // Ensure that the node has not already been positioned if (childNode != null && !childNode.IsHidden && !processedNodes.Contains(childNode.Id)) { // Position the node children.Add(childNode); totalWidth += childNode.Dimension.Width; processedNodes.Add(childNode.Id); } } // If there are no children, then we are done if (children.Count == 0) { return; } // Now we need to analyze and lay out all the children as a unit totalWidth += (children.Count - 1D) * NODE_SPACING; double currentX = node.Position.X - ((totalWidth - children[0].Dimension.Width) / 2D); double currentY = node.Position.Y + node.Dimension.Height + LAYER_SPACING; // Determine if the layers overlap double intersectAmount = IntersectsOnLayer(layer, currentX, currentX + totalWidth); // Check if we had an intersection if (intersectAmount != 0) { double pushAmount = intersectAmount / 2D; currentX -= pushAmount; // Give the nodes a little shove so they no longer // intersect with another subtree PushNodesOver(layer, node, pushAmount); // Make sure to push over the nodes in the root layer as well } AddSpanToLayer(layer, currentX, currentX + totalWidth); // Once we get here we have a good position, so we need to set it foreach (NodeMapData currentChildNode in children) { SaveNodePosition(currentChildNode, currentX, currentY); AddToLayer(currentChildNode, layer); currentX += currentChildNode.Dimension.Width + NODE_SPACING; } // Now we need to do the same thing for each // of the children node, recursively foreach (NodeMapData currentChildNode in children) { CalulateSubtreePosition(graph, currentChildNode, layer + 1); } }
private static double GetNumberOfEdges(GraphMapData graph, NodeMapData node) { double numEdges = 0D; foreach (EdgeMapData edge in graph.GetEdges()) { if (edge.Source.Equals(node.Id) || edge.Target.Equals(node.Id)) { numEdges++; } } return numEdges; }
private static ICollection<EdgeMapData> GetNodesEdges(GraphMapData graph, NodeMapData node) { ICollection<EdgeMapData> edges = new List<EdgeMapData>(); foreach (EdgeMapData edge in graph.GetEdges()) { if (edge.Source.Equals(node.Id) || edge.Target.Equals(node.Id)) { edges.Add(edge); } } return edges; }
internal override string ExportData(GraphMapData graph) { Chart chart = GraphToAnb(graph); XmlSerializer anbSerializer = new XmlSerializer(typeof(Chart)); MemoryStream anbStream = new MemoryStream(); string result; anbSerializer.Serialize(anbStream, chart); anbStream.Position = 0; using (TextReader reader = new StreamReader(anbStream)) { result = reader.ReadToEnd(); } return result; }
/// <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 object[] GetPartitionNodeDimensionAndPosition(GraphMapData graphMapData, PartitionNode partitionNode) { Point topLeft = new Point(double.MaxValue, double.MaxValue); Point bottomRight = new Point(double.MinValue, double.MinValue); // Loop through all node view models to get the bounding area foreach (NodeViewModelBase nodeViewModelBase in partitionNode.Nodes) { NodeMapData nodeMapData = graphMapData.Nodes[nodeViewModelBase.ParentNode.ID]; topLeft.X = Math.Min(topLeft.X, nodeMapData.Position.X - nodeMapData.Dimension.Width / 2D); topLeft.Y = Math.Min(topLeft.Y, nodeMapData.Position.Y - nodeMapData.Dimension.Height / 2D); bottomRight.X = Math.Max(bottomRight.X, nodeMapData.Position.X + nodeMapData.Dimension.Width / 2D); bottomRight.Y = Math.Max(bottomRight.Y, nodeMapData.Position.Y + nodeMapData.Dimension.Height / 2D); } // Set the new dimensions based on the calculation performed double width = Math.Max(bottomRight.X - topLeft.X, 1D); double height = Math.Max(bottomRight.Y - topLeft.Y, 1D); Size dimension = new Size(width, height); // get the center of the partitionNode Point position = new Point(topLeft.X + width / 2D, topLeft.Y + height / 2D); object[] result = new object[] { dimension, position }; return result; }
private static IDictionary<string, Point> GetOriginalPositions(GraphMapData clusteredGraphMapData) { ICollection<NodeMapData> nodes = clusteredGraphMapData.GetNodes(); IDictionary<string, Point> originalPositions = new Dictionary<string, Point>(nodes.Count); foreach (NodeMapData node in nodes) { originalPositions[node.Id] = node.Position; } return originalPositions; }
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; }
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; }