internal EdgeConstraintGenerator(
            IEnumerable<Edge> edges,
            IdealEdgeLengthSettings settings,
            AxisSolver horizontalSolver,
            AxisSolver verticalSolver)
        {
            // filter out self edges
            this.edges = edges.Where(e => e.Source != e.Target);

            this.settings = settings;
            this.horizontalSolver = horizontalSolver;
            this.verticalSolver = verticalSolver;

            foreach (var e in this.edges) {
                TNode u = CreateTNode(e.Source), v = CreateTNode(e.Target);
                u.outNeighbours.Add(v);
                v.inNeighbours.Add(u);
            }

            foreach (var v in nodeMap.Values) {
                if(v.stackNode==null) {
                    DFS(v);
                }
            }

            while (stack.Count > 0) {
                component = new List<TNode>();
                RDFS(stack.Last.Value);
                if (component.Count > 1) {
                    var cyclicComponent = new Set<Node>();
                    foreach (var v in component) {
                        cyclicComponent.Insert(v.v);
                    }
                    cyclicComponents.Add(cyclicComponent);
                }
            }

            switch (settings.EdgeDirectionConstraints) {
                case Directions.South:
                    this.addConstraint = this.AddSConstraint;
                    break;
                case Directions.North:
                    this.addConstraint = this.AddNConstraint;
                    break;
                case Directions.West:
                    this.addConstraint = this.AddWConstraint;
                    break;
                case Directions.East:
                    this.addConstraint = this.AddEConstraint;
                    break;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Creates a VerticalSeparationConstraint for each edge in the given set to structural constraints,
        /// to require these edges to be downward pointing.  Also checks for cycles, and edges involved
        /// in a cycle receive no VerticalSeparationConstraint, but can optionally receive a circle constraint.
        /// </summary>
        /// <param name="edges"></param>
        /// <param name="settings"></param>
        /// <param name="horizontalSolver"></param>
        /// <param name="verticalSolver"></param>
        internal static void GenerateEdgeConstraints(
            IEnumerable <Edge> edges,
            IdealEdgeLengthSettings settings,
            AxisSolver horizontalSolver,
            AxisSolver verticalSolver)
        {
            if (settings.EdgeDirectionConstraints == Directions.None)
            {
                return;
            }
            EdgeConstraintGenerator g = new EdgeConstraintGenerator(edges, settings, horizontalSolver, verticalSolver);

            g.GenerateSeparationConstraints();
        }
Esempio n. 3
0
        /// <summary>
        /// Obtain a starting configuration that is feasible with respect to the structural
        /// constraints.  This is necessary to avoid e.g. cycles in the constraint graph;
        /// for example, dragging the root of a downward-pointing tree downward below other
        /// nodes of the tree can result in auto-generation of constraints generating some
        /// constraints with the root on the right-hand side, and the structural constraints
        /// have it on the left-hand side.
        ///
        /// When AvoidOverlaps==true and we reach ConstraintLevel>=2 then we also need to remove
        /// overlaps... prior to this we need to force horizontal resolving of overlaps
        /// between *all* nodes involved in vertical equality constraints (i.e. no skipping),
        /// and then vertical overlap resolution of all nodes involved in horizontal equality
        /// constraints
        /// </summary>
        static internal void Enforce(FastIncrementalLayoutSettings settings, int currentConstraintLevel, IEnumerable <FiNode> nodes, List <IConstraint> horizontalConstraints, List <IConstraint> verticalConstraints, IEnumerable <Cluster> clusterHierarchies, Func <Cluster, LayoutAlgorithmSettings> clusterSettings)
        {
            foreach (LockPosition l in settings.locks)
            {
                l.Project();
            }

            ResetPositions(nodes);
            double dblVpad  = settings.NodeSeparation + Pad;
            double dblHpad  = settings.NodeSeparation;
            double dblCVpad = settings.ClusterMargin + Pad;
            double dblCHpad = settings.ClusterMargin;

            for (int level = settings.MinConstraintLevel; level <= currentConstraintLevel; ++level)
            {
                // to obtain a feasible solution when equality constraints are present we need to be extra careful
                // but the solution below is a little bit crummy, is not currently optimized when there are no
                // equality constraints and we do not really have any scenarios involving equality constraints at
                // the moment, and also the fact that it turns off DeferToVertical causes it to resolve too
                // many overlaps horizontally, so let's skip it for now.
                //if (level >= 2 && settings.AvoidOverlaps)
                //{
                //    RemoveOverlapsOnEqualityConstraints(dblVpad, dblHpad, horizontalConstraints, verticalConstraints);
                //}
                var hsSolver = new AxisSolver(true, nodes, clusterHierarchies,
                                              level >= 2 && settings.AvoidOverlaps, level, clusterSettings);
                hsSolver.structuralConstraints    = horizontalConstraints;
                hsSolver.OverlapRemovalParameters = new Core.Geometry.OverlapRemovalParameters
                {
                    AllowDeferToVertical        = true,
                    ConsiderProportionalOverlap = settings.IdealEdgeLength.EdgeDirectionConstraints != Core.Geometry.Directions.None
                };
                hsSolver.Initialize(dblHpad, dblVpad, dblCHpad, dblCVpad, v => v.Center);
                hsSolver.SetDesiredPositions();
                hsSolver.Solve();
                ResetPositions(nodes);
                var vsSolver = new AxisSolver(false, nodes, clusterHierarchies,
                                              level >= 2 && settings.AvoidOverlaps, level, clusterSettings);
                vsSolver.structuralConstraints = verticalConstraints;
                vsSolver.Initialize(dblHpad, dblVpad, dblCHpad, dblCVpad, v => v.Center);
                vsSolver.SetDesiredPositions();
                vsSolver.Solve();
                ResetPositions(nodes);
            }
        }
 /// <summary>
 /// Obtain a starting configuration that is feasible with respect to the structural 
 /// constraints.  This is necessary to avoid e.g. cycles in the constraint graph;
 /// for example, dragging the root of a downward-pointing tree downward below other
 /// nodes of the tree can result in auto-generation of constraints generating some
 /// constraints with the root on the right-hand side, and the structural constraints
 /// have it on the left-hand side.
 /// 
 /// When AvoidOverlaps==true and we reach ConstraintLevel>=2 then we also need to remove
 /// overlaps... prior to this we need to force horizontal resolving of overlaps 
 /// between *all* nodes involved in vertical equality constraints (i.e. no skipping), 
 /// and then vertical overlap resolution of all nodes involved in horizontal equality
 /// constraints
 /// </summary>
 static internal void Enforce(FastIncrementalLayoutSettings settings, int currentConstraintLevel, IEnumerable<FiNode> nodes, List<IConstraint> horizontalConstraints, List<IConstraint> verticalConstraints, IEnumerable<Cluster> clusterHierarchies, Func<Cluster, LayoutAlgorithmSettings> clusterSettings)
 {
     foreach (LockPosition l in settings.locks)
     {
         l.Project();
     }
     ResetPositions(nodes);
     double dblVpad = settings.NodeSeparation + Pad;
     double dblHpad = settings.NodeSeparation;
     double dblCVpad = settings.ClusterMargin + Pad;
     double dblCHpad = settings.ClusterMargin;
     for (int level = settings.MinConstraintLevel; level <= currentConstraintLevel; ++level)
     {
         // to obtain a feasible solution when equality constraints are present we need to be extra careful
         // but the solution below is a little bit crummy, is not currently optimized when there are no
         // equality constraints and we do not really have any scenarios involving equality constraints at
         // the moment, and also the fact that it turns off DeferToVertical causes it to resolve too
         // many overlaps horizontally, so let's skip it for now.
         //if (level >= 2 && settings.AvoidOverlaps)
         //{
         //    RemoveOverlapsOnEqualityConstraints(dblVpad, dblHpad, horizontalConstraints, verticalConstraints);
         //}
         var hsSolver = new AxisSolver(true, nodes, clusterHierarchies,
                                      level >= 2 && settings.AvoidOverlaps, level, clusterSettings);
         hsSolver.structuralConstraints = horizontalConstraints;
         hsSolver.OverlapRemovalParameters = new Core.Geometry.OverlapRemovalParameters
         {
             AllowDeferToVertical = true,
             ConsiderProportionalOverlap = settings.IdealEdgeLength.EdgeDirectionConstraints != Core.Geometry.Directions.None
         };
         hsSolver.Initialize(dblHpad, dblVpad, dblCHpad, dblCVpad, v => v.Center);
         hsSolver.SetDesiredPositions();
         hsSolver.Solve();
         ResetPositions(nodes);
         var vsSolver = new AxisSolver(false, nodes, clusterHierarchies,
                                      level >= 2 && settings.AvoidOverlaps, level, clusterSettings);
         vsSolver.structuralConstraints = verticalConstraints;
         vsSolver.Initialize(dblHpad, dblVpad, dblCHpad, dblCVpad, v => v.Center);
         vsSolver.SetDesiredPositions();
         vsSolver.Solve();
         ResetPositions(nodes);
     }
 }
        /// <summary>
        /// Creates a VerticalSeparationConstraint for each edge in the given set to structural constraints,
        /// to require these edges to be downward pointing.  Also checks for cycles, and edges involved
        /// in a cycle receive no VerticalSeparationConstraint, but can optionally receive a circle constraint.
        /// </summary>
        /// <param name="edges"></param>
        /// <param name="settings"></param>
        /// <param name="horizontalSolver"></param>
        /// <param name="verticalSolver"></param>
        internal static void GenerateEdgeConstraints(
            IEnumerable<Edge> edges,
            IdealEdgeLengthSettings settings,
            AxisSolver horizontalSolver,
            AxisSolver verticalSolver)
        {
            if (settings.EdgeDirectionConstraints == Directions.None)
            {
                return;
            }
            EdgeConstraintGenerator g = new EdgeConstraintGenerator(edges, settings, horizontalSolver, verticalSolver);
            g.GenerateSeparationConstraints();

            // we have in the past used Circular constraints to better show cycles... it's a little experimental though
            // so it's not currently enabled
            //foreach (var c in g.CyclicComponents) {
            //    constraints.Add(new ProcrustesCircleConstraint(c));
            //}
        }
Esempio n. 6
0
        /// <summary>
        /// Creates a VerticalSeparationConstraint for each edge in the given set to structural constraints,
        /// to require these edges to be downward pointing.  Also checks for cycles, and edges involved
        /// in a cycle receive no VerticalSeparationConstraint, but can optionally receive a circle constraint.
        /// </summary>
        /// <param name="edges"></param>
        /// <param name="settings"></param>
        /// <param name="horizontalSolver"></param>
        /// <param name="verticalSolver"></param>
        internal static void GenerateEdgeConstraints(
            IEnumerable <Edge> edges,
            IdealEdgeLengthSettings settings,
            AxisSolver horizontalSolver,
            AxisSolver verticalSolver)
        {
            if (settings.EdgeDirectionConstraints == Directions.None)
            {
                return;
            }
            EdgeConstraintGenerator g = new EdgeConstraintGenerator(edges, settings, horizontalSolver, verticalSolver);

            g.GenerateSeparationConstraints();

            // we have in the past used Circular constraints to better show cycles... it's a little experimental though
            // so it's not currently enabled
            //foreach (var c in g.CyclicComponents) {
            //    constraints.Add(new ProcrustesCircleConstraint(c));
            //}
        }
        internal EdgeConstraintGenerator(
            IEnumerable <Edge> edges,
            IdealEdgeLengthSettings settings,
            AxisSolver horizontalSolver,
            AxisSolver verticalSolver)
        {
            // filter out self edges
            this.edges = edges.Where(e => e.Source != e.Target);

            this.settings         = settings;
            this.horizontalSolver = horizontalSolver;
            this.verticalSolver   = verticalSolver;

            foreach (var e in this.edges)
            {
                TNode u = CreateTNode(e.Source), v = CreateTNode(e.Target);
                u.outNeighbours.Add(v);
                v.inNeighbours.Add(u);
            }

            foreach (var v in nodeMap.Values)
            {
                if (v.stackNode == null)
                {
                    DFS(v);
                }
            }

            while (stack.Count > 0)
            {
                component = new List <TNode>();
                RDFS(stack.Last.Value);
                if (component.Count > 1)
                {
                    var cyclicComponent = new Set <Node>();
                    foreach (var v in component)
                    {
                        cyclicComponent.Insert(v.v);
                    }

                    cyclicComponents.Add(cyclicComponent);
                }
            }

            switch (settings.EdgeDirectionConstraints)
            {
            case Directions.South:
                this.addConstraint = this.AddSConstraint;
                break;

            case Directions.North:
                this.addConstraint = this.AddNConstraint;
                break;

            case Directions.West:
                this.addConstraint = this.AddWConstraint;
                break;

            case Directions.East:
                this.addConstraint = this.AddEConstraint;
                break;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Create the graph data structures.
        /// </summary>
        /// <param name="geometryGraph"></param>
        /// <param name="settings">The settings for the algorithm.</param>
        /// <param name="initialConstraintLevel">initialize at this constraint level</param>
        /// <param name="clusterSettings">settings by cluster</param>
        internal FastIncrementalLayout(GeometryGraph geometryGraph, FastIncrementalLayoutSettings settings,
                                       int initialConstraintLevel,
                                       Func <Cluster, LayoutAlgorithmSettings> clusterSettings)
        {
            graph                = geometryGraph;
            this.settings        = settings;
            this.clusterSettings = clusterSettings;
            int i = 0;
            ICollection <Node> allNodes = graph.Nodes;

            nodes = new FiNode[allNodes.Count];
            foreach (Node v in allNodes)
            {
                v.AlgorithmData = nodes[i] = new FiNode(i, v);
                i++;
            }

            clusterEdges.Clear();
            edges.Clear();

            foreach (Edge e in graph.Edges)
            {
                if (e.Source is Cluster || e.Target is Cluster)
                {
                    clusterEdges.Add(e);
                }
                else
                {
                    edges.Add(new FiEdge(e));
                }
                foreach (var l in e.Labels)
                {
                    l.InnerPoints = l.OuterPoints = null;
                }
            }
            SetLockNodeWeights();
            components = new List <FiNode[]>();
            if (!settings.InterComponentForces)
            {
                basicGraph = new BasicGraph <FiEdge>(edges, nodes.Length);
                foreach (var componentNodes in ConnectedComponentCalculator <FiEdge> .GetComponents(basicGraph))
                {
                    var vs = new FiNode[componentNodes.Count()];
                    int vi = 0;
                    foreach (int v in componentNodes)
                    {
                        vs[vi++] = nodes[v];
                    }
                    components.Add(vs);
                }
            }
            else // just one big component (regardless of actual edges)
            {
                components.Add(nodes);
            }
            horizontalSolver = new AxisSolver(true, nodes, new[] { geometryGraph.RootCluster }, settings.AvoidOverlaps,
                                              settings.MinConstraintLevel, clusterSettings)
            {
                OverlapRemovalParameters =
                    new OverlapRemovalParameters {
                    AllowDeferToVertical = true,
                    // use "ProportionalOverlap" mode only when iterative apply forces layout is being used.
                    // it is not necessary otherwise.
                    ConsiderProportionalOverlap = settings.ApplyForces
                }
            };
            verticalSolver = new AxisSolver(false, nodes, new[] { geometryGraph.RootCluster }, settings.AvoidOverlaps,
                                            settings.MinConstraintLevel, clusterSettings);

            SetupConstraints();
            geometryGraph.RootCluster.ComputeWeight();

            foreach (
                Cluster c in geometryGraph.RootCluster.AllClustersDepthFirst().Where(c => c.RectangularBoundary == null)
                )
            {
                c.RectangularBoundary = new RectangularClusterBoundary();
            }

            CurrentConstraintLevel = initialConstraintLevel;
        }
        /// <summary>
        /// Create the graph data structures.
        /// </summary>
        /// <param name="geometryGraph"></param>
        /// <param name="settings">The settings for the algorithm.</param>
        /// <param name="initialConstraintLevel">initialize at this constraint level</param>
        /// <param name="clusterSettings">settings by cluster</param>
        internal FastIncrementalLayout(GeometryGraph geometryGraph, FastIncrementalLayoutSettings settings,
                                       int initialConstraintLevel,
                                       Func<Cluster, LayoutAlgorithmSettings> clusterSettings) {
            graph = geometryGraph;
            this.settings = settings;
            this.clusterSettings = clusterSettings;
            int i = 0;
            ICollection<Node> allNodes = graph.Nodes;
            nodes = new FiNode[allNodes.Count];
            foreach (Node v in allNodes) {
                v.AlgorithmData = nodes[i] = new FiNode(i, v);
                i++;
            }

            clusterEdges.Clear();
            edges.Clear();

            foreach (Edge e in graph.Edges) {
                if (e.Source is Cluster || e.Target is Cluster)
                    clusterEdges.Add(e);
                else
                    edges.Add(new FiEdge(e));
                foreach (var l in e.Labels)
                    l.InnerPoints = l.OuterPoints = null;
            }
            SetLockNodeWeights();
            components = new List<FiNode[]>();
            if (!settings.InterComponentForces) {
                basicGraph = new BasicGraph<FiEdge>(edges, nodes.Length);
                foreach (var componentNodes in ConnectedComponentCalculator<FiEdge>.GetComponents(basicGraph)) {
                    var vs = new FiNode[componentNodes.Count()];
                    int vi = 0;
                    foreach (int v in componentNodes) {
                        vs[vi++] = nodes[v];
                    }
                    components.Add(vs);
                }
            }
            else // just one big component (regardless of actual edges)
                components.Add(nodes);
            horizontalSolver = new AxisSolver(true, nodes, new[] {geometryGraph.RootCluster}, settings.AvoidOverlaps,
                                              settings.MinConstraintLevel, clusterSettings) {
                                                  OverlapRemovalParameters =
                                                      new OverlapRemovalParameters {
                                                          AllowDeferToVertical = true,
                   // use "ProportionalOverlap" mode only when iterative apply forces layout is being used.
                   // it is not necessary otherwise.
                                                          ConsiderProportionalOverlap = settings.ApplyForces
                                                      }
                                              };
            verticalSolver = new AxisSolver(false, nodes, new[] {geometryGraph.RootCluster}, settings.AvoidOverlaps,
                                            settings.MinConstraintLevel, clusterSettings);

            SetupConstraints();
            geometryGraph.RootCluster.ComputeWeight();

            foreach (
                Cluster c in geometryGraph.RootCluster.AllClustersDepthFirst().Where(c => c.RectangularBoundary == null)
                ) {
                c.RectangularBoundary = new RectangularClusterBoundary();
            }

            CurrentConstraintLevel = initialConstraintLevel;
        }