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;
            }
        }
        /// <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));
            //}
        }
Example #3
0
        /// <summary>
        /// Compute ideal edge lengths for the given graph component based on the given settings
        /// </summary>
        /// <param name="settings">settings for calculating ideal edge length</param>
        /// <param name="component">a graph component</param>
        public static void ComputeDesiredEdgeLengths(IdealEdgeLengthSettings settings, GeometryGraph component)
        {
            if (component == null)
            {
                return;
            }
            foreach (var e in component.Edges)
            {
                e.SourcePort = null;
                e.TargetPort = null;

                // use larger of DefaultLength and
                // minimum of the diagonal of a square of area equal to the bounding box of the source and that of the target
                e.Length = Math.Max(settings.DefaultLength,
                                    Math.Sqrt(2d * Math.Min(e.Source.BoundingBox.Width * e.Source.BoundingBox.Height, e.Target.BoundingBox.Width * e.Target.BoundingBox.Height)));
            }
            if (settings.ProportionalToSymmetricDifference)
            {
                SetEdgeLengthsProportionalToSymmetricDifference(component, settings.ProportionalEdgeLengthOffset, settings.ProportionalEdgeLengthAdjustment);
            }
        }
        /// <summary>
        /// Compute ideal edge lengths for the given graph component based on the given settings
        /// </summary>
        /// <param name="settings">settings for calculating ideal edge length</param>
        /// <param name="component">a graph component</param>
        public static void ComputeDesiredEdgeLengths(IdealEdgeLengthSettings settings, GeometryGraph component)
        {
            if (component == null)
            {
                return;
            }
            foreach (var e in component.Edges)
            {
                e.SourcePort = null;
                e.TargetPort = null;

                // use larger of DefaultLength and
                // minimum of the diagonal of a square of area equal to the bounding box of the source and that of the target
                e.Length = Math.Max(settings.DefaultLength,
                    Math.Sqrt(2d * Math.Min(e.Source.BoundingBox.Width * e.Source.BoundingBox.Height, e.Target.BoundingBox.Width * e.Target.BoundingBox.Height)));
            }
            if (settings.ProportionalToSymmetricDifference)
            {
                SetEdgeLengthsProportionalToSymmetricDifference(component, settings.ProportionalEdgeLengthOffset, settings.ProportionalEdgeLengthAdjustment);
            }
        }