/// <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> /// Returns a PartitionNode instance for the next connected /// component contained in the provided list. The collection /// provided is altered and should not be changed between calls /// to this method. /// </summary> /// <param name="nodeVMs">The collection of node view models to be processed</param> /// <param name="partitionGraphScope">The scope for the paritioned graph</param> /// <param name="originalScope">The scope for the original graph</param> /// <returns>a PartitionNode containing a set of connected nodes</returns> private PartitionNode GetNextConnectedComponent(IList <NodeViewModelBase> nodeVMs, string scope) { // Make sure node view models were provided if (nodeVMs.Count == 0) { return(null); } // Create a new partition node to hold these components PartitionNode partitionNode = new PartitionNode(scope, "PN-" + nodeVMs.Count); // Start at the first nodeVMs List <NodeViewModelBase> visitedNodes = new List <NodeViewModelBase>(); List <NodeViewModelBase> rootNodes = new List <NodeViewModelBase>(); // Add the first node view model to the root and visited lists rootNodes.Add(nodeVMs[0]); visitedNodes.Add(nodeVMs[0]); // Itterate over the root nodes while (rootNodes.Count > 0) { int currentNodeIndex = 0; // Add the current node view model to the // current PartitionNode partitionNode.AddNode(rootNodes[currentNodeIndex]); // Itterate over the node's neighbors foreach (Model.INode node in GetGraphComponents(rootNodes[currentNodeIndex].Scope).Data.Neighbors(rootNodes[currentNodeIndex].ParentNode)) { // Get the nodeVM for this node NodeViewModelBase nodeVM = GetGraphComponents(rootNodes[currentNodeIndex].Scope).GetNodeViewModel(node) as NodeViewModelBase; // Check if this node has already been visisted if (!visitedNodes.Contains(nodeVM)) { // Add this node to our two holder collections rootNodes.Add(nodeVM); visitedNodes.Add(nodeVM); } } // Remove the current node since it has been processed nodeVMs.Remove(rootNodes[currentNodeIndex]); rootNodes.RemoveAt(currentNodeIndex); } return(partitionNode); }
public ICollection<Point> CalculateConvexHullForCluster(PartitionNode pn) { double padding = 0; List<Point> points = new List<Point>(); foreach (NodeViewModelBase nodeVM in pn.Nodes) { points.Add(new Point(nodeVM.Position.X - nodeVM.Width / 2 - padding, nodeVM.Position.Y - nodeVM.Height / 2 - padding)); points.Add(new Point(nodeVM.Position.X - nodeVM.Width / 2 - padding, nodeVM.Position.Y + nodeVM.Height / 2 + padding)); points.Add(new Point(nodeVM.Position.X + nodeVM.Width / 2 + padding, nodeVM.Position.Y + nodeVM.Height / 2 + padding)); points.Add(new Point(nodeVM.Position.X + nodeVM.Width / 2 + padding, nodeVM.Position.Y - nodeVM.Height / 2 - padding)); } return ConvexHull.CalculateConvexHull(points); }
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; }
/// <summary> /// Returns a PartitionNode instance for the next connected /// component contained in the provided list. The collection /// provided is altered and should not be changed between calls /// to this method. /// </summary> /// <param name="nodeVMs">The collection of node view models to be processed</param> /// <param name="partitionGraphScope">The scope for the paritioned graph</param> /// <param name="originalScope">The scope for the original graph</param> /// <returns>a PartitionNode containing a set of connected nodes</returns> private PartitionNode GetNextConnectedComponent(IList<NodeViewModelBase> nodeVMs, string scope) { // Make sure node view models were provided if (nodeVMs.Count == 0) return null; // Create a new partition node to hold these components PartitionNode partitionNode = new PartitionNode(scope, "PN-" + nodeVMs.Count); // Start at the first nodeVMs List<NodeViewModelBase> visitedNodes = new List<NodeViewModelBase>(); List<NodeViewModelBase> rootNodes = new List<NodeViewModelBase>(); // Add the first node view model to the root and visited lists rootNodes.Add(nodeVMs[0]); visitedNodes.Add(nodeVMs[0]); // Itterate over the root nodes while (rootNodes.Count > 0) { int currentNodeIndex = 0; // Add the current node view model to the // current PartitionNode partitionNode.AddNode(rootNodes[currentNodeIndex]); // Itterate over the node's neighbors foreach (Model.INode node in GetGraphComponents(rootNodes[currentNodeIndex].Scope).Data.Neighbors(rootNodes[currentNodeIndex].ParentNode)) { // Get the nodeVM for this node NodeViewModelBase nodeVM = GetGraphComponents(rootNodes[currentNodeIndex].Scope).GetNodeViewModel(node) as NodeViewModelBase; // Check if this node has already been visisted if (!visitedNodes.Contains(nodeVM)) { // Add this node to our two holder collections rootNodes.Add(nodeVM); visitedNodes.Add(nodeVM); } } // Remove the current node since it has been processed nodeVMs.Remove(rootNodes[currentNodeIndex]); rootNodes.RemoveAt(currentNodeIndex); } return partitionNode; }
/// <summary> /// Creates the polygons that represent the highlights for clustered data /// </summary> /// <param name="pn">The partition node containing nodes in the cluster</param> /// <returns>The polygon created for the highlight</returns> private Polygon CreateHighlightPolygon(PartitionNode pn) { PointCollection convexHull = ConvertListOfPointsToPointCollection(_cluster.CalculateConvexHullForCluster(pn)); return DrawHighlightPolygon(convexHull); }
/// <summary> /// /// </summary> /// <param name="initialNode"></param> /// <returns></returns> private PartitionNode GetClusterAsPartitionNode(INodeShape initialNode) { // Determine if the provided node is already // stored in our internal collection. If it // is, return it. if (_nodeToPartition.ContainsKey(initialNode)) return _nodeToPartition[initialNode]; PartitionNode pn = new PartitionNode(_sourceGraph.Scope, "Partition" + (_currentId++).ToString()); _partitionNodes.Add(pn); Dictionary<INodeShape, bool> nodesInCluster = new Dictionary<INodeShape, bool>(); Queue<INodeShape> nodesToTriangulate = new Queue<INodeShape>(); nodesInCluster[initialNode] = true; nodesToTriangulate.Enqueue(initialNode); while (nodesToTriangulate.Count > 0) { List<INodeShape> tempList = FindTrianglesToAdd(nodesToTriangulate.Dequeue(), nodesInCluster); foreach (INodeShape nodeVM in tempList) { // Add the node view model to our queue nodesToTriangulate.Enqueue(nodeVM); } } // Loop over all the node view models in the dictionary foreach (NodeViewModelBase nodeVM in nodesInCluster.Keys) { // Add the node to the partition pn.AddNode(nodeVM); // Save the updated partition node _nodeToPartition[nodeVM] = pn; } return pn; }