void WriteClusterRectBoundary(RectangularClusterBoundary recClBnd) { if (recClBnd == null) { return; } WriteStartElement(GeometryToken.RectangularClusterBoundary); WriteAttribute(GeometryToken.LeftMargin, recClBnd.LeftMargin); WriteAttribute(GeometryToken.RightMargin, recClBnd.RightMargin); WriteAttribute(GeometryToken.TopMargin, recClBnd.TopMargin); WriteAttribute(GeometryToken.BottomMargin, recClBnd.BottomMargin); if (recClBnd.DefaultMarginIsSet) { WriteAttribute(GeometryToken.DefaultLeftMargin, recClBnd.DefaultLeftMargin); WriteAttribute(GeometryToken.DefaultRightMargin, recClBnd.DefaultRightMargin); WriteAttribute(GeometryToken.DefaultTopMargin, recClBnd.DefaultTopMargin); WriteAttribute(GeometryToken.DefaultBottomMargin, recClBnd.DefaultBottomMargin); } WriteAttribute(GeometryToken.GenerateFixedConstraints, recClBnd.GenerateFixedConstraints); WriteAttribute(GeometryToken.GenerateFixedConstraintsDefault, recClBnd.GenerateFixedConstraintsDefault); WriteAttribute(GeometryToken.MinNodeHeight, recClBnd.MinHeight); WriteAttribute(GeometryToken.MinNodeWidth, recClBnd.MinWidth); WriteRect(recClBnd.Rect.Left, recClBnd.Rect.Bottom, recClBnd.Rect.Width, recClBnd.Rect.Height, recClBnd.RadiusX, recClBnd.RadiusY); WriteBorderInfo(GeometryToken.RightBorderInfo, recClBnd.RightBorderInfo); WriteBorderInfo(GeometryToken.LeftBorderInfo, recClBnd.LeftBorderInfo); WriteBorderInfo(GeometryToken.TopBorderInfo, recClBnd.TopBorderInfo); WriteBorderInfo(GeometryToken.BottomBorderInfo, recClBnd.BottomBorderInfo); WriteEndElement(); }
/// <summary> /// Sets the weight of the node (the FINode actually) to the weight required by this lock. /// If the node is a Cluster then: /// - its boundaries are locked /// - all of its descendant nodes have their lock weight set /// - all of its descendant clusters are set to generate fixed constraints (so they don't get squashed) /// Then, the node (or clusters) parents (all the way to the root) have their borders set to generate unfixed constraints /// (so that this node can move freely inside its ancestors /// </summary> internal void SetLockNodeWeight() { Cluster cluster = node as Cluster; if (cluster != null) { RectangularClusterBoundary cb = cluster.RectangularBoundary; cb.Lock(Bounds.Left, Bounds.Right, Bounds.Top, Bounds.Bottom); foreach (var c in cluster.AllClustersDepthFirst()) { c.RectangularBoundary.GenerateFixedConstraints = true; foreach (var child in c.Nodes) { SetFINodeWeight(child, weight); } } } else { SetFINodeWeight(node, weight); } foreach (Cluster ancestor in this.node.AllClusterAncestors) { if (ancestor.RectangularBoundary != null) { ancestor.RectangularBoundary.GenerateFixedConstraints = false; } ancestor.UnsetInitialLayoutState(); } }
/// <summary> /// sets IsInitialLayoutState to false and restores the default margins if we have a RectangularBoundary /// </summary> public void UnsetInitialLayoutState() { isInInitialLayoutState = false; RectangularClusterBoundary rb = RectangularBoundary; if (rb != null) { rb.RestoreDefaultMargin(); } }
/// <summary> /// Set the initial layout state such that our current margin is stored and the new margin is taken from the given rb /// </summary> public void SetInitialLayoutState(RectangularClusterBoundary bounds) { isInInitialLayoutState = true; if (RectangularBoundary != null && bounds != null) { RectangularBoundary.StoreDefaultMargin(); RectangularBoundary.LeftMargin = bounds.LeftMargin; RectangularBoundary.RightMargin = bounds.RightMargin; RectangularBoundary.BottomMargin = bounds.BottomMargin; RectangularBoundary.TopMargin = bounds.TopMargin; } }
private void UpdateOlapClusters(IEnumerable <Cluster> incClusters) { foreach (var incClus in incClusters) { RectangularClusterBoundary rb = incClus.RectangularBoundary; // Because two heavily-weighted nodes can force each other to move, we have to update // any BorderInfos that are IsFixedPosition to reflect this possible movement; for example, // a fixed border and a node being dragged will both have heavy weights. if (IsHorizontal) { rb.rectangle.Left = rb.olapCluster.Position - (rb.olapCluster.Size / 2); rb.rectangle.Right = rb.olapCluster.Position + (rb.olapCluster.Size / 2); if (rb.LeftBorderInfo.IsFixedPosition) { rb.LeftBorderInfo = new BorderInfo( rb.LeftBorderInfo.InnerMargin, rb.rectangle.Left, rb.LeftBorderInfo.Weight); } if (rb.RightBorderInfo.IsFixedPosition) { rb.RightBorderInfo = new BorderInfo( rb.RightBorderInfo.InnerMargin, rb.rectangle.Right, rb.RightBorderInfo.Weight); } } else { rb.rectangle.Bottom = rb.olapCluster.Position - (rb.olapCluster.Size / 2); rb.rectangle.Top = rb.olapCluster.Position + (rb.olapCluster.Size / 2); if (rb.TopBorderInfo.IsFixedPosition) { rb.TopBorderInfo = new BorderInfo( rb.TopBorderInfo.InnerMargin, rb.rectangle.Top, rb.TopBorderInfo.Weight); } if (rb.BottomBorderInfo.IsFixedPosition) { rb.BottomBorderInfo = new BorderInfo( rb.BottomBorderInfo.InnerMargin, rb.rectangle.Bottom, rb.BottomBorderInfo.Weight); } } // We don't use this anymore now that we've transferred the position and size // so clean it up as the Gen/Solver will be going out of scope. rb.olapCluster = null; // Recurse. UpdateOlapClusters(incClus.Clusters); } }
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); } }