private void AddOlapNode(ConstraintGenerator generator, OverlapRemovalCluster olapParentCluster, FiNode filNode, InitialCenterDelegateType nodeCenter) { // If the node already has an mOlapNode, it's already in a cluster (in a different // hierarchy); we just add it to the new cluster. if (null != filNode.getOlapNode(IsHorizontal)) { generator.AddNodeToCluster(olapParentCluster, filNode.getOlapNode(IsHorizontal)); return; } var center = nodeCenter(filNode); // We need to create a new Node in the Generator. if (IsHorizontal) { // Add the Generator node with the X-axis coords primary, Y-axis secondary. filNode.mOlapNodeX = generator.AddNode(olapParentCluster, filNode /* userData */ , center.X, center.Y , filNode.Width, filNode.Height, filNode.stayWeight); } else { // Add the Generator node with the Y-axis coords primary, X-axis secondary. filNode.mOlapNodeY = generator.AddNode(olapParentCluster, filNode /* userData */ , center.Y, center.X , filNode.Height, filNode.Width, filNode.stayWeight); } }
static void ProcessClusterHierarchy(OverlapRemovalCluster root, ClusterDelegate worker) { var stack = new Stack<ClusterItem>(); stack.Push(new ClusterItem(root)); while (stack.Count > 0) { // Keep the cluster on the stack until we're done with its children. var item = stack.Peek(); int prevStackCount = stack.Count; if (!item.ChildrenHaveBeenPushed) { item.ChildrenHaveBeenPushed = true; foreach (var childCluster in item.Cluster.Clusters) { stack.Push(new ClusterItem(childCluster)); } if (stack.Count > prevStackCount) { continue; } } // endif !node.ChildrenHaveBeenPushed // No children to push so pop and process this cluster. Debug.Assert(stack.Peek() == item, "stack.Peek() should be 'item'"); stack.Pop(); worker(item.Cluster); } }
private void AddOlapClusters(ConstraintGenerator generator, OverlapRemovalCluster olapParentCluster, Cluster incClus, InitialCenterDelegateType nodeCenter) { LayoutAlgorithmSettings settings = clusterSettings(incClus); double nodeSeparationH = settings.NodeSeparation; double nodeSeparationV = settings.NodeSeparation + 1e-4; double innerPaddingH = settings.ClusterMargin; double innerPaddingV = settings.ClusterMargin + 1e-4; // Creates the OverlapRemoval (Olap) Cluster/Node objects for our FastIncrementalLayout (FIL) objects. // If !isHorizontal this overwrites the Olap members of the Incremental.Clusters and Msagl.Nodes. // First create the olapCluster for the current incCluster. If olapParentCluster is null, then // incCluster is the root of a new hierarchy. RectangularClusterBoundary rb = incClus.RectangularBoundary; if (IsHorizontal) { rb.olapCluster = generator.AddCluster( olapParentCluster, incClus /* userData */, rb.MinWidth, rb.MinHeight, rb.LeftBorderInfo, rb.RightBorderInfo, rb.BottomBorderInfo, rb.TopBorderInfo); rb.olapCluster.NodePadding = nodeSeparationH; rb.olapCluster.NodePaddingP = nodeSeparationV; rb.olapCluster.ClusterPadding = innerPaddingH; rb.olapCluster.ClusterPaddingP = innerPaddingV; } else { var postXLeftBorderInfo = new BorderInfo(rb.LeftBorderInfo.InnerMargin, rb.Rect.Left, rb.LeftBorderInfo.Weight); var postXRightBorderInfo = new BorderInfo(rb.RightBorderInfo.InnerMargin, rb.Rect.Right, rb.RightBorderInfo.Weight); rb.olapCluster = generator.AddCluster( olapParentCluster, incClus /* userData */, rb.MinHeight, rb.MinWidth, rb.BottomBorderInfo, rb.TopBorderInfo, postXLeftBorderInfo, postXRightBorderInfo); rb.olapCluster.NodePadding = nodeSeparationV; rb.olapCluster.NodePaddingP = nodeSeparationH; rb.olapCluster.ClusterPadding = innerPaddingV; rb.olapCluster.ClusterPaddingP = innerPaddingH; } rb.olapCluster.TranslateChildren = rb.GenerateFixedConstraints; // Note: Incremental.Cluster always creates child List<Cluster|Node> so we don't have to check for null here. // Add our child nodes. foreach (var filNode in incClus.Nodes) { AddOlapNode(generator, rb.olapCluster, (FiNode)filNode.AlgorithmData, nodeCenter); } // Now recurse through all child clusters. foreach (var incChildClus in incClus.Clusters) { AddOlapClusters(generator, rb.olapCluster, incChildClus, nodeCenter); } }
internal OverlapRemovalCluster(uint id, OverlapRemovalCluster parentCluster, object userData, double minSize, double minSizeP, double nodePadding, double nodePaddingP, double clusterPadding, double clusterPaddingP, BorderInfo openBorderInfo, BorderInfo closeBorderInfo, BorderInfo openBorderInfoP, BorderInfo closeBorderInfoP) : base(id, userData) { this.MinimumSize = minSize; this.MinimumSizeP = minSizeP; this.NodePadding = nodePadding; this.NodePaddingP = nodePaddingP; this.ClusterPadding = clusterPadding; this.ClusterPaddingP = clusterPaddingP; this.ParentCluster = parentCluster; this.OpenBorderInfo = openBorderInfo; this.OpenBorderInfo.EnsureWeight(); this.CloseBorderInfo = closeBorderInfo; this.CloseBorderInfo.EnsureWeight(); this.OpenBorderInfoP = openBorderInfoP; this.OpenBorderInfoP.EnsureWeight(); this.CloseBorderInfoP = closeBorderInfoP; this.CloseBorderInfoP.EnsureWeight(); CreateBorderNodes(); }
internal ClusterItem(OverlapRemovalCluster cluster) { this.Cluster = cluster; }
public void AddNodeToCluster(OverlapRemovalCluster cluster, OverlapRemovalNode node) { // Node derives from Cluster so make sure we don't have this - the only way to create // cluster hierarchies is by AddCluster. ValidateArg.IsNotNull(cluster, "cluster"); if (node is OverlapRemovalCluster) { throw new InvalidOperationException( #if DEBUG "Argument 'node' must not be a Cluster" #endif // DEBUG ); } cluster.AddNode(node); }
// Zero cluster margins. This ctor is currently used only by the generator's DefaultClusterHierarchy, // which by default is created with non-fixed borders and no margins. internal OverlapRemovalCluster(uint id, OverlapRemovalCluster parentCluster, object userData, double padding, double paddingP) : this(id, parentCluster, userData, 0, 0, padding, paddingP, 0, 0, new BorderInfo(0.0), new BorderInfo(0.0), new BorderInfo(0.0), new BorderInfo(0.0)) { }
/// <summary> /// Add a Cluster with default border information and specified minimum sizes. /// </summary> /// <param name="parentCluster">The cluster this cluster is to be a member of; if null, this is the root of a /// new hierarchy, otherwise must be non-NULL (perhaps DefaultClusterHierarchy).</param> /// <param name="userData">An object that is passed through.</param> /// <param name="minimumSize">Minimum cluster size along the primary axis.</param> /// <param name="minimumSizeP">Minimum cluster size along the perpendicular axis.</param> /// <returns>The new Cluster.</returns> public OverlapRemovalCluster AddCluster(OverlapRemovalCluster parentCluster, object userData, double minimumSize, double minimumSizeP) { return AddCluster(parentCluster, userData, minimumSize, minimumSizeP, new BorderInfo(0.0), new BorderInfo(0.0), new BorderInfo(0.0), new BorderInfo(0.0)); // 0.0 margins }
/// <summary> /// Add a Cluster with default border information and no minimum sizes. /// </summary> /// <param name="parentCluster">The cluster this cluster is to be a member of; if null, this is the root of a /// new hierarchy, otherwise must be non-NULL (perhaps DefaultClusterHierarchy).</param> /// <param name="userData">An object that is passed through.</param> /// <returns>The new Cluster.</returns> public OverlapRemovalCluster AddCluster(OverlapRemovalCluster parentCluster, object userData) { return AddCluster(parentCluster, userData, new BorderInfo(0.0), new BorderInfo(0.0), new BorderInfo(0.0), new BorderInfo(0.0)); // 0.0 margins }
/// <summary> /// Creates a new cluster with a minimum size within the specified parent cluster. Clusters allow creating a subset of /// nodes that must be within a distinct rectangle. /// </summary> /// <param name="parentCluster">The cluster this cluster is to be a member of; if null, this is the root of a /// new hierarchy, otherwise must be non-NULL (perhaps DefaultClusterHierarchy).</param> /// <param name="userData">An object that is passed through.</param> /// <param name="minimumSize">Minimum cluster size along the primary axis.</param> /// <param name="minimumSizeP">Minimum cluster size along the perpendicular axis.</param> /// <param name="openBorderInfo">Information about the Left (if isHorizontal, else Top) border.</param> /// <param name="closeBorderInfo">Information about the Right (if isHorizontal, else Bottom) border.</param> /// <param name="openBorderInfoP">Same as OpenBorder, but in the secondary (Perpendicular) axis.</param> /// <param name="closeBorderInfoP">Same as CloseBorder, but in the secondary (Perpendicular) axis.</param> /// <returns>The new Cluster.</returns> /// public OverlapRemovalCluster AddCluster(OverlapRemovalCluster parentCluster, object userData, double minimumSize, double minimumSizeP, BorderInfo openBorderInfo, BorderInfo closeBorderInfo, BorderInfo openBorderInfoP, BorderInfo closeBorderInfoP) { var newCluster = new OverlapRemovalCluster(this.nextNodeId, parentCluster, userData, minimumSize, minimumSizeP, this.Padding, this.PaddingP, this.ClusterPadding, this.ClusterPaddingP, openBorderInfo, closeBorderInfo, openBorderInfoP, closeBorderInfoP); this.nextNodeId += OverlapRemovalCluster.NumInternalNodes; if (null == parentCluster) { this.clusterHierarchies.Add(newCluster); } else { // @@DCR: Enforce that Clusters live in only one hierarchy - they can have only one parent, so add a // Cluster.parentCluster to enforce this. parentCluster.AddNode(newCluster); } return newCluster; }
/// <summary> /// Creates a new cluster with no minimum size within the specified parent cluster. Clusters allow creating a subset of /// nodes that must be within a distinct rectangle. /// </summary> /// <param name="parentCluster">The cluster this cluster is to be a member of; if null, this is the root of a /// new hierarchy, otherwise must be non-NULL (perhaps DefaultClusterHierarchy).</param> /// <param name="userData">An object that is passed through.</param> /// <param name="openBorderInfo">Information about the Left (if isHorizontal, else Top) border.</param> /// <param name="closeBorderInfo">Information about the Right (if isHorizontal, else Bottom) border.</param> /// <param name="openBorderInfoP">Same as OpenBorder, but in the secondary (Perpendicular) axis.</param> /// <param name="closeBorderInfoP">Same as CloseBorder, but in the secondary (Perpendicular) axis.</param> /// <returns>The new Cluster.</returns> /// public OverlapRemovalCluster AddCluster(OverlapRemovalCluster parentCluster, object userData, BorderInfo openBorderInfo, BorderInfo closeBorderInfo, BorderInfo openBorderInfoP, BorderInfo closeBorderInfoP) { return AddCluster(parentCluster, userData, 0.0 /*minSize*/, 0.0 /*minSizeP*/, openBorderInfo, closeBorderInfo, openBorderInfoP, closeBorderInfoP); }
/// <summary> /// Add a new variable to the ConstraintGenerator. /// </summary> /// <param name="initialCluster">The cluster this node is to be a member of. It may not be null; pass /// DefaultClusterHierarchy to create a node at the lowest level. Subsequently a node /// may be added to additional clusters, but only to one cluster per hierarchy.</param> /// <param name="userData">An object that is passed through.</param> /// <param name="position">Position of the node in the primary axis; if isHorizontal, it contains horizontal /// position and size, else it contains vertical position and size.</param> /// <param name="size">Size of the node in the primary axis.</param> /// <param name="positionP">Position of the node in the secondary (Perpendicular) axis.</param> /// <param name="sizeP">Size of the node in the secondary (Perpendicular) axis.</param> /// <param name="weight">Weight of the node (indicates how freely it should move).</param> /// <returns>The created node.</returns> public OverlapRemovalNode AddNode(OverlapRemovalCluster initialCluster, object userData, double position, double positionP, double size, double sizeP, double weight) { ValidateArg.IsNotNull(initialCluster, "initialCluster"); // @@PERF: Currently every node will have at least one constraint generated if there are any // other nodes along its line, regardless of whether the perpendicular coordinates result in overlap. // It might be worthwhile to add a check to avoid constraint generation in the case that there cannot // be such an overlap on a line, or if the nodes are separated by some amount of distance. Debug.Assert(null != initialCluster, "initialCluster must not be null"); var nodNew = new OverlapRemovalNode(this.nextNodeId++, userData, position, positionP, size, sizeP, weight); initialCluster.AddNode(nodNew); return nodNew; }