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);
            }
        }
Ejemplo n.º 2
0
        private void VerifyAxisResults(uint rep, ConstraintGenerator generator, OverlapRemovalParameters olapParameters, ref bool succeeded)
        {
            var axisName = generator.IsHorizontal ? "X" : "Y";
            var solver   = generator.IsHorizontal ? this.SolverX : this.SolverY;
            var solution = generator.IsHorizontal ? this.SolutionX : this.SolutionY;

            if (TestGlobals.VerboseLevel >= 3)
            {
                this.WriteLine("  {0} Nodes after solving Constraints:", axisName);
                foreach (Variable var in solver.Variables)
                {
                    var node = (OverlapRemovalNode)var.UserData;
                    Console.Write("    {0}", node);

                    const string Format = " - L/R T/B {0:F5}/{1:F5} {2:F5}/{3:F5}";
                    if (generator.IsHorizontal)
                    {
                        // X is Perpendicular here
                        this.WriteLine(Format, node.OpenP, node.CloseP, node.Open, node.Close);
                    }
                    else
                    {
                        // Y is Perpendicular here
                        this.WriteLine(Format, node.Open, node.Close, node.OpenP, node.CloseP);
                    }
                }
            }

            // We should never see unsatisfiable constraints since we created them ourselves.
            if (0 != solution.NumberOfUnsatisfiableConstraints)
            {
                succeeded = false;
                this.WriteLine(" *** Error! {0} unsatisfiable {1} constraints found ***",
                               solution.NumberOfUnsatisfiableConstraints, axisName);
                if ((TestGlobals.VerboseLevel >= 2) && (0 == rep))
                {
                    foreach (Constraint cst in solver.Constraints.Where(cst => cst.IsUnsatisfiable))
                    {
                        this.WriteLine("      {0}", cst);
                    }
                } // endif VerboseLevel
            }     // endif unsatisfiable constraints

            bool violationSeen = false;

            foreach (Constraint cst in solver.Constraints)
            {
                if (!this.VerifyConstraint(olapParameters.SolverParameters, cst, generator.IsHorizontal, ref violationSeen))
                {
                    succeeded = false;
                }
            }

            if (solution.ExecutionLimitExceeded)
            {
                this.WriteLine(GetCutoffString(solution));
            }
        }
Ejemplo n.º 3
0
 internal OverlapRemovalCluster CreateCluster(ConstraintGenerator conGen)
 {
     if (null == this.Cluster)
     {
         // Ensure the parent Cluster is created as we must pass it as a parameter.
         // Don't call this.ParentCluster here because it's got an Assert that our
         // cluster has been created - and it hasn't, yet; that's what we're doing here.
         // clusParent remains null if this.IsNewHierarchy.
         OverlapRemovalCluster clusParent = null;
         if (!this.IsNewHierarchy)
         {
             clusParent = (null == this.ParentClusterDef)
                              ? conGen.DefaultClusterHierarchy
                              : this.ParentClusterDef.CreateCluster(conGen);
         }
         if (conGen.IsHorizontal)
         {
             this.Cluster = conGen.AddCluster(
                 clusParent,
                 this.ClusterId,
                 this.MinimumSizeX,
                 this.MinimumSizeY,
                 this.LeftBorderInfo,
                 this.RightBorderInfo,
                 this.TopBorderInfo,
                 this.BottomBorderInfo);
         }
         else
         {
             // Use horizontal PostX BorderInfos due to MinimumSize; see PostX().
             this.Cluster = conGen.AddCluster(
                 clusParent,
                 this.ClusterId,
                 this.MinimumSizeY,
                 this.MinimumSizeX,
                 this.TopBorderInfo,
                 this.BottomBorderInfo,
                 this.PostXLeftBorderInfo,
                 this.PostXRightBorderInfo);
         }
     }
     return(this.Cluster);
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Create variables, generate non-overlap constraints.
        /// </summary>
        /// <param name="hPad">horizontal node padding</param>
        /// <param name="vPad">vertical node padding</param>
        /// <param name="cHPad">horizontal cluster padding</param>
        /// <param name="cVPad">vertical cluster padding</param>
        /// <param name="nodeCenter"></param>
        internal void Initialize(double hPad, double vPad, double cHPad, double cVPad, InitialCenterDelegateType nodeCenter)
        {
            // For the Vertical ConstraintGenerator, Padding is vPad and PadddingP(erpendicular) is hPad.
            cg = new ConstraintGenerator(IsHorizontal
                                         , IsHorizontal ? hPad : vPad
                                         , IsHorizontal ? vPad : hPad
                                         , IsHorizontal ? cHPad : cVPad
                                         , IsHorizontal ? cVPad : cHPad);
            solver = new Solver();

            foreach (var filNode in nodes)
            {
                filNode.SetOlapNode(IsHorizontal, null);
            }

            // Calculate horizontal non-Overlap constraints.
            if (avoidOverlaps && clusterHierarchies != null)
            {
                foreach (var c in clusterHierarchies)
                {
                    AddOlapClusters(cg, null /* OlapParentCluster */, c, nodeCenter);
                }
            }

            foreach (var filNode in nodes)
            {
                if (filNode.getOlapNode(IsHorizontal) == null)
                {
                    AddOlapNode(cg, cg.DefaultClusterHierarchy /* olapParentCluster */, filNode, nodeCenter);
                }

                filNode.getOlapNode(IsHorizontal).CreateVariable(solver);
            }
            if (avoidOverlaps && this.ConstraintLevel >= 2)
            {
                cg.Generate(solver, OverlapRemovalParameters);
            }

            AddStructuralConstraints();
        }
        private void DebugVerifyClusters(ConstraintGenerator generator, Cluster incCluster, Cluster root)
        {
            double dblEpsilon = 0.0001;

            // First verify that all nodes are within the cluster.
            Rectangle clusRect = incCluster.RectangularBoundary.rectangle;

            foreach (var v in incCluster.Nodes)
            {
                FiNode    iiFilNode  = (FiNode)v.AlgorithmData;
                Rectangle iiNodeRect = iiFilNode.mNode.BoundaryCurve.BoundingBox;

                if (IsHorizontal)
                {
                    // Don't check containment for the root ClusterHierarchy as there is no border for it.
                    if (incCluster != root)
                    {
                        // This is horizontal so we've not yet calculated the Y-axis stuff.  The only thing we
                        // can do is verify we're within cluster X bounds.  If *Space is negative, there's overlap.
                        // Generator primary axis is horizontal so use its Padding.
                        double dblLboundSpace = iiNodeRect.Left - clusRect.Left - generator.Padding;
                        double dblRboundSpace = clusRect.Right - iiNodeRect.Right - generator.Padding;
                        Debug.Assert((dblLboundSpace >= -dblEpsilon) && (dblRboundSpace >= -dblEpsilon)
                                     , "Node is not within parent Cluster");
                    }
                }
                else
                {
                    // Don't check containment for the root ClusterHierarchy as there is no border for it.
                    if (incCluster != root)
                    {
                        // This is vertical so we've calculated the Y-axis stuff and horizontal is Perpendicular.
                        DebugVerifyRectContains(clusRect, iiNodeRect
                                                , generator.PaddingP, generator.Padding, dblEpsilon);
                    }
                    // Make sure the node doesn't intersect any following nodes, or any clusters.
                    foreach (var u in incCluster.Nodes)
                    {
                        if (u == v)
                        {
                            continue;
                        }
                        FiNode    jjFilNode  = (FiNode)u.AlgorithmData;
                        Rectangle jjNodeRect = jjFilNode.mNode.BoundaryCurve.BoundingBox;

                        // We've already added the padding for the node so don't add it for the jjNode/Cluster.
                        DebugVerifyRectsDisjoint(iiNodeRect, jjNodeRect
                                                 , generator.PaddingP, generator.Padding, dblEpsilon);
                    }
                    foreach (Cluster incClusComp in incCluster.Clusters)
                    {
                        DebugVerifyRectsDisjoint(iiNodeRect, incClusComp.RectangularBoundary.rectangle
                                                 , generator.PaddingP, generator.Padding, dblEpsilon);
                    }
                } // endif isHorizontal
            }     // endfor iiNode

            // Now verify the clusters are contained and don't overlap.
            foreach (var iiIncClus in incCluster.Clusters)
            {
                Rectangle iiClusRect = iiIncClus.RectangularBoundary.rectangle;

                if (IsHorizontal)
                {
                    // Don't check containment for the root ClusterHierarchy as there is no border for it.
                    if (incCluster != root)
                    {
                        // This is horizontal so we've not yet calculated the Y-axis stuff.  The only thing we
                        // can do is verify we're within cluster X bounds.  If *Space is negative, there's overlap.
                        // Generator primary axis is horizontal so use its Padding.
                        double dblLboundSpace = iiClusRect.Left - clusRect.Left - generator.Padding;
                        double dblRboundSpace = clusRect.Right - iiClusRect.Right - generator.Padding;
                        Debug.Assert((dblLboundSpace >= -dblEpsilon) && (dblRboundSpace >= -dblEpsilon)
                                     , "Cluster is not within parent Cluster");
                    }
                }
                else
                {
                    // Don't check containment for the root ClusterHierarchy as there is no border for it.
                    if (incCluster != root)
                    {
                        // This is vertical so we've calculated the Y-axis stuff and horizontal is Perpendicular.
                        DebugVerifyRectContains(clusRect, iiClusRect
                                                , generator.PaddingP, generator.Padding, dblEpsilon);
                    }
                    // Make sure the cluster doesn't intersect any following clusters.
                    foreach (var jjIncClus in incCluster.Clusters)
                    {
                        if (jjIncClus == iiIncClus)
                        {
                            continue;
                        }
                        Rectangle jjClusRect = jjIncClus.RectangularBoundary.rectangle;
                        DebugVerifyRectsDisjoint(iiClusRect, jjClusRect
                                                 , generator.PaddingP, generator.Padding, dblEpsilon);
                    }
                } // endif isHorizontal

                // Now recurse.
                DebugVerifyClusters(generator, iiIncClus, root);
            } // endfor iiCluster
        }
        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);
            }
        }
Ejemplo n.º 7
0
        private void AddNodesAndSolve(ConstraintGenerator generator,
                                      IEnumerable <VariableDef> iterVariableDefs,
                                      OverlapRemovalParameters olapParameters,
                                      IEnumerable <ConstraintDef> iterConstraintDefs,
                                      ref bool succeeded)
        {
            var axisName = generator.IsHorizontal ? "X" : "Y";
            var solver   = generator.IsHorizontal ? this.SolverX : this.SolverY;

            foreach (VariableDef varDef in iterVariableDefs)
            {
                // Create the variable in its initial cluster.
                OverlapRemovalCluster olapClusParent = generator.DefaultClusterHierarchy;
                if (varDef.ParentClusters.Count > 0)
                {
                    olapClusParent = varDef.ParentClusters[0].Cluster;
                }
                OverlapRemovalNode newNode;
                if (generator.IsHorizontal)
                {
                    newNode = generator.AddNode(olapClusParent, varDef.IdString,
                                                varDef.DesiredPosX, varDef.DesiredPosY,
                                                varDef.SizeX, varDef.SizeY, varDef.WeightX);
                    varDef.VariableX = new OlapTestNode(newNode);
                }
                else
                {
                    newNode = generator.AddNode(olapClusParent, varDef.IdString,
                                                varDef.DesiredPosY, varDef.VariableX.ActualPos,
                                                varDef.SizeY, varDef.SizeX, varDef.WeightY);
                    varDef.VariableY = new OlapTestNode(newNode);
                }

                // Add it to its other clusters.
                for (int ii = 1; ii < varDef.ParentClusters.Count; ++ii)
                {
                    olapClusParent = varDef.ParentClusters[ii].Cluster;
                    generator.AddNodeToCluster(olapClusParent, newNode);
                }
            }
            generator.Generate(solver, olapParameters);
            if (TestGlobals.VerboseLevel >= 3)
            {
                this.WriteLine("  {0} Constraints:", axisName);
                foreach (Constraint cst in solver.Constraints.OrderBy(cst => cst))
                {
                    this.WriteLine("    {0} {1} g {2:F5}", cst.Left.UserData, cst.Right.UserData, cst.Gap);
                }
            }

            if (null != iterConstraintDefs)
            {
                // TODO: Compare expected to actual constraints generated in solver
            }

            var solution = generator.Solve(solver, olapParameters, false /* doGenerate */);

            if (!this.VerifySolutionMembers(solution, /*iterNeighborDefs:*/ null))
            {
                succeeded = false;
            }
            if (generator.IsHorizontal)
            {
                this.SolutionX = solution;
            }
            else
            {
                this.SolutionY = solution;
            }
        }
Ejemplo n.º 8
0
        private void CreateSolversAndGetSolutions(Stopwatch sw, IEnumerable <ClusterDef> iterClusterDefs, IEnumerable <VariableDef> iterVariableDefs, IEnumerable <ConstraintDef> iterConstraintDefsX, IEnumerable <ConstraintDef> iterConstraintDefsY, ref bool succeeded)
        {
            var olapParameters = new OverlapRemovalParameters(this.SolverParameters)
            {
                AllowDeferToVertical = this.AllowDeferToVertical
            };

            for (uint rep = 0; rep < TestGlobals.TestReps; ++rep)
            {
                sw.Start();

                // Load the Horizontal ProjectionSolver and ConstraintGenerator with variables.
                // We must Solve the X coordinates before generating the Y ones, so that the
                // Y generation, whose scan line uses X coordinates, uses the updated values.
                var generatorX = new ConstraintGenerator(true /* fIsHorizontal */, this.MinPaddingX, this.MinPaddingY);
                this.SolverX = new Solver();

                // First create the X Clusters.
                if (null != iterClusterDefs)
                {
                    foreach (ClusterDef clusDef in iterClusterDefs)
                    {
                        clusDef.ComputeInitialBorders();  // called for H only; does both H and V
                        clusDef.CreateCluster(generatorX);
                    }
                }
                this.AddNodesAndSolve(generatorX, iterVariableDefs, olapParameters, iterConstraintDefsX, ref succeeded);

                sw.Stop();

                this.VerifyAxisResults(rep, generatorX, olapParameters, ref succeeded);

                sw.Start();

                // Load the Vertical ProjectionSolver and ConstraintGenerator with variables.
                // This uses the X coordinate determined by the above solution for the perpendicular.
                var generatorY = new ConstraintGenerator(false /* fIsHorizontal */, this.MinPaddingY, this.MinPaddingX);
                this.SolverY = new Solver();

                // First create the Y Clusters.
                if (null != iterClusterDefs)
                {
                    // Clear out the ConGenX Clusters first, then create them in ConGenY.
                    foreach (ClusterDef clusDef in iterClusterDefs)
                    {
                        if (!clusDef.PostX())
                        {
                            succeeded = false;
                        }
                    }
                    foreach (ClusterDef clusDef in iterClusterDefs)
                    {
                        clusDef.CreateCluster(generatorY);
                    }
                }

                this.AddNodesAndSolve(generatorY, iterVariableDefs, olapParameters, iterConstraintDefsY, ref succeeded);

                sw.Stop();

                if (null != iterClusterDefs)
                {
                    foreach (ClusterDef clusDef in iterClusterDefs)
                    {
                        if (!clusDef.PostY())
                        {
                            succeeded = false;
                        }
                    }
                }

                this.VerifyAxisResults(rep, generatorY, olapParameters, ref succeeded);
            }
        }