static void ProcessSugiamaLayout(GeometryGraph geometryGraph, SugiyamaLayoutSettings sugiyamaLayoutSettings, CancelToken cancelToken) {
            PlaneTransformation originalTransform;
            var transformIsNotIdentity = HandleTransformIsNotIdentity(geometryGraph, sugiyamaLayoutSettings, out originalTransform);

            if (geometryGraph.RootCluster.Clusters.Any()) {
                PrepareGraphForInitialLayoutByCluster(geometryGraph, sugiyamaLayoutSettings);
                var initialBc = new InitialLayoutByCluster(geometryGraph, a => sugiyamaLayoutSettings);
                initialBc.Run(cancelToken);
                //route the rest of the edges, those between the clusters
                RouteAndLabelEdges(geometryGraph, sugiyamaLayoutSettings,
                    geometryGraph.Edges.Where(e => e.Curve == null).ToArray());
            }
            else
                geometryGraph.AlgorithmData = SugiyamaLayoutSettings.CalculateLayout(geometryGraph,
                    sugiyamaLayoutSettings, cancelToken);

            if (transformIsNotIdentity)
                sugiyamaLayoutSettings.Transformation = originalTransform;

            PostRunTransform(geometryGraph, sugiyamaLayoutSettings);
        }
        public void RoutingWithThreeGroups()
        {
            var graph = LoadGraph("abstract.msagl.geom");
            var root = graph.RootCluster;
            var a = new Cluster { UserData = "a" };
            foreach (string id in new[] { "17", "39", "13", "19", "28", "12" })
                a.AddChild(graph.FindNodeByUserData(id));

            var b = new Cluster { UserData = "b" };
            b.AddChild(a);
            b.AddChild(graph.FindNodeByUserData("18"));
            root.AddChild(b);

            var c = new Cluster { UserData = "c" };
            foreach (string id in new[] { "30", "5", "6", "7", "8" })
                c.AddChild(graph.FindNodeByUserData(id));
            root.AddChild(c);

            var clusterNodes = new Set<Node>(root.AllClustersDepthFirst().SelectMany(cl => cl.Nodes));
            foreach (var node in graph.Nodes.Where(n => clusterNodes.Contains(n) == false))
                root.AddChild(node);

            FixClusterBoundariesWithNoRectBoundaries(root, 5);
            var defaultSettings = new FastIncrementalLayoutSettings();
            var rootSettings = new FastIncrementalLayoutSettings() { AvoidOverlaps = true };

            var initialLayout = new InitialLayoutByCluster(graph, new[] { graph.RootCluster }, cl => cl == root ? rootSettings : defaultSettings);
            initialLayout.Run();
            
            const double Padding = 5;

            SplineRouter splineRouter = new SplineRouter(graph, Padding/3, Padding, Math.PI / 6);
            splineRouter.Run();
#if TEST_MSAGL
            if (!DontShowTheDebugViewer())
            {
                graph.UpdateBoundingBox();
                DisplayGeometryGraph.ShowGraph(graph);                
            }
#endif
            
        }
 static void Layout(GeometryGraph graph, Random rnd)
 {
     if (rnd.Next() % 5 < 3){ 
         var settings = new SugiyamaLayoutSettings();
         var layout = new InitialLayoutByCluster(graph, settings) {RunInParallel = false};
         layout.Run();
     }
     else {
         var settings = new FastIncrementalLayoutSettings { AvoidOverlaps = true };
         var layout = new InitialLayoutByCluster(graph, settings);
         layout.Run();
     }
 }
        static void LoadGeomFile(string s, EdgeRoutingSettings edgeRoutingSettings, bool show) {
            LayoutAlgorithmSettings settings;
            GeometryGraph geomGraph = GeometryGraphReader.CreateFromFile(s, out settings);
            if (geomGraph == null) {
                //Opens file "data.xml" and deserializes the object from it.
                var stream = File.Open(s, FileMode.Open);
                var formatter = new BinaryFormatter();
                geomGraph = (GeometryGraph) formatter.Deserialize(stream);
                geomGraph.RootCluster = new Cluster();
                stream.Close();
            }
            geomGraph.UpdateBoundingBox();
            if (FormStuff.initialLayout) {
                var l = new List<Cluster>();
                l.Add(geomGraph.RootCluster);
                var il = new InitialLayoutByCluster(geomGraph, new FastIncrementalLayoutSettings());
                il.Run();
            }
            else if (mds) {
                var mdsSettings = new MdsLayoutSettings
                { IterationsWithMajorization = 21,ScaleX = 1, ScaleY=1, RemoveOverlaps = true
                };
                var mdslayout = new MdsGraphLayout(mdsSettings, geomGraph);
                mdslayout.Run();
                var router = new SplineRouter(geomGraph, 1, 20, Math.PI / 6, edgeRoutingSettings.BundlingSettings);
                router.Run();
            }
            else {
                var sugiyamaSettings = (SugiyamaLayoutSettings) settings;
                if (edgeRoutingSettings.EdgeRoutingMode == EdgeRoutingMode.Rectilinear ||
                    edgeRoutingSettings.EdgeRoutingMode == EdgeRoutingMode.RectilinearToCenter) {
                    RouteRectEdgesOfGeomGraph(edgeRoutingSettings.EdgeRoutingMode, true, 
                                            edgeRoutingSettings.UseObstacleRectangles, edgeRoutingSettings.BendPenalty, geomGraph, sugiyamaSettings);
                } else {
                    const double angle = 30*Math.PI/180;
                    var router = new SplineRouter(geomGraph, 1, 20, angle, edgeRoutingSettings.BundlingSettings);
                    router.Run();

                    TestPadding(geomGraph);
                }
            }

#if DEBUG
            if (show) {
                geomGraph.UpdateBoundingBox();
                var b = geomGraph.BoundingBox;
                b.Pad(40);
                geomGraph.BoundingBox = b;
                DisplayGeometryGraph.ShowGraph(geomGraph);
            }
#endif
        }
        static GeometryGraph GetTestGraphWithClusters(out LayoutAlgorithmSettings settings) {            
            GeometryGraph graph =
                GeometryGraphReader.CreateFromFile(
                    "C:\\dev\\GraphLayout\\MSAGLTests\\Resources\\MSAGLGeometryGraphs\\abstract.msagl.geom",
                    //"E:\\dev\\MSAGL\\GraphLayout\\MSAGLTests\\Resources\\MSAGLGeometryGraphs\\abstract.msagl.geom",
                    out settings);
            foreach (var edge in graph.Edges) {
                edge.Curve = null;
                edge.EdgeGeometry.TargetArrowhead = null;
            }
            graph.UpdateBoundingBox();
            var root = graph.RootCluster;
            var a = new Cluster {UserData = "a"};
            foreach (string id in new[] {"17", "39", "13", "19", "28", "12"})
                a.AddChild(graph.FindNodeByUserData(id));

            var b = new Cluster {UserData = "b"};
            b.AddChild(a);
            b.AddChild(graph.FindNodeByUserData("18"));
            root.AddChild(b);

            var c = new Cluster {UserData = "c"};
            foreach (string id in new[] {"30", "5", "6", "7", "8"})
                c.AddChild(graph.FindNodeByUserData(id));
            root.AddChild(c);

            var clusterNodes = new Set<Node>(root.AllClustersDepthFirst().SelectMany(cl => cl.Nodes));
            foreach (var node in graph.Nodes.Where(n => clusterNodes.Contains(n) == false))
                root.AddChild(node);

            FixClusterBoundariesWithNoRectBoundaries(root, 5);
            var fastIncrementalLayoutSettings = new FastIncrementalLayoutSettings();


            var d=new Dictionary<Cluster, LayoutAlgorithmSettings>();
            d[root] = new FastIncrementalLayoutSettings { AvoidOverlaps = true };

            var initialLayout = new InitialLayoutByCluster(graph, fastIncrementalLayoutSettings);
            initialLayout.Run();
            graph.UpdateBoundingBox();
            //FixClusterBoundariesWithNoRectBoundaries(root, 5);
            return graph;
        }
        public void TreeGraphFastIncrementalLayout()
        {
            GeometryGraph treeGraph = GraphGenerator.GenerateTree(20);
            treeGraph.RootCluster = new Cluster(treeGraph.Nodes);
            var settings = new FastIncrementalLayoutSettings { AvoidOverlaps = true, PackingAspectRatio = 1.6 };
            settings.EdgeRoutingSettings = new EdgeRoutingSettings { EdgeRoutingMode = EdgeRoutingMode.Spline, ConeAngle = Math.PI / 6, Padding = settings.NodeSeparation / 2.1 };
            foreach (var v in treeGraph.Nodes)
            {
                v.BoundingBox = new Rectangle(0, 0, new Point(30, 30));
            }
            foreach (var e in treeGraph.Edges)
            {
                e.EdgeGeometry.SourceArrowhead = new Arrowhead { Length = 4, Width = 4 };
                e.EdgeGeometry.TargetArrowhead = new Arrowhead { Length = 8, Width = 4 };
            }
            var layout = new InitialLayoutByCluster(treeGraph, settings);

            double progress = 0.0;

            EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete;

            try
            {
                layout.ProgressChanged += handler;
                layout.Run();
            }
            finally
            {
                layout.ProgressChanged -= handler;
            }

            EnableDebugViewer();
            ShowGraphInDebugViewer(treeGraph);

            const double EdgeLengthDelta = 0.5;

            foreach (var e in treeGraph.Edges)
            {
                Assert.IsNotNull(e.Curve, "Edge curves not populated");
                if (e.Source != e.Target)
                {
                    double actualLength = (e.Source.Center - e.Target.Center).Length;
                    double actualDesiredRatio = e.Length / actualLength;
                    Assert.AreEqual(1, actualDesiredRatio, EdgeLengthDelta, "Edge length is not correct");
                }
            }

            double aspectRatio = treeGraph.BoundingBox.Width / treeGraph.BoundingBox.Height;
            Assert.AreEqual(settings.PackingAspectRatio, aspectRatio, 0.2, "Aspect ratio too far from desired");

            Assert.AreEqual(1.0, progress, "Progress was never reported as 100%.  Last update was at " + progress + "%");
        }
        public void DenseClusteringNoEdges()
        {
            GeometryGraph graph = new GeometryGraph();
            const double Scale = 100;
            const double Margin = 5;
            for (int i = 0; i < 9; ++i)
            {
                graph.Nodes.Add(new Node(CurveFactory.CreateRectangle(Scale, Scale, new Point())));
            }
            Cluster innerCluster = CreateCluster(graph.Nodes.Take(2), Margin);
            Cluster outerCluster = CreateCluster(graph.Nodes.Take(4).Except(innerCluster.Nodes), Margin);
            outerCluster.AddChild(innerCluster);
            graph.RootCluster = new Cluster(graph.Nodes.Except(graph.Nodes.Take(4)));
            graph.RootCluster.AddChild(outerCluster);
            var initialLayout = new InitialLayoutByCluster(
                graph, new FastIncrementalLayoutSettings { NodeSeparation = Margin, ClusterMargin = Margin / 2, PackingAspectRatio = 1 });
            initialLayout.Run();

            EnableDebugViewer();
            ShowGraphInDebugViewer(graph);

            Assert.IsTrue(
                ApproximateComparer.Close(graph.BoundingBox.LeftBottom, new Point()), "Graph origin is not 0,0");
            Assert.AreEqual(340, graph.BoundingBox.Width, 0.1, "Width is incorrect");
            Assert.AreEqual(340, graph.BoundingBox.Height, 0.1, "Height is incorrect");

        }
        public void LayeredLayoutOrientationByCluster()
        {
            var clusteredGraph = CreateClusteredGraph(padding: 1);
            foreach(var e in clusteredGraph.Edges)
            {
                e.Labels.Add(new Label(40,10,e));
            }
            var defaultSettings = new SugiyamaLayoutSettings { NodeSeparation = 5, PackingAspectRatio = 1.3, LayerSeparation = 5 };
            var settings = new Dictionary<Cluster, LayoutAlgorithmSettings>();
            foreach (var c in clusteredGraph.RootCluster.Clusters)
            {
                var localSettings = (SugiyamaLayoutSettings)defaultSettings.Clone();
                localSettings.Transformation = PlaneTransformation.Rotation(Math.PI / 2);
                settings[c] = localSettings;
            }
            var layout = new InitialLayoutByCluster(clusteredGraph, c => settings.ContainsKey(c) ? settings[c] : defaultSettings);

            double progress = 0.0;
            EnableDebugViewer();

            EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete;

            try
            {
                layout.ProgressChanged += handler;
                layout.Run();
            }
            finally
            {
                layout.ProgressChanged -= handler;
            }

            double aspectRatio = clusteredGraph.BoundingBox.Width / clusteredGraph.BoundingBox.Height;

            //Assert.AreEqual(1.0, progress, "Progress was never reported as 100%.  Last update was at " + progress + "%");
            //var router = new SplineRouter(clusteredGraph, settings.Padding, settings.Padding/2.1, Math.PI/6);
            //router.Run();
            ShowGraphInDebugViewer(clusteredGraph);

            // lots of components in this graph, it gets pretty close to the ideal aspect ratio
            Assert.AreEqual(defaultSettings.PackingAspectRatio, aspectRatio, 0.2, "Difference between actual and desired aspect ratios too large");

            foreach (var e in clusteredGraph.Edges)
            {
                if (e.Source.ClusterParents.Contains(clusteredGraph.RootCluster) || e.Target.ClusterParents.Contains(clusteredGraph.RootCluster))
                {
                    Assert.IsTrue(e.Source.Center.Y > e.Target.Center.Y, "Top level edges should be vertical");
                }
                else
                {
                    Assert.IsTrue(e.Source.Center.X < e.Target.Center.X, "Nested edges should be horizontal");
                }
            }
        }
        public void GraphModelGroupedForceDirectedSplineTest()
        {
            LayoutAlgorithmSettings settings;
            var graph = LoadGraph("GraphModelGrouped.msagl.geom", out settings);
            settings = new FastIncrementalLayoutSettings { NodeSeparation = 5, PackingAspectRatio = 1.2, AvoidOverlaps = true };
            settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline;
            settings.EdgeRoutingSettings.Padding = 2;
            var layout = new InitialLayoutByCluster(graph, settings);

            foreach (var c in graph.RootCluster.AllClustersDepthFirst().Where(c => c != graph.RootCluster))
            {
                c.RectangularBoundary = new RectangularClusterBoundary { LeftMargin = 5, RightMargin = 5, BottomMargin = 5, TopMargin = 5 };
                c.BoundaryCurve = CurveFactory.CreateRectangle(30, 30, new Point(15, 15));
            }

            double progress = 0.0;
            EnableDebugViewer();

            EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete;

            try
            {
                layout.ProgressChanged += handler;
                layout.Run();
            }
            finally
            {
                layout.ProgressChanged -= handler;
            }

	    // Ignore this assertion due to bug: 688960 - One MSAGL unit test is failing due to Parallel Linq which affects the Progress accounting.
            //Assert.AreEqual(1.0, progress, "Progress was never reported as 100%.  Last update was at " + progress + "%");

            ShowGraphInDebugViewer(graph);

            foreach (var e in graph.Edges)
            {
                Assert.IsNotNull(e.Curve, "Edge was not routed");
            }
        }
        public void GraphModelGroupedForceDirectedRectilinearTest()
        {
            LayoutAlgorithmSettings settings;
            var graph = LoadGraph("GraphModelGrouped.msagl.geom", out settings);
            settings = new FastIncrementalLayoutSettings { NodeSeparation = 5, PackingAspectRatio = 1.2, AvoidOverlaps = true, GravityConstant = 0.5 };
            settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Rectilinear;
            settings.EdgeRoutingSettings.Padding = 2;
            settings.EdgeRoutingSettings.CornerRadius = 2;
            var layout = new InitialLayoutByCluster(graph, settings);

            foreach (var c in graph.RootCluster.AllClustersDepthFirst().Where(c => c != graph.RootCluster))
            {
                c.RectangularBoundary = new RectangularClusterBoundary { LeftMargin = 5, RightMargin = 5, BottomMargin = 5, TopMargin = 5 };
                c.BoundaryCurve = CurveFactory.CreateRectangle(30, 30, new Point(15, 15));
            }

            double progress = 0.0;
            EnableDebugViewer();

            EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete;

            try
            {
                layout.ProgressChanged += handler;
                layout.Run();
            }
            finally
            {
                layout.ProgressChanged -= handler;
            }

            Assert.IsTrue(1.0 <= progress, "Progress was never reported as 100%.  Last update was at " + progress + "%");
            ShowGraphInDebugViewer(graph);

            foreach (var e in graph.Edges)
            {
                Assert.IsNotNull(e.Curve, "Edge was not routed");
            }
        }
        public void GraphModelGroupedLayeredTest()
        {

            LayoutAlgorithmSettings settings;
            var graph = LoadGraph("GraphModelGrouped.msagl.geom", out settings);
            foreach (var e in graph.Edges)
            {
                e.Labels.Add(new Label(40, 10, e));
            }
            settings = new SugiyamaLayoutSettings { NodeSeparation = 5, PackingAspectRatio = 1.2, LayerSeparation = 5 };
            var layout = new InitialLayoutByCluster(graph, settings);

            foreach (var c in graph.RootCluster.AllClustersDepthFirst().Where(c => c != graph.RootCluster))
            {
                c.RectangularBoundary = new RectangularClusterBoundary { LeftMargin = 5, RightMargin = 5, BottomMargin = 5, TopMargin = 5 };
                c.BoundaryCurve = CurveFactory.CreateRectangle(30, 30, new Point(15, 15));
            }

            double progress = 0.0;
            EnableDebugViewer();

            EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete;

            try
            {
                layout.ProgressChanged += handler;
                layout.Run();
            }
            finally
            {
                layout.ProgressChanged -= handler;
            }

            Assert.AreEqual(1.0, progress, "Progress was never reported as 100%.  Last update was at " + progress + "%");
            ShowGraphInDebugViewer(graph);

            foreach (var e in graph.Edges)
            {
                Assert.IsNotNull(e.Curve, "Edge was not routed");
            }
        }
        public void CalculateLayout_CorrectPacking()
        {
            var clusteredGraph = CreateClusteredGraph(padding: 1);
            var settings = new SugiyamaLayoutSettings { NodeSeparation = 5, PackingAspectRatio = 1.2, LayerSeparation = 5 };
            var layout = new InitialLayoutByCluster(clusteredGraph, settings);

            double progress = 0.0;
            EnableDebugViewer();

            EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete;

            try
            {
                layout.ProgressChanged += handler;
                layout.Run();
            }
            finally
            {
                layout.ProgressChanged -= handler;
            }

            double aspectRatio = clusteredGraph.BoundingBox.Width / clusteredGraph.BoundingBox.Height;

            //Assert.AreEqual(1.0, progress, "Progress was never reported as 100%.  Last update was at " + progress + "%");
            //var router = new SplineRouter(clusteredGraph, settings.Padding, settings.Padding/2.1, Math.PI/6);
            //router.Run();
            ShowGraphInDebugViewer(clusteredGraph);

            foreach (var e in clusteredGraph.Edges)
            {
                Assert.IsNotNull(e.Curve, "Edge was not routed");
            }
            // skinny aspect ratio specified above caused lots of vertical stacking in groups which actually leads
            // to a final aspect ratio close to 1
            Assert.AreEqual(settings.PackingAspectRatio, aspectRatio, 0.2, "Difference between actual and desired aspect ratios too large");
        }