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 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"); }
void LayoutOneComponent(GeometryGraph component) { PrepareGraphForLayout(component); if (component.RootCluster.Clusters.Any()) { var layoutSettings = new SugiyamaLayoutSettings { FallbackLayoutSettings = new FastIncrementalLayoutSettings { AvoidOverlaps = true }, NodeSeparation = lgLayoutSettings.NodeSeparation, LayerSeparation = lgLayoutSettings.NodeSeparation, EdgeRoutingSettings = lgLayoutSettings.EdgeRoutingSettings, LayeringOnly = true }; var initialBc = new InitialLayoutByCluster(component, a => layoutSettings); initialBc.Run(); } else { LayoutHelpers.CalculateLayout(component, GetMdsLayoutSettings(), cancelToken); } var box = component.BoundingBox; box.Pad(lgLayoutSettings.NodeSeparation / 2); component.BoundingBox = box; }
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, //use different settings per each Cluster if available c => sugiyamaLayoutSettings.ClusterSettings.ContainsKey(c.UserData) ? sugiyamaLayoutSettings.ClusterSettings[c.UserData] : sugiyamaLayoutSettings); initialBc.Run(cancelToken); //route the rest of the edges, those between the clusters var edgesToRoute = sugiyamaLayoutSettings.EdgeRoutingSettings.EdgeRoutingMode == EdgeRoutingMode.SplineBundling ? geometryGraph.Edges.ToArray() : geometryGraph.Edges.Where(e => e.Curve == null).ToArray(); RouteAndLabelEdges(geometryGraph, sugiyamaLayoutSettings, edgesToRoute, 0, cancelToken); } else { geometryGraph.AlgorithmData = SugiyamaLayoutSettings.CalculateLayout(geometryGraph, sugiyamaLayoutSettings, cancelToken); } if (transformIsNotIdentity) { sugiyamaLayoutSettings.Transformation = originalTransform; } PostRunTransform(geometryGraph, sugiyamaLayoutSettings); }
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 TreeGraphMdsLayout() { GeometryGraph treeGraph = GraphGenerator.GenerateTree(20); treeGraph.RootCluster = new Cluster(treeGraph.Nodes); var settings = new MdsLayoutSettings { ScaleX = 1, ScaleY = 1, RemoveOverlaps = true, PackingAspectRatio = 1.4 }; 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)); } 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, 1.4, "Aspect ratio too far from desired"); Assert.AreEqual(1.0, progress, "Progress was never reported as 100%. Last update was at " + progress + "%"); }
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 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 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"); } }
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(); } }
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"); }
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 }