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;
 }