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"); }