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); } }
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."); }
public void ConstraintWithTransformation() { Random random = new Random(999); GeometryGraph graph = GraphGenerator.GenerateOneSimpleGraph(); GraphGenerator.SetRandomNodeShapes(graph, random); SugiyamaLayoutSettings settings = new SugiyamaLayoutSettings(); //layer direction to be left to right settings.Transformation = PlaneTransformation.Rotation(Math.PI / 2); List <Node> nodes = graph.Nodes.ToList(); settings.AddUpDownConstraint(nodes[0], nodes[1]); settings.AddLeftRightConstraint(nodes[3], nodes[4]); settings.AddUpDownVerticalConstraint(nodes[0], nodes[3]); settings.AddSameLayerNeighbors(nodes[2], nodes[4]); LayeredLayout layeredLayout = new LayeredLayout(graph, settings); layeredLayout.Run(); ShowGraphInDebugViewer(graph); SugiyamaValidation.ValidateUpDownConstraint(nodes[0], nodes[1]); SugiyamaValidation.ValidateLeftRightConstraint(nodes[3], nodes[4]); SugiyamaValidation.ValidateUpDownVerticalConstraint(nodes[0], nodes[3]); SugiyamaValidation.ValidateNeighborConstraint(graph, nodes[2], nodes[4], settings); }
private static void LayoutAndValidate(GeometryGraph graph, SugiyamaLayoutSettings settings, double nodeSeparation, double layerSeparation, LayerDirection direction) { settings.NodeSeparation = nodeSeparation; switch (direction) { case LayerDirection.None: case LayerDirection.TopToBottom: break; case LayerDirection.BottomToTop: settings.Transformation = PlaneTransformation.Rotation(Math.PI); break; case LayerDirection.LeftToRight: settings.Transformation = PlaneTransformation.Rotation(Math.PI / 2); break; case LayerDirection.RightToLeft: settings.Transformation = PlaneTransformation.Rotation(-Math.PI / 2); break; } settings.LayerSeparation = layerSeparation; LayeredLayout layeredLayout = new LayeredLayout(graph, settings); layeredLayout.Run(); ShowGraphInDebugViewer(graph); // SugiyamaValidation.ValidateGraph(graph, settings); }
public void RandomDotFileTests() { int line, column; string msg; string fileName = Path.Combine(this.TestContext.TestDir, "Out\\Dots\\fsm.dot"); Drawing.Graph drawGraph = Parser.Parse(fileName, out line, out column, out msg); drawGraph.CreateGeometryGraph(); GeometryGraph graph = drawGraph.GeometryGraph; GraphGenerator.SetRandomNodeShapes(graph, random); LayeredLayout layeredLayout = new LayeredLayout(graph, new SugiyamaLayoutSettings() { BrandesThreshold = 1 }); layeredLayout.Run(); string[] allFiles = Directory.GetFiles(Path.Combine(this.TestContext.TestDir, "Out\\Dots"), "*.dot"); List <int> selected = new List <int>(); for (int i = 0; i < 10; i++) { int next = random.Next(allFiles.Length); while (selected.Contains(next)) { next = random.Next(allFiles.Length); } selected.Add(next); WriteLine("Now handling dot file: " + allFiles[next]); drawGraph = Parser.Parse(allFiles[next], out line, out column, out msg); drawGraph.CreateGeometryGraph(); graph = drawGraph.GeometryGraph; GraphGenerator.SetRandomNodeShapes(graph, random); LayerDirection direction = LayerDirection.None; switch (i % 4) { case 0: direction = LayerDirection.TopToBottom; break; case 1: direction = LayerDirection.BottomToTop; break; case 2: direction = LayerDirection.LeftToRight; break; case 3: direction = LayerDirection.RightToLeft; break; } LayoutAndValidate(graph, (SugiyamaLayoutSettings)drawGraph.LayoutAlgorithmSettings, direction); } }
internal void RecalculateLayout() { var settings = new SugiyamaLayoutSettings { Transformation = PlaneTransformation.Rotation(Math.PI / 2), EdgeRoutingSettings = { EdgeRoutingMode = EdgeRoutingMode.Spline } }; var layout = new LayeredLayout(graph, settings); layout.Run(); }
public void Layout(NetworkViewModel network) { if (network == null || network.Nodes.Count <= 0) { return; } GeometryGraph graph = new GeometryGraph(); Dictionary <NodeViewModel, Microsoft.Msagl.Core.Layout.Node> layoutLookup = new Dictionary <NodeViewModel, Microsoft.Msagl.Core.Layout.Node>(); const double nodeWidth = 230; const double nodeHeight = 100; const double spacingHorizontal = 90; const double spacingVertical = 60; // build collection of all nodes foreach (NodeViewModel node in network.Nodes.Items) { ICurve box = CurveFactory.CreateRectangle(nodeWidth, nodeHeight, new Microsoft.Msagl.Core.Geometry.Point()); Microsoft.Msagl.Core.Layout.Node layoutNode = new Microsoft.Msagl.Core.Layout.Node(box) { UserData = node }; layoutLookup.Add(node, layoutNode); graph.Nodes.Add(layoutNode); } foreach (ConnectionViewModel items in network.Connections.Items) { Microsoft.Msagl.Core.Layout.Node inNode = layoutLookup[items.Input.Parent]; Microsoft.Msagl.Core.Layout.Node outNode = layoutLookup[items.Output.Parent]; Edge edge = new Edge(inNode, outNode); graph.Edges.Add(edge); } // perform layout operation SugiyamaLayoutSettings settings = new SugiyamaLayoutSettings { Transformation = PlaneTransformation.Rotation(-90 * (Math.PI / 180)), // left to right NodeSeparation = spacingHorizontal, LayerSeparation = spacingVertical, }; LayeredLayout layeredLayout = new LayeredLayout(graph, settings); layeredLayout.Run(); // apply the node positions to the real graph foreach (KeyValuePair <NodeViewModel, Microsoft.Msagl.Core.Layout.Node> node in layoutLookup) { node.Key.Position = new Point(node.Value.BoundingBox.Center.X, node.Value.BoundingBox.Center.Y); } }
private void RunLayout() { var settings = new SugiyamaLayoutSettings { Transformation = PlaneTransformation.Rotation(Math.PI / 2), EdgeRoutingSettings = { EdgeRoutingMode = mode }, }; var layout = new LayeredLayout(graph, settings); layout.Run(); }
public void GraphLayout() { var graphAdapter = new MsaglGraphAdapter(state); var settings = new SugiyamaLayoutSettings() { Transformation = PlaneTransformation.Rotation(3.0 * Math.PI / 2.0), NodeSeparation = 10.0 }; var layout = new LayeredLayout(graphAdapter.resultGraph, settings); layout.Run(); var minPosition = new Vector2(float.MaxValue, float.MaxValue); foreach (var node in graphAdapter.resultGraph.Nodes) { var position = node.BoundingBox.LeftBottom; if (position.X < minPosition.x) { minPosition.x = (float)position.X; } if (position.Y < minPosition.y) { minPosition.y = (float)position.Y; } } foreach (var node in graphAdapter.resultGraph.Nodes) { var view = (SystemViewData)node.UserData; var vector = new Vector2(Mathf.Round((float)node.BoundingBox.Left), Mathf.Round((float)node.BoundingBox.Bottom)); view.position.position = vector - minPosition + kWindowOffset; } state.edges.Clear(); foreach (var edge in graphAdapter.resultGraph.Edges) { var systemEdge = new SystemGraphEdge(); foreach (var point in edge.EdgeGeometry.SmoothedPolyline) { var vector = new Vector2((float)point.X, (float)point.Y); systemEdge.points.Add(vector - minPosition + kWindowOffset); } systemEdge.target = state.systemViews.IndexOf((SystemViewData)edge.Target.UserData); systemEdge.points[systemEdge.points.Count - 1] = ExteriorPointFromOtherPoint(state.systemViews[systemEdge.target].position, systemEdge.points[systemEdge.points.Count - 2]); state.edges.Add(systemEdge); } }
public void CalculateLayout(GeometryGraph geometryGraph) { var geomGraphComponents = GraphConnectedComponents.CreateComponents(geometryGraph.Nodes, geometryGraph.Edges); var settings = LayoutAlgorithmSettings as SugiyamaLayoutSettings; foreach (var components in geomGraphComponents) { var layout = new LayeredLayout(components, settings); components.Margins = 100; layout.Run(); } Microsoft.Msagl.Layout.MDS.MdsGraphLayout.PackGraphs(geomGraphComponents, settings); geometryGraph.UpdateBoundingBox(); }
public void SelfEdge() { var g = new GeometryGraph(); var n = SetNode(g, "a", 10, 10); var e = new Edge(n, n); g.Edges.Add(e); var l = new LayeredLayout(g, new SugiyamaLayoutSettings()); l.Run(); g.Translate(-n.Center); var sr = new SplineRouter(g, 2, 4, Math.PI / 6); sr.Run(); }
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); }
void LayeredLayout(SugiyamaLayoutSettings layeredSettings, GeometryGraph component) { var layeredLayout = new LayeredLayout(component, layeredSettings); layeredLayout.SetCancelToken(this.CancelToken); double aspectRatio = layeredLayout.EstimateAspectRatio(); double edgeDensity = (double)component.Edges.Count / component.Nodes.Count; // if the estimated aspect ratio is not in the range below then we fall back to force directed layout // with constraints which is both faster and usually returns a better aspect ratio for largish graphs var fallbackLayoutSettings = layeredSettings.FallbackLayoutSettings; if (fallbackLayoutSettings != null && (component.Nodes.Count > 50 && edgeDensity > 2 || // too dense component.Nodes.Count > 40 && edgeDensity > 3.0 || // too dense component.Nodes.Count > 30 && edgeDensity > 4.0 || // too dense component.Nodes.Count > 30 && aspectRatio > layeredSettings.MaxAspectRatioEccentricity || // too wide component.Nodes.Count > 30 && aspectRatio < 1d / layeredSettings.MaxAspectRatioEccentricity // too high )) { // for large graphs there's really no point trying to produce nice edge routes // the sugiyama edge routing can be quite circuitous on large graphs anyway var prevEdgeRouting = fallbackLayoutSettings.EdgeRoutingSettings.EdgeRoutingMode; if (component.Nodes.Count > 100 && edgeDensity > 2.0) { fallbackLayoutSettings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.StraightLine; } LayoutComponent(fallbackLayoutSettings, component); fallbackLayoutSettings.EdgeRoutingSettings.EdgeRoutingMode = prevEdgeRouting; } else { var prevEdgeRouting = layeredSettings.EdgeRoutingSettings.EdgeRoutingMode; // for large graphs there's really no point trying to produce nice edge routes // the sugiyama edge routing can be quite circuitous on large graphs anyway if (component.Nodes.Count > 100 && edgeDensity > 2.0) { layeredSettings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.StraightLine; } layeredLayout.Run(this.CancelToken); layeredSettings.EdgeRoutingSettings.EdgeRoutingMode = prevEdgeRouting; InitialLayoutHelpers.FixBoundingBox(component, layeredSettings); } //LayoutAlgorithmSettings.ShowGraph(component); }
public void CanDrawGeometryGraph() { Graph graph = new Graph(); GeometryGraph ge = new GeometryGraph(); graph.GeometryGraph = ge; SugiyamaLayoutSettings sugiyamaSettings = new SugiyamaLayoutSettings { Transformation = PlaneTransformation.Rotation(Math.PI / 2), EdgeRoutingSettings = { EdgeRoutingMode = EdgeRoutingMode.Spline }, MinNodeHeight = 10, MinNodeWidth = 20, }; sugiyamaSettings.NodeSeparation *= 2; graph.LayoutAlgorithmSettings = sugiyamaSettings; graph.AddNode("A"); graph.AddNode("B"); graph.AddNode("C"); graph.AddNode("D"); graph.AddEdge("A", "B"); foreach (Node n in graph.Nodes) { graph.GeometryGraph.Nodes.Add(new GeometryNode(CurveFactory.CreateRectangle(20, 10, new GeometryPoint()), n)); } foreach (Edge e in graph.Edges) { GeometryNode source = graph.FindGeometryNode(e.SourceNode.Id); GeometryNode target = graph.FindGeometryNode(e.TargetNode.Id); graph.GeometryGraph.Edges.Add(new GeometryEdge(source, target)); } ge.UpdateBoundingBox(); graph.GeometryGraph = ge; using (Bitmap bmp = new Bitmap(400, 400, PixelFormat.Format32bppPArgb)) using (Graphics g = Graphics.FromImage(bmp)) { g.Clear(System.DrawingCore.Color.White); Rectangle rect = new Rectangle(0, 0, 400, 400); //GdiUtils.SetGraphTransform(graph, rect, g); LayeredLayout layout = new LayeredLayout(graph.GeometryGraph, sugiyamaSettings); layout.Run(); GdiUtils.DrawFromGraph(rect, graph.GeometryGraph, g); bmp.Save("graph.bmp", ImageFormat.Bmp); } }
static internal 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); }
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); }
private void RunLayout() { settings = settings ?? new SugiyamaLayoutSettings { Transformation = PlaneTransformation.Rotation(0 * Math.PI / 2), PackingMethod = PackingMethod.Columns, EdgeRoutingSettings = { Padding = 100, }, GroupSplit = 10, }; settings.EdgeRoutingSettings.EdgeRoutingMode = mode; var layout = new LayeredLayout(graph, settings); layout.Run(); }
public override void AfterVisitTree() { LayoutSettings = new SugiyamaLayoutSettings { Transformation = PlaneTransformation.Rotation(System.Math.PI), EdgeRoutingSettings = { EdgeRoutingMode = EdgeRoutingMode.Spline }, MinNodeHeight = 10, MinNodeWidth = 20, }; //LayoutSettings.NodeSeparation *= 2; Graph.LayoutAlgorithmSettings = LayoutSettings; foreach (Node n in Graph.Nodes) { Graph.GeometryGraph.Nodes.Add( new GeometryNode(CurveFactory.CreateRectangle(20, 10, new GeometryPoint()), n)); } foreach (Edge e in Graph.Edges) { GeometryNode source = Graph.FindGeometryNode(e.SourceNode.Id); GeometryNode target = Graph.FindGeometryNode(e.TargetNode.Id); Graph.GeometryGraph.Edges.Add(new GeometryEdge(source, target)); } Graph.GeometryGraph.UpdateBoundingBox(); using (Bitmap bmp = new Bitmap(1200, 1200, PixelFormat.Format32bppPArgb)) using (Graphics g = Graphics.FromImage(bmp)) { Rectangle rect = new Rectangle(0, 0, 1200, 1200); g.Clear(System.Drawing.Color.White); GraphDiagramUtil.SetGraphTransform(Graph.GeometryGraph, rect, g); LayeredLayout layout = new LayeredLayout(Graph.GeometryGraph, LayoutSettings); layout.Run(); GraphDiagramUtil.DrawFromGraph(rect, Graph.GeometryGraph, g); bmp.Save("graph.bmp", ImageFormat.Bmp); } }
public void LabelsNearEdges() { // Setup string filePath = Path.Combine(this.TestContext.TestDir, "Out\\Dots", "chat.dot"); GeometryGraph graph = this.LoadGraph(filePath); AddLabelSizes(graph); Assert.IsTrue(graph.CollectAllLabels().Count > 0, "The loaded graph has no labels."); // Execute LayeredLayout layeredLayout = new LayeredLayout(graph, new SugiyamaLayoutSettings()); layeredLayout.Run(); // Verify foreach (Edge edge in graph.Edges) { VerifyLabelIsNearEdges(edge); // We do not verify that labels don't overlap other edges, // since that is not gauranteed by sugiyama layout. } }
private void SetGraph() { var graph = new Graph(); graph.AddEdge("a", "b"); graph.AddEdge("e", "b"); graph.AddEdge("d", "b"); graph.AddEdge("b", "c"); graph.AddEdge("a22", "b22"); graph.AddEdge("e22", "b22"); graph.AddEdge("d22", "b22"); graph.AddEdge("b22", "c22"); graph.AddEdge("a0", "b0"); graph.AddEdge("b0", "c0"); graph.AddEdge("a33", "b33"); graph.AddEdge("e33", "b33"); graph.AddEdge("d33", "b33"); graph.AddEdge("b33", "c33"); graph.AddEdge("a11", "b11"); graph.AddEdge("b11", "c11").LabelText = "Test labels!"; graph.CreateGeometryGraph(); foreach (Node node in graph.Nodes) { node.GeometryNode.BoundaryCurve = CreateLabelAndBoundary(node); } foreach (var edge in graph.Edges) { if (edge.Label != null) { var geomEdge = edge.GeometryEdge; double width; double height; StringMeasure.MeasureWithFont(edge.LabelText, new Font(edge.Label.FontName, (float)edge.Label.FontSize), out width, out height); edge.Label.GeometryLabel = geomEdge.Label = new Label(width, height, geomEdge); } } var geomGraph = graph.GeometryGraph; var geomGraphComponents = GraphConnectedComponents.CreateComponents(geomGraph.Nodes, geomGraph.Edges); var settings = new SugiyamaLayoutSettings(); foreach (var subgraph in geomGraphComponents) { var layout = new LayeredLayout(subgraph, settings); subgraph.Margins = settings.NodeSeparation / 2; layout.Run(); } Microsoft.Msagl.Layout.MDS.MdsGraphLayout.PackGraphs(geomGraphComponents, settings); geomGraph.UpdateBoundingBox(); gViewer1.NeedToCalculateLayout = false; gViewer1.Graph = graph; }
public void TreeWithConstraints() { var graph = new GeometryGraph(); var closed = new Node(CreateEllipse(), "closed"); var line = new Node(CreateEllipse(), "line"); var bezier = new Node(CreateEllipse(), "bezier"); var arc = new Node(CreateEllipse(), "arc"); var rectangle = new Node(CreateEllipse(), "rectangle"); var ellipse = new Node(CreateEllipse(), "ellipse"); var polygon = new Node(CreateEllipse(), "polygon"); var shapes = new Node(CreateEllipse(), "shapes"); var open = new Node(CreateEllipse(), "open"); graph.Nodes.Add(closed); graph.Nodes.Add(line); graph.Nodes.Add(bezier); graph.Nodes.Add(arc); graph.Nodes.Add(rectangle); graph.Nodes.Add(ellipse); graph.Nodes.Add(polygon); graph.Nodes.Add(shapes); graph.Nodes.Add(open); var so = new Edge(shapes, open); var sc = new Edge(shapes, closed); var ol = new Edge(open, line); var ob = new Edge(open, bezier); var oa = new Edge(open, arc); var cr = new Edge(closed, rectangle); var ce = new Edge(closed, ellipse); var cp = new Edge(closed, polygon); graph.Edges.Add(so); graph.Edges.Add(sc); graph.Edges.Add(ol); graph.Edges.Add(ob); graph.Edges.Add(oa); graph.Edges.Add(cr); graph.Edges.Add(ce); graph.Edges.Add(cp); var settings = new SugiyamaLayoutSettings(); settings.AddUpDownVerticalConstraint(closed, ellipse); settings.AddUpDownVerticalConstraint(open, bezier); settings.AddUpDownConstraint(closed, open); settings.AddSameLayerNeighbors(polygon, open); settings.AddLeftRightConstraint(closed, open); //To verify 444585, just turn on this following commented line settings.AddLeftRightConstraint(ellipse, rectangle); settings.AddLeftRightConstraint(ellipse, bezier); LayeredLayout layeredLayout = new LayeredLayout(graph, settings); layeredLayout.Run(); ShowGraphInDebugViewer(graph); Assert.IsTrue(Math.Abs(closed.Center.X - ellipse.Center.X) < 0.01); Assert.IsTrue(Math.Abs(open.Center.X - bezier.Center.X) < 0.01); foreach (var n0 in graph.Nodes) { foreach (var n1 in graph.Nodes) { if (n0 == n1) { continue; } Assert.IsFalse(n0.BoundingBox.Intersects(n1.BoundingBox)); } } SugiyamaValidation.ValidateUpDownVerticalConstraint(closed, ellipse); SugiyamaValidation.ValidateUpDownVerticalConstraint(open, bezier); SugiyamaValidation.ValidateUpDownConstraint(closed, open); SugiyamaValidation.ValidateNeighborConstraint(graph, polygon, open, settings); SugiyamaValidation.ValidateLeftRightConstraint(closed, open); //To verify 444585, also turn on this following commented line //SugiyamaValidation.ValidateLeftRightConstraint(ellipse, rectangle); SugiyamaValidation.ValidateLeftRightConstraint(ellipse, bezier); }
public void GenerateTechs() { foreach (var instance in _ringInstances) { instance.ReturnToPool(); } _ringInstances.Clear(); foreach (var instance in _techInstances) { instance.ReturnToPool(); } _techInstances.Clear(); foreach (var instance in _linkInstances) { instance.ReturnToPool(); } _linkInstances.Clear(); foreach (var instance in _arrowInstances) { instance.ReturnToPool(); } _arrowInstances.Clear(); var graph = new GeometryGraph(); var settings = new SugiyamaLayoutSettings(); if (TestMode) { for (int i = 0; i < TechCount; i++) { var node = NewNode(i); graph.Nodes.Add(node); if (i > SeedTechs) { graph.Edges.Add(new Edge(graph.Nodes[Random.Range(max(0, i - RollingWindowSize), i - 1)], node)); } } foreach (var vertex in graph.Nodes.Where(v => !graph.Edges.Any(e => e.Source == v || e.Target == v))) { graph.Edges.Add(new Edge(vertex, graph.Nodes[Random.Range(0, TechCount - 1)])); } } else { var nodeMap = new Dictionary <BlueprintData, Node>(); foreach (var blueprint in Blueprints) { var node = NewNode(blueprint); nodeMap[blueprint] = node; graph.Nodes.Add(node); } foreach (var targetBlueprint in Blueprints) { foreach (var sourceBlueprint in Blueprints.Where(sb => targetBlueprint.Dependencies.Any(dep => sb.ID == dep))) { var edge = new Edge(nodeMap[sourceBlueprint], nodeMap[targetBlueprint]); graph.Edges.Add(edge); var splitName = sourceBlueprint.Name.Split(' '); if (splitName.Length > 1) { var nameStart = string.Join(" ", splitName.Take(splitName.Length - 1)); if (targetBlueprint.Name.StartsWith(nameStart)) { edge.Weight *= 10; } } } } } settings.BrandesThreshold = 9999; var islands = graph.GetClusteredConnectedComponents(); var islandMap = graph.Nodes.ToDictionary(n => n, n => islands.Find(c => c.Nodes.Any(cn => cn.UserData == n))); if (TestMode) { foreach (var island in islands) { foreach (var node in island.Nodes) { var region = GetRegion(island, node, DependencyAncestorDepth, DependencyDepth); while (Random.value < MultipleDependencyProbability && region.Count > 0) { var dependency = region[Random.Range(0, region.Count)]; graph.Edges.Add(new Edge(dependency.UserData as Node, node.UserData as Node)); region.Remove(dependency); } } } } var islandsBySize = islands.OrderByDescending(i => i.Nodes.Count); var largestIsland = islandsBySize.First(); foreach (var island in islandsBySize.Skip(1)) { settings.VerticalConstraints.SameLayerConstraints.Insert(new Tuple <Node, Node>( largestIsland.Nodes[Random.Range(0, largestIsland.Nodes.Count)].UserData as Node, island.Nodes[Random.Range(0, island.Nodes.Count)].UserData as Node)); } settings.PackingMethod = PackingMethod; settings.Transformation = PlaneTransformation.Rotation(PI); var layout = new LayeredLayout(graph, settings); layout.Run(); var positions = graph.Nodes.ToDictionary(n => n, n => (float2)n.Center); var islandCenters = islands.ToDictionary(i => i, i => i.Nodes.Aggregate(float2(0, 0), (total, v) => total + positions[v.UserData as Node]) / i.Nodes.Count); Rect bounds = Rect.MinMaxRect( positions.Values.Min(v => v.x), positions.Values.Min(v => v.y), positions.Values.Max(v => v.x), positions.Values.Max(v => v.y)); var tiers = Mathf.RoundToInt(graph.Nodes.Max(n => Rect.PointToNormalized(bounds, n.Center).y) / graph.Nodes.Min(n => { var normalized = Rect.PointToNormalized(bounds, n.Center); return(normalized.y > .001f ? normalized.y : 1); })); // var islandsBySize = islands.OrderByDescending(i => i.Nodes.Count); // var largestIsland = islandsBySize.First(); // foreach(var island in islandsBySize.Skip(1)) // settings.AddSameLayerNeighbors(largestIsland.Nodes.RandomElement().UserData as Node, island.Nodes.RandomElement().UserData as Node); // // layout = new LayeredLayout(graph, settings); // layout.Run(); positions = graph.Nodes.ToDictionary(n => n, n => (float2)n.Center); islandCenters = islands.ToDictionary(i => i, i => i.Nodes.Aggregate(float2(0, 0), (total, v) => total + positions[v.UserData as Node]) / i.Nodes.Count); bounds = Rect.MinMaxRect( positions.Values.Min(v => v.x), positions.Values.Min(v => v.y), positions.Values.Max(v => v.x), positions.Values.Max(v => v.y)); Debug.Log($"Generated {tiers} tiers of techs!"); var islandColors = islandCenters.ToDictionary( i => i.Key, i => Color.HSVToRGB(lerp(HueMin, HueMax, Rect.PointToNormalized(bounds, i.Value).x), Saturation, Brightness)); var islandFillMaterials = islandColors.ToDictionary(i => i.Key, i => { var mat = new Material(TechFillMaterial); var col = i.Value; col.a = FillOpacity; mat.SetColor("_TintColor", col); return(mat); }); var islandGlowMaterials = islandColors.ToDictionary(i => i.Key, i => { var mat = new Material(TechGlowMaterial); var col = i.Value; col.a = GlowOpacity; mat.SetColor("_TintColor", col); return(mat); }); var islandArrowMaterials = islandColors.ToDictionary(i => i.Key, i => { var mat = new Material(TechArrowMaterial); var col = i.Value; col.a = 1; mat.SetColor("_TintColor", col); return(mat); }); var islandLinkMaterials = islandColors.ToDictionary(i => i.Key, i => { var mat = new Material(TechLinkMaterial); var col = i.Value; col.a = 1; mat.SetColor("_TintColor", col); return(mat); }); if (Radial) { positions = positions.ToDictionary( kvp => kvp.Key, kvp => { var normalized = Rect.PointToNormalized(bounds, kvp.Value); var rads = normalized.x * (PI * 2 - PaddingRadians) + PaddingRadians / 2; return(float2(sin(rads), -cos(rads)) * ((normalized.y * tiers + StartTier + .5f) * LayerDistance) * Scale); }); } else { positions = positions.ToDictionary( kvp => kvp.Key, kvp => { var normalized = Rect.PointToNormalized(bounds, kvp.Value); return(float2( normalized.x * LayerDistance * tiers * (bounds.width / bounds.height), (normalized.y * tiers / 2 + StartTier + .5f) * LayerDistance)); }); } foreach (var vertex in graph.Nodes.Where(positions.ContainsKey)) { var tech = Tech.Instantiate <TechNode>(); tech.transform.position = (Vector2)positions[vertex]; tech.Label.text = $"{(TestMode ? ((int) vertex.UserData).ToString() : ((BlueprintData) vertex.UserData).ID.ToString().Substring(0,2))}"; var gradient = tech.Label.colorGradient; gradient.bottomLeft = gradient.bottomRight = islandColors[islandMap[vertex]]; tech.Label.colorGradient = gradient; tech.Icon.material.SetTexture("_MainTex", _icons[Random.Range(0, _icons.Length - 1)]); tech.Fill.material = islandFillMaterials[islandMap[vertex]]; tech.Glow.material = islandGlowMaterials[islandMap[vertex]]; if (!TestMode) { tech.Fill.GetComponent <ClickableCollider>().OnClick += (collider, data) => { PropertiesPanel.Clear(); var blueprint = (BlueprintData)vertex.UserData; PropertiesPanel.Title.text = blueprint.Name; PropertiesPanel.AddProperty("Research Time", () => $"{blueprint.ResearchTime:0.##} MH"); PropertiesPanel.AddProperty("Produces", () => $"{Context.Cache.Get<ItemData>(blueprint.Item).Name}"); PropertiesPanel.AddProperty("Production Quality", () => $"{Mathf.RoundToInt(blueprint.Quality * 100)}%"); PropertiesPanel.AddProperty("Production Time", () => $"{blueprint.ProductionTime:0.##} MH"); var ingredientsList = PropertiesPanel.AddList("Ingredients"); foreach (var ingredient in blueprint.Ingredients) { var ingredientData = Context.Cache.Get <ItemData>(ingredient.Key); ingredientsList.AddProperty(ingredientData.Name, () => ingredient.Value.ToString()); } ingredientsList.SetExpanded(true, true); var dependenciesList = PropertiesPanel.AddList("Dependencies"); foreach (var dependency in blueprint.Dependencies) { var dependencyBlueprint = Context.Cache.Get <BlueprintData>(dependency); dependenciesList.AddProperty(dependencyBlueprint.Name); } dependenciesList.SetExpanded(true, true); var descendantsList = PropertiesPanel.AddList("Descendants"); foreach (var descendant in Blueprints.Where(bp => bp.Dependencies.Any(dep => blueprint.ID == dep))) { descendantsList.AddProperty(descendant.Name); } descendantsList.SetExpanded(true, true); } } ; _techInstances.Add(tech.GetComponent <Prototype>()); } foreach (var edge in graph.Edges) { var link = RadialLink.Instantiate <LineRenderer>(); link.material = islandLinkMaterials[islandMap[edge.Source]]; link.positionCount = LinkPoints; var p1r = length(positions[edge.Source]); var p2r = length(positions[edge.Target]); var p1a = (atan2(positions[edge.Source].y, positions[edge.Source].x) + PI * 2.5f) % (PI * 2); var p2a = (atan2(positions[edge.Target].y, positions[edge.Target].x) + PI * 2.5f) % (PI * 2); var p1 = float2(sin(p1a) * p1r, -cos(p1a) * p1r); var p2 = float2(sin(p2a) * p2r, -cos(p2a) * p2r); var dist = length(p2 - p1); var distProp = (dist - LinkTargetDistance) / dist; var dir = new float2(); var lastPos = new float2(); link.SetPositions(Enumerable.Range(0, LinkPoints).Select(i => { var lerp = (float)i / (LinkPoints - 1) * distProp; var angle = math.lerp(p1a, p2a, (lerp)); var radius = math.lerp(p1r, p2r, lerp); var pos = Radial ? float2(sin(angle) * radius, -cos(angle) * radius) : math.lerp(positions[edge.Source], positions[edge.Target], lerp); dir = normalize(pos - lastPos); lastPos = pos; return((Vector3)float3(lastPos, LinkDepth)); }).ToArray()); _linkInstances.Add(link.GetComponent <Prototype>()); var arrow = Arrow.Instantiate <TechArrow>(); arrow.transform.position = new Vector3(lastPos.x, lastPos.y, ArrowDepth); arrow.transform.rotation = Quaternion.Euler(0, 0, atan2(dir.y, dir.x) * Mathf.Rad2Deg); arrow.Icon.material = islandArrowMaterials[islandMap[edge.Source]]; _arrowInstances.Add(arrow.GetComponent <Prototype>()); } if (Radial) { for (int i = 1; i <= tiers; i++) { var ring = Ring.Instantiate <LineRenderer>(); var ringPositions = new Vector3[Sections]; for (int s = 0; s < Sections; s++) { var rads = ((float)s / (Sections - 1)) * (PI * 2 - PaddingRadians) + PaddingRadians / 2; ringPositions[s] = new Vector3(sin(rads), -cos(rads), 0) * ((i + StartTier) * (LayerDistance) * Scale); ringPositions[s].z = RingDepth; } ring.positionCount = Sections; ring.SetPositions(ringPositions); var tierLerp = (float)i / (tiers - 1); ring.colorGradient = new Gradient { alphaKeys = new [] { new GradientAlphaKey(1, 0), new GradientAlphaKey(1, 1) }, colorKeys = Enumerable.Range(0, RingColorKeys).Select(x => { var ringLerp = (float)x / (RingColorKeys - 1); return(new GradientColorKey( Color.HSVToRGB(HueMin + (HueMax - HueMin) * ringLerp, lerp(RingInnerSaturation, RingOuterSaturation, tierLerp), lerp(RingInnerBrightness, RingOuterBrightness, tierLerp)), ringLerp)); }).ToArray() }; _ringInstances.Add(ring.GetComponent <Prototype>()); } } } }
static internal 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(' ')) { 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(); settings.Transformation = PlaneTransformation.Rotation(Math.PI / 2); settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline; var layout = new LayeredLayout(graph, settings); layout.Run(); return(graph); // 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) // AddNode(id, graph, w, h); // foreach (var id in col1) // AddNode(id, graph, w, h); // foreach (var id in col2) // AddNode(id, graph, w, h); // foreach (var id in col3) // 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 // graph.Transformation = PlaneTransformation.Rotation(Math.PI / 2); // settings.NodeSeparation = 5; // settings.LayerSeparation = 100; // var ll = new LayeredLayout(graph, settings); // ll.Run(); // return graph; }
static void TestGraphWithConstraints() { var graph = new GeometryGraph(); var closed = new Node(CreateEllipse(), "closed"); var line = new Node(CreateEllipse(), "line"); var bezier = new Node(CreateEllipse(), "bezier"); var arc = new Node(CreateEllipse(), "arc"); var rectangle = new Node(CreateEllipse(), "rectangle"); var ellipse = new Node(CreateEllipse(), "ellipse"); var polygon = new Node(CreateEllipse(), "polygon"); var shapes = new Node(CreateEllipse(), "shapes"); var open = new Node(CreateEllipse(), "open"); graph.Nodes.Add(closed); graph.Nodes.Add(line); graph.Nodes.Add(bezier); graph.Nodes.Add(arc); graph.Nodes.Add(rectangle); graph.Nodes.Add(ellipse); graph.Nodes.Add(polygon); graph.Nodes.Add(shapes); graph.Nodes.Add(open); var so = new Edge(shapes, open); var sc = new Edge(shapes, closed); var ol = new Edge(open, line); var ob = new Edge(open, bezier); var oa = new Edge(open, arc); var cr = new Edge(closed, rectangle); var ce = new Edge(closed, ellipse); var cp = new Edge(closed, polygon); graph.Edges.Add(so); graph.Edges.Add(sc); graph.Edges.Add(ol); graph.Edges.Add(ob); graph.Edges.Add(oa); graph.Edges.Add(cr); graph.Edges.Add(ce); graph.Edges.Add(cp); var settings = new SugiyamaLayoutSettings(); settings.AddUpDownVerticalConstraint(closed, ellipse); settings.AddUpDownVerticalConstraint(open, bezier); settings.AddUpDownConstraint(closed, open); settings.AddSameLayerNeighbors(polygon, open); settings.AddLeftRightConstraint(closed, open); settings.AddLeftRightConstraint(open, closed); ////To verify 444585, just turn on this following commented line settings.AddLeftRightConstraint(ellipse, rectangle); settings.AddLeftRightConstraint(ellipse, bezier); var layeredLayout = new LayeredLayout(graph, settings); layeredLayout.Run(); #if TEST_MSAGL DisplayGeometryGraph.ShowGraph(graph); #endif }
public void StaircaseLayoutWithConstraints() { var graph = new GeometryGraph(); var a = new Node(CreateRectangle()); var b = new Node(CreateRectangle()); var c = new Node(CreateRectangle()); var d = new Node(CreateRectangle()); // need the following dummy nodes for constraints var v1 = new Node(CreateDot()); var v2 = new Node(CreateDot()); var v3 = new Node(CreateDot()); graph.Nodes.Add(a); graph.Nodes.Add(b); graph.Nodes.Add(c); graph.Nodes.Add(d); graph.Nodes.Add(v1); graph.Nodes.Add(v2); graph.Nodes.Add(v3); graph.Edges.Add(new Edge(a, b)); graph.Edges.Add(new Edge(a, b)); graph.Edges.Add(new Edge(b, a)); graph.Edges.Add(new Edge(b, c)); graph.Edges.Add(new Edge(c, d)); graph.Edges.Add(new Edge(d, c)); graph.Edges.Add(new Edge(c, d)); graph.Edges.Add(new Edge(d, c)); // if dummy nodes are not connected to graph then we get a DebugAssert fail graph.Edges.Add(new Edge(a, v1)); graph.Edges.Add(new Edge(b, v2)); graph.Edges.Add(new Edge(c, v3)); var settings = new SugiyamaLayoutSettings(); // it's fairly easy to find debug assert failures by trying different combinations of the following settings.AddUpDownVerticalConstraint(a, v1); settings.AddUpDownVerticalConstraint(b, v2); settings.AddUpDownVerticalConstraint(c, v3); //settings.AddUpDownVerticalConstraint(v2, d); //settings.AddUpDownConstraint(a, v1); //settings.AddUpDownConstraint(a, b); //settings.AddUpDownConstraint(b, c); //settings.AddUpDownConstraint(c, d); settings.AddSameLayerNeighbors(v1, b); settings.AddSameLayerNeighbors(v2, c); settings.AddSameLayerNeighbors(d, v3); //settings.AddLeftRightConstraint(v1, b); //settings.AddLeftRightConstraint(v2, c); - doesn't work LayeredLayout layeredLayout = new LayeredLayout(graph, settings); layeredLayout.Run(); graph.Nodes.Remove(v1); graph.Nodes.Remove(v2); graph.Nodes.Remove(v3); ShowGraphInDebugViewer(graph); }