public void Layouting() { // If we have a given dot file, we can also simply read it back in RootGraph root = RootGraph.FromDotFile(TestContext.CurrentContext.TestDirectory + "/out.dot"); // Let's have graphviz compute a dot layout for us root.ComputeLayout(); // We can export this to svg root.ToSvgFile(TestContext.CurrentContext.TestDirectory + "/dot_out.svg"); // Or programatically read out the layout attributes Node nodeA = root.GetNode("A"); PointF position = nodeA.Position(); Assert.AreEqual("{X=43, Y=192.1739}", position.ToString()); // Like a bounding box of an object RectangleF nodeboundingbox = nodeA.BoundingBox(); Assert.AreEqual("{X=16,Y=171.3391,Width=54,Height=41.66957}", nodeboundingbox.ToString()); // Or splines between nodes Node nodeB = root.GetNode("B"); Edge edge = root.GetEdge(nodeA, nodeB, "Some edge name"); PointF[] spline = edge.FirstSpline(); string splineString = string.Join(", ", spline.Select(p => p.ToString())); string expectedSplineString = "{X=0, Y=0}, {X=43, Y=171.29}, {X=43, Y=163.45}," + " {X=43, Y=154.26}, {X=43, Y=145.63}"; Assert.AreEqual(expectedSplineString, splineString); GraphvizLabel nodeLabel = nodeA.GetLabel(); Assert.AreEqual("{X=36.25977,Y=181.4415,Width=13.48047,Height=21.46484}", nodeLabel.BoundingBox().ToString()); Assert.AreEqual("Times-Roman", nodeLabel.FontName().ToString()); SubGraph cluster = root.GetSubgraph("cluster_1"); RectangleF clusterbox = cluster.BoundingBox(); RectangleF rootgraphbox = root.BoundingBox(); Assert.AreEqual("{X=8,Y=8,Width=70,Height=135.34}", clusterbox.ToString()); Assert.AreEqual("{X=0,Y=0,Width=142,Height=213.01}", rootgraphbox.ToString()); // Once all layout information is obtained from the graph, the resources should be // reclaimed. To do this, the application should call the cleanup routine associated // with the layout algorithm used to draw the graph. This is done by a call to // FreeLayout(). A given graph can be laid out multiple times. The application, however, // must clean up the earlier layout's information with a call to FreeLayout before // invoking a new layout function. root.FreeLayout(); // We can use layout engines other than dot by explicitly passing the engine we want root.ComputeLayout(LayoutEngines.Neato); root.ToSvgFile(TestContext.CurrentContext.TestDirectory + "/neato_out.svg"); }
public void Layouting() { // If we have a given dot file (in this case the one we generated above), we can also read it back in RootGraph root = RootGraph.FromDotFile(TestContext.CurrentContext.TestDirectory + "/out.dot"); // Let's have graphviz compute a dot layout for us root.ComputeLayout(); // We can export this to svg root.ToSvgFile(TestContext.CurrentContext.TestDirectory + "/dot_out.svg"); // Or programatically read out the layout attributes Node nodeA = root.GetNode("A"); PointF position = nodeA.Position(); Utils.AssertPattern(@"{X=[\d.]+, Y=[\d.]+}", position.ToString()); // Like a bounding box of an object RectangleF nodeboundingbox = nodeA.BoundingBox(); Utils.AssertPattern(@"{X=[\d.]+,Y=[\d.]+,Width=[\d.]+,Height=[\d.]+}", nodeboundingbox.ToString()); // Or splines between nodes Node nodeB = root.GetNode("B"); Edge edge = root.GetEdge(nodeA, nodeB, "Some edge name"); PointF[] spline = edge.FirstSpline(); string splineString = string.Join(", ", spline.Select(p => p.ToString())); string expectedSplinePattern = @"{X=[\d.]+, Y=[\d.]+}, {X=[\d.]+, Y=[\d.]+}, {X=[\d.]+, Y=[\d.]+}," + @" {X=[\d.]+, Y=[\d.]+}, {X=[\d.]+, Y=[\d.]+}"; Utils.AssertPattern(expectedSplinePattern, splineString); GraphvizLabel nodeLabel = nodeA.GetLabel(); Utils.AssertPattern(@"{X=[\d.]+,Y=[\d.]+,Width=[\d.]+,Height=[\d.]+}", nodeLabel.BoundingBox().ToString()); Utils.AssertPattern(@"Times-Roman", nodeLabel.FontName().ToString()); // Once all layout information is obtained from the graph, the resources should be // reclaimed. To do this, the application should call the cleanup routine associated // with the layout algorithm used to draw the graph. This is done by a call to // FreeLayout(). A given graph can be laid out multiple times. The application, however, // must clean up the earlier layout's information with a call to FreeLayout before // invoking a new layout function. root.FreeLayout(); // We can use layout engines other than dot by explicitly passing the engine we want root.ComputeLayout(LayoutEngines.Neato); root.ToSvgFile(TestContext.CurrentContext.TestDirectory + "/neato_out.svg"); }
protected override PlacementInfo PositionComponents(Dictionary <FIRRTLNode, Point> nodeSizes, Module mod) { PlacementInfo placments = new PlacementInfo(); const int dpi = 96; const int ppi = 72; RootGraph graph = RootGraph.CreateNew("some name??", GraphType.Directed); graph.SafeSetAttribute("rankdir", "LR", "TB"); graph.SafeSetAttribute("ranksep", "7", "0.5"); graph.SafeSetAttribute("nodesep", "1.0", "0.25"); //Add nodes to graph Dictionary <FIRRTLNode, Node> firNodeToNode = new Dictionary <FIRRTLNode, Node>(); Dictionary <Input, string> inputToPort = new Dictionary <Input, string>(); Dictionary <Output, string> outputToPort = new Dictionary <Output, string>(); Dictionary <Input, Node> inputToNode = new Dictionary <Input, Node>(); Dictionary <Output, Node> outputToNode = new Dictionary <Output, Node>(); int nodeCounter = 0; int portName = 0; foreach (var firNode in nodeSizes) { if (firNode.Key == mod) { continue; } string nodeName = $"n{nodeCounter++}"; Node node = graph.GetOrAddNode(nodeName); node.SafeSetAttribute("shape", "record", "ellipse"); node.SafeSetAttribute("width", ((double)firNode.Value.X / dpi).ToString(), "0.75"); node.SafeSetAttribute("height", ((double)firNode.Value.Y / dpi).ToString(), "0.5"); Input[] nodeInputs = firNode.Key.GetInputs(); Output[] nodeOutputs = firNode.Key.GetOutputs(); MakeIntoRecord(node, nodeInputs, nodeOutputs, inputToPort, outputToPort, ref portName); firNodeToNode.Add(firNode.Key, node); foreach (var input in nodeInputs) { inputToNode.Add(input, node); } foreach (var output in nodeOutputs) { outputToNode.Add(output, node); } } Node modInputNode = graph.GetOrAddNode("modInput"); MakeIntoRecord(modInputNode, mod.GetInputs(), Array.Empty <Output>(), inputToPort, outputToPort, ref portName); modInputNode.SafeSetAttribute("rank", "sink", "sink"); Node modOutputNode = graph.GetOrAddNode("modOutput"); MakeIntoRecord(modInputNode, Array.Empty <Input>(), mod.GetOutputs(), inputToPort, outputToPort, ref portName); modOutputNode.SafeSetAttribute("rank", "source", "source"); //Make edges int edgeCounter = 0; foreach (Output output in outputToNode.Keys) { if (!output.IsConnectedToAnything()) { continue; } var from = outputToNode[output]; foreach (var input in output.GetConnectedInputs()) { if (input.Node != null && input.Node is INoPlaceAndRoute) { continue; } if (!inputToNode.ContainsKey(input)) { continue; } var to = inputToNode[input]; var edge = graph.GetOrAddEdge(from, to, (edgeCounter++).ToString()); edge.SafeSetAttribute("tailport", outputToPort[output], " "); edge.SafeSetAttribute("headport", inputToPort[input], " "); } } graph.ComputeLayout(); Dictionary <FIRRTLNode, Rectangle> firNodeRects = new Dictionary <FIRRTLNode, Rectangle>(); foreach (var firToVizNode in firNodeToNode) { var centerF = firToVizNode.Value.Position(); var center = new Point((int)(centerF.X * dpi), (int)(centerF.Y * dpi)) / ppi; var nodeSize = nodeSizes[firToVizNode.Key]; var topLeft = center - (nodeSize / 2); firNodeRects.Add(firToVizNode.Key, new Rectangle(topLeft, nodeSize)); } graph.FreeLayout(); Point min = new Point(int.MaxValue, int.MaxValue); foreach (var rect in firNodeRects.Values) { min = Point.Min(min, rect.Pos); } Point offsetBy = min.Abs(); foreach (var firRect in firNodeRects) { placments.AddNodePlacement(firRect.Key, new Rectangle(offsetBy + firRect.Value.Pos, firRect.Value.Size)); } Point borderPadding = new Point(100, 200); placments.AutoSpacePlacementRanks(mod); placments.AddBorderPadding(borderPadding); return(placments); }