/// <summary> /// Simple unconstrained layout of graph used by multiscale layout /// </summary> /// <param name="graph"></param> /// <param name="edgeLengthMultiplier"></param> /// <param name="level">double in range [0,1] indicates how far down the multiscale stack we are /// 1 is at the top, 0 at the bottom, controls repulsive force strength and ideal edge length</param> private void SimpleLayout(GeometryGraph graph, double level, double edgeLengthMultiplier) { var settings = new FastIncrementalLayoutSettings { MaxIterations = 10, MinorIterations = 3, GravityConstant = 1.0 - level, RepulsiveForceConstant = Math.Log(edgeLengthMultiplier * level * 500 + Math.E), InitialStepSize = 0.6 }; foreach (var e in graph.Edges) { e.Length *= Math.Log(level * 500 + Math.E); } settings.InitializeLayout(graph, settings.MinConstraintLevel); do { #pragma warning disable 618 LayoutHelpers.CalculateLayout(graph, settings, null); #pragma warning restore 618 } while (settings.Iterations < settings.MaxIterations); }
public void VisualizeNeuralNetToFile(string neuralNetPicFilePath) { FastIncrementalLayoutSettings fastSettings = new FastIncrementalLayoutSettings { AvoidOverlaps = true, NodeSeparation = 30, RouteEdges = true }; SugiyamaLayoutSettings settings = new SugiyamaLayoutSettings { FallbackLayoutSettings = fastSettings }; m_opsViz.LayoutAlgorithmSettings = settings; Microsoft.Msagl.GraphViewerGdi.GraphRenderer renderer = new Microsoft.Msagl.GraphViewerGdi.GraphRenderer(m_opsViz); renderer.CalculateLayout(); System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap((int)m_opsViz.Width, (int)m_opsViz.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); renderer.Render(bitmap); bitmap.Save(neuralNetPicFilePath); bitmap.Dispose(); }
static Graph CtreateDrawingGraph(out FastIncrementalLayoutSettings settings) { settings = new FastIncrementalLayoutSettings { RouteEdges = true, NodeSeparation = 30 }; var drawingGraph = new Graph(); AddEdge(drawingGraph, "0", "1"); AddEdge(drawingGraph, "0", "2"); AddEdge(drawingGraph, "1", "3"); AddEdge(drawingGraph, "2", "4"); AddEdge(drawingGraph, "2", "5"); AddEdge(drawingGraph, "2", "6"); AddEdge(drawingGraph, "5", "7"); AddEdge(drawingGraph, "5", "6"); AddEdge(drawingGraph, "7", "8"); AddEdge(drawingGraph, "8", "6"); drawingGraph.CreateGeometryGraph(); foreach (DrawingNode node in drawingGraph.Nodes) { double w, h; var label = node.Label; var font = new Font(label.FontName, (float)label.FontSize); StringMeasure.MeasureWithFont(label.Text, font, out w, out h); node.Label.Width = w; node.Label.Height = h; node.Attr.Shape = Shape.DrawFromGeometry; node.GeometryNode.BoundaryCurve = CurveFactory.CreateRectangleWithRoundedCorners(1.2 * w, 1.2 * h, 3, 3, new Point()); } return(drawingGraph); }
/// <summary> /// Apply the appropriate layout to the specified cluster /// </summary> /// <param name="cluster">the root of the cluster hierarchy to lay out</param> /// <returns>list of edges external to the cluster</returns> void LayoutCluster(Cluster cluster) { ProgressStep(); cluster.UnsetInitialLayoutState(); FastIncrementalLayoutSettings settings = null; LayoutAlgorithmSettings s = clusterSettings(cluster); Directions layoutDirection = Directions.None; if (s is SugiyamaLayoutSettings) { var ss = s as SugiyamaLayoutSettings; settings = ss.FallbackLayoutSettings != null ? new FastIncrementalLayoutSettings((FastIncrementalLayoutSettings)ss.FallbackLayoutSettings) : new FastIncrementalLayoutSettings(); layoutDirection = LayeredLayoutEngine.GetLayoutDirection(ss); } else { settings = new FastIncrementalLayoutSettings((FastIncrementalLayoutSettings)s); } settings.ApplyForces = true; settings.MinorIterations = 10; settings.AvoidOverlaps = true; settings.InterComponentForces = false; settings.IdealEdgeLength = new IdealEdgeLengthSettings { EdgeDirectionConstraints = layoutDirection, ConstrainedEdgeSeparation = 30 }; settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline; HashSet <Node> addedNodes; if (addedNodesByCluster.TryGetValue(cluster, out addedNodes)) { // if the structure of the cluster has changed then we apply unconstrained layout first, // then introduce structural constraints, and then all constraints settings.MinConstraintLevel = 0; settings.MaxConstraintLevel = 2; } else { settings.MinConstraintLevel = 2; } GeometryGraph newGraph = GetShallowCopyGraphUnderCluster(cluster); LayoutAlgorithmHelpers.ComputeDesiredEdgeLengths(settings.IdealEdgeLength, newGraph); // orthogonal ordering constraints preserve the left-of, above-of relationships between existing nodes // (we do not apply these to the newly added nodes) GenerateOrthogonalOrderingConstraints( newGraph.Nodes.Where(v => !addedNodes.Contains(v.UserData as Node)).ToList(), settings); LayoutComponent(newGraph, settings); //LayoutAlgorithmSettings.ShowGraph(newGraph); InitialLayoutByCluster.FixOriginalGraph(newGraph, true); cluster.UpdateBoundary(newGraph.BoundingBox); }
public static void Layout(GeometryGraph graph) { foreach (Node n in graph.Nodes) { n.BoundaryCurve = CurveFactory.CreateEllipse(20.0, 10.0, new Point()); } foreach (Cluster c in graph.RootCluster.AllClustersDepthFirst()) { c.BoundaryCurve = c.BoundingBox.Perimeter(); } var settings = new FastIncrementalLayoutSettings(); settings.AvoidOverlaps = true; settings.NodeSeparation = 30; settings.RouteEdges = true; LayoutHelpers.CalculateLayout(graph, settings, new CancelToken()); foreach (Cluster c in graph.RootCluster.AllClustersDepthFirst()) { c.BoundaryCurve = c.BoundingBox.Perimeter(); } var bundlingsettings = new BundlingSettings() { EdgeSeparation = 5, CreateUnderlyingPolyline = true }; var router = new SplineRouter(graph, 10.0, 1.25, Math.PI / 6.0, bundlingsettings); router.Run(); graph.UpdateBoundingBox(); }
public void CalculateLayout_ReportsAllProgress() { GeometryGraph treeGraph = GraphGenerator.GenerateTree(20); var settings = new FastIncrementalLayoutSettings(); InitialLayout layout = new InitialLayout(treeGraph, settings); double progress = 0.0; EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete; try { layout.ProgressChanged += handler; layout.Run(); } finally { layout.ProgressChanged -= handler; } Assert.AreEqual(0, treeGraph.BoundingBox.Bottom); Assert.AreEqual(0, treeGraph.BoundingBox.Left); foreach (var v in treeGraph.Nodes) { Assert.IsTrue(treeGraph.BoundingBox.Contains(v.BoundingBox)); } Assert.AreEqual(1.0, progress, "Progress was never reported as 100%. Last update was at " + progress + "%"); }
internal void LayoutComponent(GeometryGraph component, FastIncrementalLayoutSettings settings) { // for small graphs (below 100 nodes) do extra iterations settings.MaxIterations = LayoutAlgorithmHelpers.NegativeLinearInterpolation( component.Nodes.Count, /*lowerThreshold:*/ 50, /*upperThreshold:*/ 500, /*minIterations:*/ 3, /*maxIterations:*/ 5); settings.MinorIterations = LayoutAlgorithmHelpers.NegativeLinearInterpolation(component.Nodes.Count, /*lowerThreshold:*/ 50, /*upperThreshold:*/ 500, /*minIterations:*/ 2, /*maxIterations:*/ 10); FastIncrementalLayout fil = new FastIncrementalLayout(component, settings, settings.MinConstraintLevel, anyCluster => settings); Debug.Assert(settings.Iterations == 0); foreach (var level in Enumerable.Range(settings.MinConstraintLevel, settings.MaxConstraintLevel + 1)) { if (level != fil.CurrentConstraintLevel) { fil.CurrentConstraintLevel = level; if (level == 2) { settings.MinorIterations = 1; settings.ApplyForces = false; } } do { fil.Run(); } while (!settings.IsDone); } // Pad the graph with margins so the packing will be spaced out. component.Margins = settings.ClusterMargin; component.UpdateBoundingBox(); }
void ForceDirectedLayout(FastIncrementalLayoutSettings settings, GeometryGraph component) { LayoutAlgorithmHelpers.ComputeDesiredEdgeLengths(settings.IdealEdgeLength, component); var layout = new InitialLayout(component, settings) { SingleComponent = true }; layout.Run(this.CancelToken); InitialLayoutHelpers.RouteEdges(component, settings, this.CancelToken); InitialLayoutHelpers.PlaceLabels(component, this.CancelToken); InitialLayoutHelpers.FixBoundingBox(component, settings); }
public override void Initialize() { EnableDebugViewer(); base.Initialize(); graph = GraphGenerator.GenerateOneSimpleGraph(); GraphGenerator.SetRandomNodeShapes(graph, random); allNodes = graph.Nodes.ToList(); settings = new FastIncrementalLayoutSettings(); settings.AvoidOverlaps = true; }
/// <summary> /// /// Non-overlap between nodes in the same cluster (or the root cluster), between the convex hulls /// of clusters and nodes that do belong to those clusters and between clusters and clusters. /// </summary> /// <param name="cluster"></param> /// <param name="settings">for padding extra space around nodes</param> public AllPairsNonOverlappingBoundaries(Cluster cluster, FastIncrementalLayoutSettings settings) { foreach (var v in cluster.nodes) { hulls.Add(new RCHull(null, v, settings.NodeSeparation)); } foreach (var c in cluster.clusters) { traverseClusters(null, c, settings.NodeSeparation); } }
static void MoveN0ToTheLeft(Node n0, GeometryGraph graph, FastIncrementalLayoutSettings settings) { n0.Center += new Point(-10, 0); LockPosition lockPosition = settings.CreateLock(n0, n0.BoundingBox); settings.IncrementalRun(graph); RouteEdges(graph, settings); //LayoutAlgorithmSettings.ShowGraph(graph); settings.ClearLocks(); settings.RemoveLock(lockPosition); }
/// <summary> /// Static layout of graph by gradually adding constraints. /// Uses PivotMds to find initial layout. /// Breaks the graph into connected components (nodes in the same cluster are considered /// connected whether or not there is an edge between them), then lays out each component /// individually. Finally, a simple packing is applied. /// ratio as close as possible to the PackingAspectRatio property (not currently used). /// </summary> public InitialLayout(GeometryGraph graph, FastIncrementalLayoutSettings settings) { ValidateArg.IsNotNull(graph, "graph"); ValidateArg.IsNotNull(settings, "settings"); this.graph = graph; this.settings = new FastIncrementalLayoutSettings(settings); this.settings.ApplyForces = true; this.settings.InterComponentForces = true; this.settings.RungeKuttaIntegration = false; this.settings.RespectEdgePorts = false; }
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 + "%"); }
protected LayoutAlgorithmSettings GetLayoutSettings(string layoutMethod) { switch (layoutMethod) { case "MDS": return(new MdsLayoutSettings()); case "Ranking": return(new RankingLayoutSettings()); case "Incremental": return(FastIncrementalLayoutSettings.CreateFastIncrementalLayoutSettings()); default: return(new SugiyamaLayoutSettings()); } }
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"); } }
static void RouteEdges(GeometryGraph graph, FastIncrementalLayoutSettings settings) { if (graph.Edges.Count < 1000) { var router = new SplineRouter(graph, settings.EdgeRoutingSettings.Padding, settings.EdgeRoutingSettings.PolylinePadding, settings.EdgeRoutingSettings.ConeAngle, settings.EdgeRoutingSettings.BundlingSettings); router.Run(); } else { var sr = new StraightLineEdges(graph.Edges, 1); sr.Run(); } }
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 FillClustersAndSettings(FastIncrementalLayoutSettings settings, GeometryGraph geometryGraph) { settings.AvoidOverlaps = true; // settings.RectangularClusters = true; var root = new Cluster(); var cluster = new Cluster(); root.AddChild(cluster); for (int i = 0; i < 4; i++) { var istring = i.ToString(); cluster.AddChild(geometryGraph.Nodes.First(n => n.UserData.ToString() == istring)); } cluster.BoundaryCurve = cluster.BoundingBox.Perimeter(); cluster = new Cluster(); root.AddChild(cluster); geometryGraph.RootCluster.AddChild(root); //make a subcluster var parent = cluster; cluster = new Cluster(); cluster.AddChild(geometryGraph.Nodes.First(n => n.UserData.ToString() == "4")); cluster.AddChild(geometryGraph.Nodes.First(n => n.UserData.ToString() == "5")); parent.AddChild(cluster); cluster = new Cluster(); for (int i = 6; i < 9; i++) { var istring = i.ToString(); cluster.AddChild(geometryGraph.Nodes.First(n => n.UserData.ToString() == istring)); } parent.AddChild(cluster); foreach (var cl in geometryGraph.RootCluster.AllClustersDepthFirst()) { if (cl.BoundaryCurve == null) { cl.BoundaryCurve = cl.BoundingBox.Perimeter(); } } }
static void FillClustersAndSettings(FastIncrementalLayoutSettings settings, GeometryGraph geometryGraph) { settings.AvoidOverlaps = true; // settings.RectangularClusters = true; var root = new Cluster(); var cluster = new Cluster(); root.AddChild(cluster); for (int i = 0; i < 4; i++) { cluster.AddChild(FindNode(geometryGraph, i)); } cluster.BoundaryCurve = cluster.BoundingBox.Perimeter(); cluster = new Cluster(); root.AddChild(cluster); geometryGraph.RootCluster.AddChild(root); //make a subcluster var parent = cluster; cluster = new Cluster(); cluster.AddChild(FindNode(geometryGraph, 4)); cluster.AddChild(FindNode(geometryGraph, 5)); parent.AddChild(cluster); cluster = new Cluster(); for (int i = 6; i < 9; i++) { cluster.AddChild(FindNode(geometryGraph, i)); } parent.AddChild(cluster); foreach (var cl in geometryGraph.RootCluster.AllClustersDepthFirst()) { if (cl.BoundaryCurve == null) { cl.BoundaryCurve = cl.BoundingBox.Perimeter(); } } SetupDisplayNodeIds(geometryGraph); }
static void TestFD() { GeometryGraph graph = CreateGeometryGraphForFD(); //LayoutAlgorithmSettings.ShowGraph(graph); var settings = new FastIncrementalLayoutSettings { AvoidOverlaps = true, ApplyForces = false, RungeKuttaIntegration = true }; var ir = new InitialLayout(graph, settings); ir.Run(); RouteEdges(graph, settings); //LayoutAlgorithmSettings.ShowGraph(graph); // AddNodeFd(graph); var n = new Node(CurveFactory.CreateDiamond(200, 200, new Point(350, 230))); var e = new Edge(n, graph.Nodes[42]); graph.Edges.Add(e); e = new Edge(n, graph.Nodes[6]); graph.Edges.Add(e); e = new Edge(n, graph.Nodes[12]); graph.Edges.Add(e); graph.Nodes.Add(n); graph.RootCluster.AddChild(n); settings.algorithm = new FastIncrementalLayout(graph, settings, settings.MaxConstraintLevel, f => settings); settings.Unconverge(); settings.CreateLock(n, new Rectangle(200, 400, 500, 100)); do { settings.IncrementalRun(graph); } while (!settings.Converged); RouteEdges(graph, settings); #if TEST_MSAGL LayoutAlgorithmSettings.ShowGraph(graph); #endif Environment.Exit(0); }
private static void LayoutAndValidate(GeometryGraph graph, double separationRatio, ISet <Node> validationExcludedNodes) { const double downwardEdgeSeparation = 70; FastIncrementalLayoutSettings settings = new FastIncrementalLayoutSettings(); settings.IdealEdgeLength = new IdealEdgeLengthSettings { ConstrainedEdgeSeparation = downwardEdgeSeparation, EdgeDirectionConstraints = Directions.South }; settings.AvoidOverlaps = true; InitialLayout initialLayout = new InitialLayout(graph, settings); initialLayout.Run(); ShowGraphInDebugViewer(graph); ValidateDownwardEdgeConstraints(graph, downwardEdgeSeparation, validationExcludedNodes); }
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(); } }
void GenerateOrthogonalOrderingConstraints(IEnumerable <Node> nodes, FastIncrementalLayoutSettings settings) { Node p = null; foreach (var v in graph.Nodes.OrderBy(v => v.Center.X)) { if (p != null) { settings.AddStructuralConstraint(new HorizontalSeparationConstraint(p, v, 0.1)); } p = v; } p = null; foreach (var v in graph.Nodes.OrderBy(v => v.Center.Y)) { if (p != null) { settings.AddStructuralConstraint(new VerticalSeparationConstraint(p, v, 0.1)); } p = v; } }
static void Main(string[] args) { #if TEST_MSAGL DisplayGeometryGraph.SetShowFunctions(); #endif ArgsParser.ArgsParser argsParser = SetArgsParser(args); if (argsParser.OptionIsUsed("-help")) { Console.WriteLine(argsParser.UsageString()); Environment.Exit(0); } if (argsParser.OptionIsUsed(PolygonDistanceTestOption)) { TestPolygonDistance(); } else if (argsParser.OptionIsUsed(TestCdtThreaderOption)) { TestCdtThreader(); } else if (argsParser.OptionIsUsed(RandomBundlingTest)) { RandomBundlingTests.RsmContent(); } bundling = argsParser.OptionIsUsed(BundlingOption); var gviewer = new GViewer(); gviewer.MouseMove += Draw.GviewerMouseMove; if (argsParser.OptionIsUsed(FdOption)) { TestFD(); gviewer.CurrentLayoutMethod = LayoutMethod.IcrementalLayout; } Form form = CreateForm(null, gviewer); if (argsParser.OptionIsUsed(AsyncLayoutOption)) { gviewer.AsyncLayout = true; } string listOfFilesFile = argsParser.GetStringOptionValue(ListOfFilesOption); if (listOfFilesFile != null) { ProcessListOfFiles(listOfFilesFile, argsParser); return; } string fileName = argsParser.GetStringOptionValue(FileOption); string ext = Path.GetExtension(fileName); if (ext != null) { ext = ext.ToLower(); if (ext == ".dot") { ProcessDotFile(gviewer, argsParser, fileName); } else { if (ext == ".geom") { GeometryGraph geometryGraph = GeometryGraphReader.CreateFromFile(fileName); geometryGraph.Margins = 10; FixHookPorts(geometryGraph); // if (argsParser.OptionIsUsed(BundlingOption)) { for (int i = 0; i < 1; i++) { #if TEST_MSAGL /*DisplayGeometryGraph.ShowGraph(geometryGraph); * var l = new List<DebugCurve>(); l.AddRange(geometryGraph.Nodes.Select(n=>new DebugCurve(100,1,"black",n.BoundaryCurve))); * l.AddRange(geometryGraph.Edges.Select(e=>new DebugCurve(100,1,"black", new LineSegment(e.Source.Center,e.Target.Center)))); * foreach (var cl in geometryGraph.RootCluster.AllClustersDepthFirst()) { * l.Add(new DebugCurve(100,2,"blue",cl.BoundaryCurve)); * foreach (var node in cl.Nodes) * l.Add(new DebugCurve(100, 2, "brown", node.BoundaryCurve)); * * foreach (var e in cl.Edges) * l.Add(new DebugCurve(100, 2, "pink", new LineSegment(e.Source.Center, e.Target.Center))); * * } * * DisplayGeometryGraph.ShowDebugCurves(l.ToArray());*/ #endif BundlingSettings bs = GetBundlingSettings(argsParser); double loosePadding; double tightPadding = GetPaddings(argsParser, out loosePadding); if (argsParser.OptionIsUsed(MdsOption)) { var mdsLayoutSettings = new MdsLayoutSettings { RemoveOverlaps = true, NodeSeparation = loosePadding * 3 }; var mdsLayout = new MdsGraphLayout(mdsLayoutSettings, geometryGraph); mdsLayout.Run(); } else { if (argsParser.OptionIsUsed(FdOption)) { var settings = new FastIncrementalLayoutSettings { AvoidOverlaps = true }; (new InitialLayout(geometryGraph, settings)).Run(); } } var splineRouter = new SplineRouter(geometryGraph, geometryGraph.Edges, tightPadding, loosePadding, Math.PI / 6, bs); splineRouter.Run(); } #if TEST_MSAGL DisplayGeometryGraph.ShowGraph(geometryGraph); #endif return; } else { if (ext == ".msagl") { Graph graph = Graph.Read(fileName); // DisplayGeometryGraph.ShowGraph(graph.GeometryGraph); if (graph != null) { if (argsParser.OptionIsUsed(BundlingOption)) { BundlingSettings bs = GetBundlingSettings(argsParser); double loosePadding; double tightPadding = GetPaddings(argsParser, out loosePadding); var br = new SplineRouter(graph.GeometryGraph, tightPadding, loosePadding, Math.PI / 6, bs); br.Run(); // DisplayGeometryGraph.ShowGraph(graph.GeometryGraph); } } gviewer.NeedToCalculateLayout = false; gviewer.Graph = graph; gviewer.NeedToCalculateLayout = true; } } } } else if (argsParser.OptionIsUsed(TestCdtOption)) { Triangulation(argsParser.OptionIsUsed(ReverseXOption)); Environment.Exit(0); } else if (argsParser.OptionIsUsed(TestCdtOption0)) { TestTriangulationOnSmallGraph(argsParser); Environment.Exit(0); } else if (argsParser.OptionIsUsed(TestCdtOption2)) { TestTriangulationOnPolys(); Environment.Exit(0); } else if (argsParser.OptionIsUsed(TestCdtOption1)) { ThreadThroughCdt(); Environment.Exit(0); } else if (argsParser.OptionIsUsed(ConstraintsTestOption)) { TestGraphWithConstraints(); } if (!argsParser.OptionIsUsed(QuietOption)) { Application.Run(form); } }
protected override void OnValueChanged(ModelRoot element, LayoutAlgorithm oldValue, LayoutAlgorithm newValue) { base.OnValueChanged(element, oldValue, newValue); if (!element.Store.InUndoRedoOrRollback) { // if this is the first time we've been here, cache what's alread there if (oldValue != LayoutAlgorithm.Default && !settingsCache.ContainsKey(oldValue) && element.LayoutAlgorithmSettings != null) { settingsCache[oldValue] = element.LayoutAlgorithmSettings; } // use the prior settings for this layout type if available if (newValue != LayoutAlgorithm.Default && settingsCache.ContainsKey(newValue)) { element.LayoutAlgorithmSettings = settingsCache[newValue]; } else { // if not, set some defaults that make sense in our context switch (newValue) { case LayoutAlgorithm.Default: element.LayoutAlgorithmSettings = null; return; case LayoutAlgorithm.FastIncremental: FastIncrementalLayoutSettings fastIncrementalLayoutSettings = new FastIncrementalLayoutSettings(); element.LayoutAlgorithmSettings = fastIncrementalLayoutSettings; break; case LayoutAlgorithm.MDS: MdsLayoutSettings mdsLayoutSettings = new MdsLayoutSettings(); mdsLayoutSettings.ScaleX = 1; mdsLayoutSettings.ScaleY = 1; mdsLayoutSettings.AdjustScale = true; mdsLayoutSettings.RemoveOverlaps = true; element.LayoutAlgorithmSettings = mdsLayoutSettings; break; case LayoutAlgorithm.Ranking: RankingLayoutSettings rankingLayoutSettings = new RankingLayoutSettings(); rankingLayoutSettings.ScaleX = 1; rankingLayoutSettings.ScaleY = 1; element.LayoutAlgorithmSettings = rankingLayoutSettings; break; case LayoutAlgorithm.Sugiyama: SugiyamaLayoutSettings sugiyamaLayoutSettings = new SugiyamaLayoutSettings { LayerSeparation = 1, MinNodeHeight = 1, MinNodeWidth = 1 }; element.LayoutAlgorithmSettings = sugiyamaLayoutSettings; break; } element.LayoutAlgorithmSettings.ClusterMargin = 1; element.LayoutAlgorithmSettings.NodeSeparation = 1; element.LayoutAlgorithmSettings.EdgeRoutingSettings.Padding = .3; element.LayoutAlgorithmSettings.EdgeRoutingSettings.PolylinePadding = 1.5; element.LayoutAlgorithmSettings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.StraightLine; settingsCache[newValue] = element.LayoutAlgorithmSettings; } } }
//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(); }
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 }
private void Layout(bool repositionateAll) { if (settings != null && repositionateAll) { settings.ClearLocks(); return; } if (cancelToken != null) { cancelToken.Canceled = true; } try { var scenes = Controller.Instance.ChapterList.getSelectedChapterDataControl().getScenesList(); // Layout algorithm settings = new Microsoft.Msagl.Layout.Incremental.FastIncrementalLayoutSettings { EdgeRoutingSettings = new EdgeRoutingSettings { EdgeRoutingMode = EdgeRoutingMode.StraightLine, Padding = 10 }, AvoidOverlaps = true, ApplyForces = false, RungeKuttaIntegration = true, NodeSeparation = 10, PackingMethod = PackingMethod.Compact }; var canvasRect = new Rect(0, 0, SPACE_WIDTH, SPACE_HEIGHT); // Graph graph = new GeometryGraph { BoundingBox = new Microsoft.Msagl.Core.Geometry.Rectangle(0, 0, SPACE_WIDTH, SPACE_HEIGHT) }; sceneToNode = new Dictionary <SceneDataControl, Node>(); sceneLockPositions = new Dictionary <SceneDataControl, LockPosition>(); var present = new Dictionary <Tuple <Node, Node>, bool>(); foreach (var scene in scenes.getScenes()) { sizes.Remove(scene.getPreviewBackground()); var rect = ToGraphRect(GetSceneRect(scene, true), canvasRect, graph.BoundingBox); var node = new Node(CurveFactory.CreateRectangle(rect), scene.getId()); /*if (!repositionateAll && rect.LeftBottom != new Point(0,0)) * { * sceneLockPositions.Add(scene, settings.CreateLock(node, rect)); * }*/ graph.Nodes.Add(node); graph.RootCluster.AddChild(node); sceneToNode.Add(scene, node); } foreach (var scene in scenes.getScenes()) { var node = sceneToNode[scene]; foreach (var exit in scene.getExitsList().getExits()) { var index = scenes.getSceneIndexByID(exit.getNextSceneId()); // If the exit points to a cutscene it normally is out of the array if (index < 0 || index >= scenes.getScenes().Count) { continue; } var nextScene = scenes.getScenes()[index]; var t = new Tuple <Node, Node>(node, sceneToNode[nextScene]); if (!present.ContainsKey(t)) { present.Add(t, true); graph.Edges.Add(new Edge(node, sceneToNode[nextScene])); var exitOrigin = GetExitArea(scene, exit, true).ToRect().center; var originRect = GetSceneRect(scene, true); var pos = exitOrigin - originRect.position; pos.x = Mathf.Clamp01(pos.x / originRect.width); pos.y = Mathf.Clamp01(pos.y / originRect.height); // Positioning constraints /*if (pos.x < 0.3) * { * settings.AddStructuralConstraint(new LeftRightConstraint(t.Item2, t.Item1)); * } * if (pos.x > 0.7) * { * settings.AddStructuralConstraint(new LeftRightConstraint(t.Item1, t.Item2)); * }*/ } } } var ir = new InitialLayout(graph, settings); ir.Run(); // Do the layouting UpdatePositions(); } catch (Exception ex) { Debug.LogError(ex.Message + " : " + ex.StackTrace); } }