public void MinimumSizeIsRespected()
        {
            // Setup
            string filePath = Path.Combine(this.TestContext.TestDir, "Out\\Dots", "chat.dot");
            GeometryGraph graph = this.LoadGraph(filePath);

            const double DesiredHeight = 100000;
            const double DesiredWidth = 100000;

            SugiyamaLayoutSettings settings = new SugiyamaLayoutSettings();
            settings.MinimalHeight = DesiredHeight;
            settings.MinimalWidth = DesiredWidth;
            
            // Execute
            LayeredLayout layeredLayout = new LayeredLayout(graph, settings);
            layeredLayout.Run();

            // Verify the graph is the correct size
            Assert.IsTrue(DesiredHeight < graph.Height, "Graph height should be the minimal height.");
            Assert.IsTrue(DesiredWidth < graph.Width, "Graph width should be the minimal width.");

            // Verify the nodes were spread apart to fill the space
            Rectangle nodeBounds = new Rectangle(graph.Nodes.Select(n => n.BoundingBox));
            Assert.IsTrue(DesiredWidth < nodeBounds.Height, "The graph nodes weren't scaled vertically to fill the space.");
            Assert.IsTrue(DesiredWidth < nodeBounds.Width, "The graph nodes weren't scaled horizontally to fill the space.");
        }
        internal ConstrainedOrdering(
            GeometryGraph geomGraph,
            BasicGraph<Node, IntEdge> basicIntGraph,
            int[] layering,
            Dictionary<Node, int> nodeIdToIndex,
            Database database,
            SugiyamaLayoutSettings settings) {

            this.settings = settings;
            horizontalConstraints = settings.HorizontalConstraints;

            horizontalConstraints.PrepareForOrdering(nodeIdToIndex, layering);

            geometryGraph = geomGraph;
            this.database = database;
            intGraph = basicIntGraph;
            initialLayering = layering;
            //this has to be changed only to insert layers that are needed
            if (NeedToInsertLayers(layering)) {
                for (int i = 0; i < layering.Length; i++)
                    layering[i] *= 2;
                LayersAreDoubled = true;
                numberOfLayers = -1;
            }

            PrepareProperLayeredGraphAndFillLayerInfos();

            adjSwapper = new AdjacentSwapsWithConstraints(
                LayerArrays,
                HasCrossWeights(),
                ProperLayeredGraph,
                layerInfos);
        }
 internal PhyloTreeLayoutCalclulation(PhyloTree phyloTreeP, SugiyamaLayoutSettings settings, BasicGraph<Node, IntEdge> intGraphP, Database dataBase) {
     this.dataBase = dataBase;
     this.tree = phyloTreeP;
     this.LayoutSettings = settings;
     this.intGraph = intGraphP;
     originalNodeToGridLayerIndices = new int[intGraph.Nodes.Count];
 }
        public void NodeShapeChange()
        {
            // Setup
            string filePath = Path.Combine(this.TestContext.TestDir, "Out\\Dots", "chat.dot");
            GeometryGraph graph = this.LoadGraph(filePath);
            var settings = new SugiyamaLayoutSettings();

            // Initial layout
            LayeredLayout layeredLayout = new LayeredLayout(graph, settings);
            layeredLayout.Run();
            SortedList<double, SortedList<double, Node>> originalLayers = SugiyamaValidation.GetLayers(graph, true);

            // Incremental layout
            List<Node> nodes = graph.Nodes.ToList();
            for (int i = 0; i < nodes.Count; i++)
            {
                // Resize a node
                Node node = nodes[i];
                node.BoundaryCurve = node.BoundaryCurve.ScaleFromOrigin(2.0, 2.0);

                // Run incremental layout
                LayeredLayout.IncrementalLayout(graph, node);
                
                // Verify - the layering and ordering of nodes should not have changed.
                SortedList<double, SortedList<double, Node>> newLayers = SugiyamaValidation.GetLayers(graph, true);
                VerifyLayersAreEqual(originalLayers, newLayers);
            }
        }
Пример #5
0
 internal TwoLayerFlatEdgeRouter(SugiyamaLayoutSettings settings, Routing routing, int[] bottomLayer, int[] topLayer)
 {
     this.settings    = settings;
     this.topLayer    = topLayer;
     this.bottomLayer = bottomLayer;
     this.routing     = routing;
     InitLabelsInfo();
 }
 internal TwoLayerFlatEdgeRouter(SugiyamaLayoutSettings settings, Routing routing, int[] bottomLayer, int[] topLayer)
 {
     this.settings = settings;
     this.topLayer = topLayer;
     this.bottomLayer = bottomLayer;
     this.routing = routing;
     InitLabelsInfo();
 }
 /// <summary>
 /// Creates a smoothed polyline
 /// </summary>
 internal SmoothedPolylineCalculator(IntEdge edgePathPar, Anchor[] anchorsP, GeometryGraph origGraph, SugiyamaLayoutSettings settings, LayerArrays la, ProperLayeredGraph layerGraph, Database databaseP) {
     this.database = databaseP;
     edgePath = edgePathPar;
     anchors = anchorsP;
     this.layerArrays = la;
     this.originalGraph = origGraph;
     this.settings = settings;
     this.layeredGraph = layerGraph;
     rightHierarchy = BuildRightHierarchy();
     leftHierarchy = BuildLeftHierarchy();
 }
 internal Routing(SugiyamaLayoutSettings settings, GeometryGraph originalGraph, Database dbP,
                  LayerArrays yLayerArrays,
                  ProperLayeredGraph properLayeredGraph,
                  BasicGraph<Node, IntEdge> intGraph
     ) {
     this.settings = settings;
     OriginalGraph = originalGraph;
     Database = dbP;
     ProperLayeredGraph = properLayeredGraph;
     LayerArrays = yLayerArrays;
     IntGraph = intGraph;
 }
 /// <summary>
 /// Creates a smoothed polyline
 /// </summary>
 internal SmoothedPolylineCalculator(IntEdge edgePathPar, Anchor[] anchorsP, GeometryGraph origGraph, SugiyamaLayoutSettings settings, LayerArrays la, ProperLayeredGraph layerGraph, Database databaseP)
 {
     this.database      = databaseP;
     edgePath           = edgePathPar;
     anchors            = anchorsP;
     this.layerArrays   = la;
     this.originalGraph = origGraph;
     this.settings      = settings;
     this.layeredGraph  = layerGraph;
     rightHierarchy     = BuildRightHierarchy();
     leftHierarchy      = BuildLeftHierarchy();
 }
Пример #10
0
 internal Routing(SugiyamaLayoutSettings settings, GeometryGraph originalGraph, Database dbP,
                  LayerArrays yLayerArrays,
                  ProperLayeredGraph properLayeredGraph,
                  BasicGraph<Node, PolyIntEdge> intGraph
     ) {
     this.settings = settings;
     OriginalGraph = originalGraph;
     Database = dbP;
     ProperLayeredGraph = properLayeredGraph;
     LayerArrays = yLayerArrays;
     IntGraph = intGraph;
 }
        internal static GeometryGraph CreateAndLayoutGraph()
        {
            PhyloTree phyloTree = new PhyloTree();
            double width = 40;
            double height = 10;

            foreach (string id in "A B C D E F G".Split(' '))
                DrawingUtilsForSamples.AddNode(id, phyloTree, width, height);

            PhyloEdge e;
            double age_of_BC = 2;
            double age_of_D = 3.5;
            double age_of_F = 1.5;
            double age_of_G = 3.5;
            double age_of_E = 2;

            phyloTree.Edges.Add(e = new PhyloEdge(phyloTree.FindNodeByUserData("A"), phyloTree.FindNodeByUserData("B")));
            e.Length = age_of_BC;
            phyloTree.Edges.Add(e = new PhyloEdge(phyloTree.FindNodeByUserData("A"), phyloTree.FindNodeByUserData("C")));
            e.Length = age_of_BC;
            phyloTree.Edges.Add(e = new PhyloEdge(phyloTree.FindNodeByUserData("A"), phyloTree.FindNodeByUserData("D")));
            e.Length = age_of_D;
            phyloTree.Edges.Add(e = new PhyloEdge(phyloTree.FindNodeByUserData("C"), phyloTree.FindNodeByUserData("E")));
            e.Length = age_of_E;
            phyloTree.Edges.Add(e = new PhyloEdge(phyloTree.FindNodeByUserData("C"), phyloTree.FindNodeByUserData("F")));
            e.Length = age_of_F;
            phyloTree.Edges.Add(e = new PhyloEdge(phyloTree.FindNodeByUserData("C"), phyloTree.FindNodeByUserData("G")));
            e.Length = age_of_G;
            var sugiyamaLayoutSettings = new SugiyamaLayoutSettings();
            foreach (var edge in phyloTree.Edges) {
                edge.EdgeGeometry.TargetArrowhead = new Arrowhead();
            }
            Microsoft.Msagl.Miscellaneous.LayoutHelpers.CalculateLayout(phyloTree, new SugiyamaLayoutSettings(), null);

            // add a couple of  non-tree edges
            Edge e0 = new Edge(phyloTree.FindNodeByUserData("F"), phyloTree.FindNodeByUserData("D")) {
                EdgeGeometry = {SourceArrowhead = new Arrowhead()}
            };
            phyloTree.Edges.Add(e0);
            Edge e1 = new Edge(phyloTree.FindNodeByUserData("G"), phyloTree.FindNodeByUserData("D")) {
                EdgeGeometry = {SourceArrowhead = new Arrowhead()}
            };
            phyloTree.Edges.Add(e1);

            // route the non-tree edges, every other edge is routed already
            double loosePadding = sugiyamaLayoutSettings.NodeSeparation/10;
            double tightPadding = sugiyamaLayoutSettings.NodeSeparation/10;
            double coneAngle = Math.PI/6;
            var router = new SplineRouter(phyloTree, new[] {e0, e1}, tightPadding, loosePadding, coneAngle, null);
            router.Run();
            return phyloTree;
        }
 Ordering(ProperLayeredGraph graphPar, bool tryReverse, LayerArrays layerArraysParam, int startOfVirtualNodes, bool balanceVirtualAndOrigNodes, bool hasCrossWeights, SugiyamaLayoutSettings settings) {
     this.tryReverse = tryReverse;
     startOfVirtNodes = startOfVirtualNodes;
     layerArrays = layerArraysParam;
     layering = layerArraysParam.Y;
     nOfLayers = layerArraysParam.Layers.Length;
     layers = layerArraysParam.Layers;
     balanceVirtAndOrigNodes = balanceVirtualAndOrigNodes;
     properLayeredGraph = graphPar;
     this.hasCrossWeights = hasCrossWeights;
     this.settings = settings;
     random = new Random(SeedOfRandom);
 }
Пример #13
0
 Ordering(ProperLayeredGraph graphPar, bool tryReverse, LayerArrays layerArraysParam, int startOfVirtualNodes, bool hasCrossWeights, SugiyamaLayoutSettings settings)
 {
     this.tryReverse      = tryReverse;
     startOfVirtNodes     = startOfVirtualNodes;
     layerArrays          = layerArraysParam;
     layering             = layerArraysParam.Y;
     nOfLayers            = layerArraysParam.Layers.Length;
     layers               = layerArraysParam.Layers;
     properLayeredGraph   = graphPar;
     this.hasCrossWeights = hasCrossWeights;
     this.settings        = settings;
     random               = new Random(SeedOfRandom);
 }
 /// <summary>
 /// it is a special recovery constructor to recreate the engine from the recovery engine
 /// </summary>
 internal LayeredLayoutEngine(LayerArrays engineLayerArrays, GeometryGraph originalGraph, ProperLayeredGraph properLayeredGraph, SugiyamaLayoutSettings sugiyamaSettings, Database database, BasicGraph<Node, IntEdge> intGraph, Dictionary<Node, int> nodeIdToIndex, BasicGraph<Node, IntEdge> gluedDagSkeletonForLayering, bool layersAreDoubled, ConstrainedOrdering constrainedOrdering, bool brandes, XLayoutGraph xLayoutGraph) {
     this.engineLayerArrays = engineLayerArrays;
     this.originalGraph = originalGraph;
     this.properLayeredGraph = properLayeredGraph;
     this.sugiyamaSettings = sugiyamaSettings;
     this.database = database;
     IntGraph = intGraph;
     this.nodeIdToIndex = nodeIdToIndex;
     GluedDagSkeletonForLayering = gluedDagSkeletonForLayering;
     LayersAreDoubled = layersAreDoubled;
     this.constrainedOrdering = constrainedOrdering;
     Brandes = brandes;
     anchors = database.anchors;
     this.xLayoutGraph = xLayoutGraph;
 }
        public void TallRatioSimpleStretch()
        {
            // Setup
            string filePath = Path.Combine(this.TestContext.TestDir, "Out\\Dots", "chat.dot");
            GeometryGraph graph = this.LoadGraph(filePath);
            SugiyamaLayoutSettings settings = new SugiyamaLayoutSettings();
            settings.AspectRatio = 0.25;
        
            // Execute
            LayeredLayout layeredLayout = new LayeredLayout(graph, settings);
            layeredLayout.Run();

            // Verify
            VerifyAspectRatio(graph, settings.AspectRatio);
        }
        public void SerializeDeserialize()
        {
            // Create settings that are different from the defaults
            SugiyamaLayoutSettings oldSettings = new SugiyamaLayoutSettings();
            oldSettings.AspectRatio++;
            oldSettings.LayerSeparation++;
            oldSettings.RepetitionCoefficientForOrdering++;
            oldSettings.RandomSeedForOrdering++;
            oldSettings.NoGainAdjacentSwapStepsBound++;
            oldSettings.MaxNumberOfPassesInOrdering++;
            oldSettings.GroupSplit++;
            oldSettings.LabelCornersPreserveCoefficient++;
            oldSettings.BrandesThreshold++;
            oldSettings.MinimalWidth++;
            oldSettings.MinimalHeight++;
            oldSettings.NodeSeparation++;
            oldSettings.MinNodeHeight++;
            oldSettings.MinNodeWidth++;
            oldSettings.LayeringOnly = !oldSettings.LayeringOnly;
            
            // Serialize
            GeometryGraph oldGraph = new GeometryGraph();
            oldGraph.Nodes.Add(new Node());
            GeometryGraphWriter.Write(oldGraph, oldSettings, "settings.msagl.geom");

            // Deserialize
            LayoutAlgorithmSettings baseSettings;
            GeometryGraphReader.CreateFromFile("settings.msagl.geom", out baseSettings);
            SugiyamaLayoutSettings newSettings = (SugiyamaLayoutSettings)baseSettings;

            // Verify
            Assert.AreEqual(oldSettings.AspectRatio, newSettings.AspectRatio, "AspectRatio was not serialized correctly.");
            Assert.AreEqual(oldSettings.LayerSeparation, newSettings.LayerSeparation, "LayerSeparation was not serialized correctly.");
            Assert.AreEqual(oldSettings.LayeringOnly, newSettings.LayeringOnly, "LayeringOnly was not serialized correctly.");
            Assert.AreEqual(oldSettings.RepetitionCoefficientForOrdering, newSettings.RepetitionCoefficientForOrdering, "RepetitionCoefficientForOrdering was not serialized correctly.");
            Assert.AreEqual(oldSettings.RandomSeedForOrdering, newSettings.RandomSeedForOrdering, "RandomSeedForOrdering was not serialized correctly.");
            Assert.AreEqual(oldSettings.NoGainAdjacentSwapStepsBound, newSettings.NoGainAdjacentSwapStepsBound, "NoGainAdjacentSwapStepsBound was not serialized correctly.");
            Assert.AreEqual(oldSettings.MaxNumberOfPassesInOrdering, newSettings.MaxNumberOfPassesInOrdering, "MaxNumberOfPassesInOrdering was not serialized correctly.");
            Assert.AreEqual(oldSettings.GroupSplit, newSettings.GroupSplit, "GroupSplit was not serialized correctly.");
            Assert.AreEqual(oldSettings.LabelCornersPreserveCoefficient, newSettings.LabelCornersPreserveCoefficient, "LabelCornersPreserveCoefficient was not serialized correctly.");
            Assert.AreEqual(oldSettings.BrandesThreshold, newSettings.BrandesThreshold, "BrandesThreshold was not serialized correctly.");
            Assert.AreEqual(oldSettings.MinimalWidth, newSettings.MinimalWidth, "MinimalWidth was not serialized correctly.");
            Assert.AreEqual(oldSettings.MinimalHeight, newSettings.MinimalHeight, "MinimalHeight was not serialized correctly.");
            Assert.AreEqual(oldSettings.NodeSeparation, newSettings.NodeSeparation, "NodeSeparation was not serialized correctly.");
            Assert.AreEqual(oldSettings.MinNodeHeight, newSettings.MinNodeHeight, "MinNodeHeight was not serialized correctly.");
            Assert.AreEqual(oldSettings.MinNodeWidth, newSettings.MinNodeWidth, "MinNodeWidth was not serialized correctly.");
        }
        /// <summary>
        /// Validate all layers have valid separation
        /// </summary>
        internal static void ValidateLayerSeparation(GeometryGraph graph, SugiyamaLayoutSettings settings)
        {
            bool isVertical = IsVerticallyLayered(settings.Transformation);
            SortedList<double, SortedList<double, Node>> layers = GetLayers(graph, isVertical);
            
#if TEST_MSAGL
            Console.WriteLine("Setting for layer separation: " + settings.LayerSeparation);
            for (int j = 0; j < layers.Count; j++)
            {                
                SortedList<double, Node> layer = layers.Values[j];
                Console.WriteLine("Layer No. " + (j + 1));
                for (int k = 0; k < layer.Count; k++)
                {
                    Node node = layer.Values[k];
                    Console.WriteLine("\t On this layer, No. " + (k + 1) + " Node's boundary is " + node.BoundingBox);
                }
            }
#endif
            //Make sure no src/target of one edge stay in same layer
            foreach (IList<Node> layer in layers.Values.Select(l => l.Values))
            {
                ValidateSourceTargetNotOnSameLayer(layer);
            }            

            Tuple<Node, Node>[] layerNodes = new Tuple<Node, Node>[layers.Keys.Count];

            for (int i = 0; i < layers.Keys.Count; i++)
            {
                layerNodes[i] = GetBiggestNodesInLayer(layers.Values[i].Values, isVertical);
            }

            for (int i = 1; i < layers.Keys.Count - 1; i++)
            {
                if (isVertical)
                {
                    Assert.IsTrue(Math.Abs(layerNodes[i - 1].Item2.BoundingBox.Bottom - layerNodes[i].Item1.BoundingBox.Top) + Tolerance >= settings.LayerSeparation, string.Format("layer {0} not having right separation with layer {1}", i - 1, i));
                    Assert.IsTrue(Math.Abs(layerNodes[i + 1].Item2.BoundingBox.Top - layerNodes[i].Item1.BoundingBox.Bottom) + Tolerance >= settings.LayerSeparation, string.Format("layer {0} not having right separation with layer {1}", i + 1, i));
                }                                                                                                                           
                else                                                                                                                        
                {                                                                                                                           
                    Assert.IsTrue(Math.Abs(layerNodes[i - 1].Item2.BoundingBox.Right - layerNodes[i].Item1.BoundingBox.Left) + Tolerance >= settings.LayerSeparation, string.Format("layer {0} not having right separation with layer {1}", i - 1, i));
                    Assert.IsTrue(Math.Abs(layerNodes[i + 1].Item2.BoundingBox.Left - layerNodes[i].Item1.BoundingBox.Right) + Tolerance >= settings.LayerSeparation, string.Format("layer {0} not having right separation with layer {1}", i + 1, i));
                }
            }
        }
        internal static GeometryGraph CreateAndLayoutGraph()
        {
            GeometryGraph graph = new GeometryGraph();

            double width = 40;
            double height = 10;

            foreach (string id in "0 1 2 3 4 5 6 A B C D E F G a b c d e".Split(' '))
            {
                DrawingUtilsForSamples.AddNode(id, graph, width, height);
            }

            graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("B")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("C")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("D")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("D"), graph.FindNodeByUserData("E")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("B"), graph.FindNodeByUserData("E")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("D"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("0"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("1"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("2"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("3"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("4"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("5"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("6"), graph.FindNodeByUserData("F")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("a"), graph.FindNodeByUserData("b")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("b"), graph.FindNodeByUserData("c")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("c"), graph.FindNodeByUserData("d")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("d"), graph.FindNodeByUserData("e")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("a")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("B"), graph.FindNodeByUserData("a")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("C"), graph.FindNodeByUserData("a")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("D"), graph.FindNodeByUserData("a")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("E"), graph.FindNodeByUserData("a")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("F"), graph.FindNodeByUserData("a")));
            graph.Edges.Add(new Edge(graph.FindNodeByUserData("G"), graph.FindNodeByUserData("a")));

            var settings = new SugiyamaLayoutSettings {
                Transformation = PlaneTransformation.Rotation(Math.PI/2),
                EdgeRoutingSettings = {EdgeRoutingMode = EdgeRoutingMode.Spline}
            };
            var layout = new LayeredLayout(graph, settings);
            layout.Run();
            return graph;
        }
        /// <summary>
        /// Default constructor
        /// </summary>
        public GViewer(){
            mdsLayoutSettings = new MdsLayoutSettings();
            sugiyamaSettings = new SugiyamaLayoutSettings();
            // This call is required by the Windows.Forms Form Designer.
            InitializeComponent();

            BackwardEnabled = false;

            ForwardEnabled = false;

            toolbar.MouseMove += ToolBarMouseMoved;

            Assembly a = Assembly.GetExecutingAssembly();   
            foreach (string r in a.GetManifestResourceNames()){
                if (r.Contains("hmove.cur"))
                    panGrabCursor = new Cursor(a.GetManifestResourceStream(r));
                else if (r.Contains("oph.cur"))
                    panOpenCursor = new Cursor(a.GetManifestResourceStream(r));
            }

            originalCursor = Cursor;

            
            panButton.Pushed = false;
            windowZoomButton.Pushed = false;

            layoutSettingsButton.ToolTipText = "Configures the layout algorithm settings";

            undoButton.ToolTipText = "Undo layout editing";
            redoButton.ToolTipText = "Redo layout editing";
            forwardButton.ToolTipText = "Forward";
            panButton.ToolTipText = panButton.Pushed ? panButtonToolTipText : PanButtonDisabledToolTipText;
            windowZoomButton.ToolTipText = windowZoomButton.Pushed
                                               ? WindowZoomButtonToolTipText
                                               : windowZoomButtonDisabledToolTipText;

            InitDrawingLayoutEditor();

            toolbar.Invalidate();

            SuspendLayout();
            InitPanel();
            Controls.Add(toolbar);
            ResumeLayout();          
        }
Пример #20
0
        internal static void OrderLayers(ProperLayeredGraph graph,
                                         LayerArrays layerArrays,
                                         int startOfVirtualNodes,
                                         SugiyamaLayoutSettings settings, CancelToken cancelToken)
        {
            bool hasCrossWeight = false;

            foreach (LayerEdge le in graph.Edges)
            {
                if (le.CrossingWeight != 1)
                {
                    hasCrossWeight = true;
                    break;
                }
            }

            var o = new Ordering(graph, true, layerArrays, startOfVirtualNodes, hasCrossWeight, settings);

            o.Run(cancelToken);
        }
        internal static GeometryGraph CreateAndLayoutGraph()
        {
            double w = 40;
            double h = 10;
            GeometryGraph graph = new GeometryGraph();
            // columns
                        var col0 = new[] { "a", "b", "c" };
            var col1 = new[] { "d", "e", "f", "g" };
            var col2 = new[] { "k", "l", "m", "n" };
            var col3 = new[] { "w", "y", "z" };

            var settings = new SugiyamaLayoutSettings();

            foreach (var id in col0)
                DrawingUtilsForSamples.AddNode(id, graph, w, h);
            foreach (var id in col1)
                DrawingUtilsForSamples.AddNode(id, graph, w, h);
            foreach (var id in col2)
                DrawingUtilsForSamples.AddNode(id, graph, w, h);
            foreach (var id in col3)
                DrawingUtilsForSamples.AddNode(id, graph, w, h);

            //pinning columns
                        settings.PinNodesToSameLayer(col0.Select(s => graph.FindNodeByUserData(s)).ToArray());
            settings.PinNodesToSameLayer(col1.Select(s => graph.FindNodeByUserData(s)).ToArray());
            settings.PinNodesToSameLayer(col2.Select(s => graph.FindNodeByUserData(s)).ToArray());
            settings.PinNodesToSameLayer(col3.Select(s => graph.FindNodeByUserData(s)).ToArray());

            AddEdgesBetweenColumns(col0, col1, graph);
            AddEdgesBetweenColumns(col1, col2, graph);
            AddEdgesBetweenColumns(col2, col3, graph);
            // rotate layer to columns
            settings.Transformation = PlaneTransformation.Rotation(Math.PI/2);
            settings.NodeSeparation = 5;
            settings.LayerSeparation = 100;
            var ll = new LayeredLayout(graph, settings);
            ll.Run();
            return graph;
        }
        /// <summary>
        /// Validate two nodes on same layer have valid separation between them
        /// </summary>
        internal static void ValidateIntraLayerNodeSeparation(Node node, Node node2, SugiyamaLayoutSettings settings)
        {

            if (node == node2 || node is Cluster || node2 is Cluster)
            {
                return;
            }
            if (OnSameLayer(node, node2, settings))
            {
                if (Math.Abs(node.Center.Y - node2.Center.Y) <= Tolerance)
                {
                    Rectangle left = node.BoundingBox;
                    Rectangle right = node2.BoundingBox;
                    Rectangle temp;
                    if (left.Left > right.Left)
                    {
                        temp = left;
                        left = right;
                        right = temp;
                    }
                    Assert.IsTrue(Math.Abs(right.Left - left.Right) >= settings.NodeSeparation, string.Format("Node (ID: {0}, BoundingBox: {1}) has less separation from Node (ID: {2}, BoundingBox: {3})", node.UserData, node.BoundingBox.ToString(), node2.UserData, node2.BoundingBox.ToString()));
                }
                else
                {
                    Rectangle top = node.BoundingBox;
                    Rectangle bottom = node2.BoundingBox;
                    Rectangle temp;
                    if (top.Top < bottom.Top)
                    {
                        temp = top;
                        top = bottom;
                        bottom = temp;
                    }
                    Assert.IsTrue(Math.Abs(top.Bottom - bottom.Top) >= settings.NodeSeparation, string.Format("Node (ID: {0}, BoundingBox: {1}) has less separation from Node (ID: {2}, BoundingBox: {3})", node.UserData, node.BoundingBox.ToString(), node2.UserData, node2.BoundingBox.ToString()));
                }
            }
        }
        internal ConstrainedOrdering(
            GeometryGraph geomGraph,
            BasicGraph <Node, IntEdge> basicIntGraph,
            int[] layering,
            Dictionary <Node, int> nodeIdToIndex,
            Database database,
            SugiyamaLayoutSettings settings)
        {
            this.settings         = settings;
            horizontalConstraints = settings.HorizontalConstraints;

            horizontalConstraints.PrepareForOrdering(nodeIdToIndex, layering);

            geometryGraph   = geomGraph;
            this.database   = database;
            intGraph        = basicIntGraph;
            initialLayering = layering;
            //this has to be changed only to insert layers that are needed
            if (NeedToInsertLayers(layering))
            {
                for (int i = 0; i < layering.Length; i++)
                {
                    layering[i] *= 2;
                }
                LayersAreDoubled = true;
                numberOfLayers   = -1;
            }

            PrepareProperLayeredGraphAndFillLayerInfos();

            adjSwapper = new AdjacentSwapsWithConstraints(
                LayerArrays,
                HasCrossWeights(),
                ProperLayeredGraph,
                layerInfos);
        }
        static void RightAnchorMultiSelfEdges(int i, ref double rightAnchor, ref double topAnchor,
                                              ref double bottomAnchor, Database database,
                                              SugiyamaLayoutSettings settings) {
            double delta = WidthOfSelfEdge(database, i, ref rightAnchor, ref topAnchor, ref bottomAnchor, settings);

            rightAnchor += delta;
        }
        static void CalcAnchorsForOriginalNode(int i, BasicGraph<Node, IntEdge> intGraph, Anchor[] anchors,
                                               Database database, SugiyamaLayoutSettings settings) {
            double leftAnchor = 0;
            double rightAnchor = leftAnchor;
            double topAnchor = 0;
            double bottomAnchor = topAnchor;

            //that's what we would have without the label and multiedges 

            if (intGraph.Nodes != null) {
                Node node = intGraph.Nodes[i];
                ExtendStandardAnchors(ref leftAnchor, ref rightAnchor, ref topAnchor, ref bottomAnchor, node, settings);
            }

            RightAnchorMultiSelfEdges(i, ref rightAnchor, ref topAnchor, ref bottomAnchor, database, settings);

            double hw = settings.MinNodeWidth/2;
            if (leftAnchor < hw)
                leftAnchor = hw;
            if (rightAnchor < hw)
                rightAnchor = hw;
            double hh = settings.MinNodeHeight/2;

            if (topAnchor < hh)
                topAnchor = hh;
            if (bottomAnchor < hh)
                bottomAnchor = hh;

            anchors[i] = new Anchor(leftAnchor, rightAnchor, topAnchor, bottomAnchor, intGraph.Nodes[i],
                                    settings.LabelCornersPreserveCoefficient) {Padding = intGraph.Nodes[i].Padding};
#if TEST_MSAGL
            anchors[i].UserData = intGraph.Nodes[i].UserData;
#endif
        }
 internal static Directions GetLayoutDirection(SugiyamaLayoutSettings settings) {
     Point dir = settings.Transformation*new Point(0, 1);
     return dir.CompassDirection;
 }
 static double SetFlatEdgesForLayer(Database database, LayerArrays layerArrays, int i,
                                    BasicGraph<IntEdge> intGraph, SugiyamaLayoutSettings settings, double ymax) {
     double flatEdgesHeight = 0;
     if (i > 0) {
         //looking for flat edges on the previous level                
         //we stack labels of multiple flat edges on top of each other
         IEnumerable<IntPair> flatPairs = GetFlatPairs(layerArrays.Layers[i - 1], layerArrays.Y,
                                                       intGraph);
         if (flatPairs.Any()) {
             double dyOfFlatEdge = settings.LayerSeparation/3;
             double ym = ymax;
             flatEdgesHeight =
                 (from pair in flatPairs
                  select SetFlatEdgesLabelsHeightAndPositionts(pair, ym, dyOfFlatEdge, database)).
                     Max();
         }
     }
     return flatEdgesHeight;
 }
 private static bool NeedToSnapBottomsToGrid(SugiyamaLayoutSettings settings)
 {
     return settings.SnapToGridByY == SnapToGridByY.Bottom;
 }
        /// <summary>
        /// 
        /// </summary>
        /// <returns>the height of the graph+spaceBeforeMargins</returns>
        internal static void CalcInitialYAnchorLocations(LayerArrays layerArrays, double spaceBeforeMargins,
                                                         GeometryGraph originalGraph, Database database,
                                                         BasicGraph<IntEdge> intGraph,
                                                         SugiyamaLayoutSettings settings,
                                                         bool layersAreDoubled) {
            Anchor[] anchors = database.Anchors;
            double ymax = originalGraph.Margins + spaceBeforeMargins; //setting up y coord - going up by y-layers
            int i = 0;
            foreach (var yLayer in layerArrays.Layers) {
                double bottomAnchorMax = 0;
                double topAnchorMax = 0;
                foreach (int j in yLayer) {
                    Anchor p = anchors[j];
                    if (p.BottomAnchor > bottomAnchorMax)
                        bottomAnchorMax = p.BottomAnchor;
                    if (p.TopAnchor > topAnchorMax)
                        topAnchorMax = p.TopAnchor;
                }

                MakeVirtualNodesTall(yLayer, bottomAnchorMax, topAnchorMax, originalGraph.Nodes.Count, database.Anchors);

                double flatEdgesHeight = SetFlatEdgesForLayer(database, layerArrays, i, intGraph, settings, ymax);

                double layerCenter = ymax + bottomAnchorMax + flatEdgesHeight;
                double layerTop = layerCenter + topAnchorMax;
                if (NeedToSnapTopsToGrid(settings)) {
                    layerTop += SnapDeltaUp(layerTop, settings.GridSizeByY);
                    foreach (int j in yLayer) anchors[j].Top = layerTop;                   
                } else if (NeedToSnapBottomsToGrid(settings)) {
                    double layerBottom = layerCenter - bottomAnchorMax;
                    layerBottom += SnapDeltaUp(layerBottom, layerBottom);
                    foreach (int j in yLayer)
                    {
                        anchors[j].Bottom = layerBottom;
                        layerTop = Math.Max(anchors[j].Top, layerTop);
                    }
                }
                else foreach (int j in yLayer) anchors[j].Y = layerCenter;
                
                double layerSep = settings.ActualLayerSeparation(layersAreDoubled);
                ymax = layerTop + layerSep;
                i++;
            }
            // for the last layer
            SetFlatEdgesForLayer(database, layerArrays, i, intGraph, settings, ymax);
        }
        /// <summary>
        /// Simpler constructor which initializes the internal graph representation automatically
        /// </summary>
        /// <param name="originalGraph"></param>
        /// <param name="settings"></param>
        internal LayeredLayoutEngine(GeometryGraph originalGraph, SugiyamaLayoutSettings settings) {
            if (originalGraph != null) {
                //enumerate the nodes - maps node indices to strings 
                nodeIdToIndex = new Dictionary<Node, int>();

                IList<Node> nodes = originalGraph.Nodes;

                int index = 0;
                foreach (Node n in nodes) {
                    nodeIdToIndex[n] = index;
                    index++;
                }

                var edges = originalGraph.Edges;

                var intEdges = new IntEdge[edges.Count];
                int i = 0;
                foreach(var edge in edges){
                
                    if (edge.Source == null || edge.Target == null)
                        throw new InvalidOperationException(); //"creating an edge with null source or target");

                    var intEdge = new IntEdge(nodeIdToIndex[edge.Source], nodeIdToIndex[edge.Target], edge);

                    intEdges[i] = intEdge;
                    i++;
                }

                IntGraph = new BasicGraph<Node, IntEdge>(intEdges, originalGraph.Nodes.Count) {Nodes = nodes};
                this.originalGraph = originalGraph;
                sugiyamaSettings = settings;
                Database = new Database();
                foreach (IntEdge e in IntGraph.Edges)
                    database.RegisterOriginalEdgeInMultiedges(e);

                CycleRemoval();
            }
        }
        internal static void CalculateAnchorSizes(Database database, out Anchor[] anchors,
                                                  ProperLayeredGraph properLayeredGraph, GeometryGraph originalGraph,
                                                  BasicGraph<Node, IntEdge> intGraph, SugiyamaLayoutSettings settings) {
            database.Anchors = anchors = new Anchor[properLayeredGraph.NodeCount];

            for (int i = 0; i < anchors.Length; i++)
                anchors[i] = new Anchor(settings.LabelCornersPreserveCoefficient);

            //go over the old vertices
            for (int i = 0; i < originalGraph.Nodes.Count; i++)
                CalcAnchorsForOriginalNode(i, intGraph, anchors, database, settings);

            //go over virtual vertices
            foreach (IntEdge intEdge in database.AllIntEdges)
                if (intEdge.LayerEdges != null) {
                    foreach (LayerEdge layerEdge in intEdge.LayerEdges) {
                        int v = layerEdge.Target;
                        if (v != intEdge.Target) {
                            Anchor anchor = anchors[v];
                            if (!database.MultipleMiddles.Contains(v)) {
                                anchor.LeftAnchor = anchor.RightAnchor = VirtualNodeWidth/2.0f;
                                anchor.TopAnchor = anchor.BottomAnchor = VirtualNodeHeight(settings)/2.0f;
                            } else {
                                anchor.LeftAnchor = anchor.RightAnchor = VirtualNodeWidth*4;
                                anchor.TopAnchor = anchor.BottomAnchor = VirtualNodeHeight(settings)/2.0f;
                            }
                        }
                    }
                    //fix label vertices      
                    if (intEdge.HasLabel) {
                        int lj = intEdge.LayerEdges[intEdge.LayerEdges.Count/2].Source;
                        Anchor a = anchors[lj];
                        double w = intEdge.LabelWidth, h = intEdge.LabelHeight;
                        a.RightAnchor = w;
                        a.LeftAnchor = VirtualNodeWidth*8;

                        if (a.TopAnchor < h/2.0)
                            a.TopAnchor = a.BottomAnchor = h/2.0;

                        a.LabelToTheRightOfAnchorCenter = true;
                    }
                }
        }
        /// <summary>
        /// constructor
        /// </summary>
        internal LayeredLayoutEngine(GeometryGraph originalGraph, BasicGraph<Node, IntEdge> graph,
                                     Dictionary<Node, int> nodeIdToIndex, SugiyamaLayoutSettings settings) {
            if (originalGraph != null) {
                this.originalGraph = originalGraph;
                sugiyamaSettings = settings;
                IntGraph = graph;
                Database = new Database();
                this.nodeIdToIndex = nodeIdToIndex;
                foreach (IntEdge e in graph.Edges)
                    database.RegisterOriginalEdgeInMultiedges(e);
#if REPORTING
                if (sugiyamaSettings.Reporting && SugiyamaLayoutLogger == null)
                    SugiyamaLayoutLogger = new SugiyamaLayoutLogger();
#endif
                CycleRemoval();
            }
        }
        static double WidthOfSelfEdge(Database database, int i, ref double rightAnchor, ref double topAnchor,
                                      ref double bottomAnchor, SugiyamaLayoutSettings settings) {
            double delta = 0;
            List<IntEdge> multiedges = database.GetMultiedge(i, i);
            //it could be a multiple self edge
            if (multiedges.Count > 0) {
                foreach (IntEdge e in multiedges)
                    if (e.Edge.Label != null) {
                        rightAnchor += e.Edge.Label.Width;
                        if (topAnchor < e.Edge.Label.Height/2.0)
                            topAnchor = bottomAnchor = e.Edge.Label.Height/2.0f;
                    }

                delta += (settings.NodeSeparation + settings.MinNodeWidth)*multiedges.Count;
            }
            return delta;
        }
    //takes a target Tree object and builds actual game nodes for it - using MSAGL as an intermediate representation for layout
    public void BuildTree(Tree target)
    {
        if (target == null)
        {
            return;                 //do not attempt to build a null tree - this means that a syntax error happened in a newick file
        }
        GameManager.DebugLog("Building tree with layout: " + eventManager.Current_Tree_State);

        ResetTreeContainer();

        GeometryGraph asMSAGL = ToMSALGraph(target);

        List <GameObject> generatedNodes = new List <GameObject>();

        //define how we want the tree to be layed out
        LayoutAlgorithmSettings settings;

        switch (eventManager.Current_Tree_State)
        {
        default:
        case InputEventManager.TreeState.BasicTree:
            settings = new Microsoft.Msagl.Layout.Layered.SugiyamaLayoutSettings();
            break;

        case InputEventManager.TreeState.TerrainTree:
        case InputEventManager.TreeState.CircularTree:
            settings = new FastIncrementalLayoutSettings();
            break;
        }

        //apply some extra settings and layout the graph according to all settings
        settings.EdgeRoutingSettings.EdgeRoutingMode = Microsoft.Msagl.Core.Routing.EdgeRoutingMode.StraightLine;
        settings.PackingMethod = PackingMethod.Compact;
        LayoutHelpers.CalculateLayout(asMSAGL, settings, null);

        //we want world space 0, 0 to be equivalent to graph space 0, 0
        float offSetX = (float)asMSAGL.Nodes[0].Center.X;
        float offSetY = (float)asMSAGL.Nodes[0].Center.Y;
        //msal graph edge weights are enormous, like hundreds of meters of in world space - scale it down
        float scaleFactor = eventManager.Current_Tree_State == InputEventManager.TreeState.TerrainTree ?
                            1f / 30f : 1f / 250f;

        //build game objects using msagl graph as spatial layout
        foreach (Microsoft.Msagl.Core.Layout.Node node in asMSAGL.Nodes)
        {
            float x = ((float)node.Center.X - offSetX) * scaleFactor;
            float y = ((float)node.Center.Y - offSetY) * scaleFactor;

            GameObject newNode = Instantiate(nodePrefab, new Vector3(
                                                 treeContainer.transform.position.x + x,
                                                 treeContainer.transform.position.y + y,
                                                 treeContainer.transform.position.z
                                                 ),
                                             Quaternion.identity);
            newNode.transform.SetParent(treeContainer.transform);
            newNode.GetComponent <BasicNodeBehaviour>().attachNodeInfo((Node)node.UserData);
            newNode.GetComponentInChildren <InfoOnHover>()._Init();
            node.UserData = newNode;

            generatedNodes.Add(newNode);

            foreach (Edge edge in node.Edges)
            {
                if (edge.Target == node)
                {
                    Line l = newNode.transform.Find("Renderer").gameObject.AddComponent <Line>();
                    l.gameObject1 = newNode;
                    l.gameObject2 = (GameObject)edge.Source.UserData;
                    newNode.transform.SetParent(((GameObject)edge.Source.UserData).transform);
                    if (newNode.GetComponent <BasicNodeBehaviour>().getAttachedNodeInfo().weightToParentSet())
                    {
                        l.setLabel("" + newNode.GetComponent <BasicNodeBehaviour>().getAttachedNodeInfo().getWeightToParent());
                    }
                    else
                    {
                        l.setLabel("");
                    }
                }
            }
        }

        if (eventManager.Current_Tree_State == InputEventManager.TreeState.TerrainTree)
        {
            Vector3 translation = new Vector3(0, -4, 0);
            treeContainer.transform.Translate(translation);
            treeContainer.transform.Rotate(90, 0, 0);

            List <GameObject> leafNodesList = new List <GameObject>();

            foreach (GameObject node in generatedNodes)
            {
                //scale up the nodes a bit to make them clearer within the terrain
                float scale = node.GetComponentInChildren <MaintainNodeScale>().targetScale;
                node.GetComponentInChildren <MaintainNodeScale>().targetScale = 2 * scale;
                node.transform.hasChanged = true;
                if (node.GetComponent <BasicNodeBehaviour>().getAttachedNodeInfo().getNumberOfChildren() == 0)
                {
                    leafNodesList.Add(node);
                }
            }

            generatedNodes[0].GetComponentInChildren <MaintainNodeScale>().targetScale = 4f;

            GameManager.DebugLog("Found " + leafNodesList.Count + " leaf nodes");

            TreeTerrainBehaviour.instance.Activate();
            TreeTerrainBehaviour.instance.ResetHeights();

            leafNodes = leafNodesList.ToArray();
            EnableOnFrameLoading();
        }
        else
        {
            DisableOnFrameLoading();
            //the player won't be moving while we aren't looking at terrain so we'll reset their position
        }

        if (eventManager.Draw_Tree_In_3D)
        {
            TreeConverter3D.Convert(treeContainer.transform.GetChild(0).gameObject);
        }

        //as a last step, reset the position of the player so they are close to the root of whatever tree they built
        player.GetComponent <PositionResetter>().ResetPosition();
    }
        void WriteSugiyamaSettings(SugiyamaLayoutSettings sugiyama) {
            WriteAttribute(GeometryToken.LayoutAlgorithmType, GeometryToken.SugiyamaLayoutSettings);
            WriteAttribute(GeometryToken.MinNodeWidth, sugiyama.MinNodeWidth);
            WriteAttribute(GeometryToken.MinNodeHeight, sugiyama.MinNodeHeight);
            WriteAttribute(GeometryToken.AspectRatio, sugiyama.AspectRatio);
            WriteAttribute(GeometryToken.NodeSeparation, sugiyama.NodeSeparation);
#if REPORTING
            WriteAttribute(GeometryToken.Reporting, sugiyama.Reporting);
#endif
            WriteAttribute(GeometryToken.RandomSeedForOrdering, sugiyama.RandomSeedForOrdering);
            WriteAttribute(GeometryToken.NoGainStepsBound, sugiyama.NoGainAdjacentSwapStepsBound);
            WriteAttribute(GeometryToken.MaxNumberOfPassesInOrdering, sugiyama.MaxNumberOfPassesInOrdering);
            WriteAttribute(GeometryToken.RepetitionCoefficientForOrdering,
                               sugiyama.RepetitionCoefficientForOrdering);
            WriteAttribute(GeometryToken.GroupSplit, sugiyama.GroupSplit);
            WriteAttribute(GeometryToken.LabelCornersPreserveCoefficient,
                               sugiyama.LabelCornersPreserveCoefficient);
            WriteAttribute(GeometryToken.BrandesThreshold, sugiyama.BrandesThreshold);
            WriteAttribute(GeometryToken.LayerSeparation, sugiyama.LayerSeparation);
            WriteTransformation(sugiyama.Transformation);
        }
        static void ExtendStandardAnchors(ref double leftAnchor, ref double rightAnchor, ref double topAnchor,
                                          ref double bottomAnchor, Node node, SugiyamaLayoutSettings settings) {
            double w = node.Width;
            double h = node.Height;


            w /= 2.0;
            h /= 2.0;


            rightAnchor = leftAnchor = w;
            topAnchor = bottomAnchor = h;
            if (settings.GridSizeByX > 0)
            {
                rightAnchor += settings.GridSizeByX / 2;
                leftAnchor += settings.GridSizeByX / 2;
            }
        }
 void Show()
 {
     SugiyamaLayoutSettings.ShowDatabase(database);
 }
 /// <summary>
 /// the height of dummy nodes
 /// </summary>
 static double VirtualNodeHeight(SugiyamaLayoutSettings settings) {
     return settings.MinNodeHeight*1.5f/8;
 }
Пример #39
0
 internal FlatEdgeRouter(SugiyamaLayoutSettings settings, Routing routing)
 {
     this.settings = settings;
     this.routing  = routing;
 }
Пример #40
0
 /// <summary>
 /// Layered layout arranged the given graph on layers inferred from the directed edge structure
 /// </summary>
 /// <param name="geometryGraph">graph to be laid out</param>
 /// <param name="settings">The settings for the algorithm.</param>
 public LayeredLayout(GeometryGraph geometryGraph, SugiyamaLayoutSettings settings)
 {
     this.geometryGraph = geometryGraph;
     this.settings      = settings;
     this.engine        = new LayeredLayoutEngine(geometryGraph, settings);
 }
Пример #41
0
        internal static LayeredLayoutEngine CalculateLayout(GeometryGraph msaglGraph, SugiyamaLayoutSettings settings, CancelToken cancelToken)
        {
            LayeredLayoutEngine engine = new LayeredLayoutEngine(msaglGraph, settings);

#if USE_PHYLOTREE
            PhyloTree phyloTree = msaglGraph as PhyloTree;

            if (phyloTree != null)
            {
                PhyloTreeLayoutCalclulation pc = new PhyloTreeLayoutCalclulation(phyloTree, settings, engine.IntGraph, engine.Database);
                pc.Run();
            }
            else
#endif
            engine.Run(cancelToken);

            return(engine);
        }