public GraphLayout(string engine, object graphObject = null) : base(null, graphObject, true) { _graph = this.GraphVizSubGraph; _dirty = true; _engine = engine; _graphObject = graphObject; _objectToNodeMap = new Dictionary <object, NodeLayout>(); _objectToEdgeMap = new Dictionary <object, EdgeLayout>(); //_graphDpiAttribute = CGraphLib.agattr(_graph, CGraphLib.AGRAPH, "dpi", "72"); _graphBbAttribute = CGraphLib.agattr(_graph, CGraphLib.AGRAPH, "bb", ""); _graphRankSepAttribute = CGraphLib.agattr(_graph, CGraphLib.AGRAPH, "ranksep", "2"); _graphNodeSepAttribute = CGraphLib.agattr(_graph, CGraphLib.AGRAPH, "nodesep", "1"); _graphLenAttribute = CGraphLib.agattr(_graph, CGraphLib.AGRAPH, "len", "3"); _graphMarginAttribute = CGraphLib.agattr(_graph, CGraphLib.AGRAPH, "margin", "10"); _nodeWidthAttribute = CGraphLib.agattr(_graph, CGraphLib.AGNODE, "width", "0"); _nodeHeightAttribute = CGraphLib.agattr(_graph, CGraphLib.AGNODE, "height", "0"); _nodeShapeAttribute = CGraphLib.agattr(_graph, CGraphLib.AGNODE, "shape", "rectangle"); _nodePosAttribute = CGraphLib.agattr(_graph, CGraphLib.AGNODE, "pos", ""); _nodeStyleAttribute = CGraphLib.agattr(_graph, CGraphLib.AGNODE, "style", ""); _nodeMarginAttribute = CGraphLib.agattr(_graph, CGraphLib.AGNODE, "margin", "0"); _edgePosAttribute = CGraphLib.agattr(_graph, CGraphLib.AGEDGE, "pos", ""); _edgeDirAttribute = CGraphLib.agattr(_graph, CGraphLib.AGEDGE, "dir", "none"); }
internal EdgeLayout(GraphLayout graph, NodeLayout source, NodeLayout target, object edgeObject) { _graph = graph; _edgeObject = edgeObject; _source = source; _target = target; _graphVizEdge = CGraphLib.agedge(_graph.GraphVizGraph, source.GraphVizNode, target.GraphVizNode, null, true); }
internal EdgeLayout CreateEdge(NodeLayout source, NodeLayout target, object edgeObject) { _dirty = true; var e = new EdgeLayout(this, source, target, edgeObject); CGraphLib.agxset(e.GraphVizEdge, _edgeDirAttribute, "none"); _objectToEdgeMap.Add(edgeObject, e); return(e); }
private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: dispose managed state (managed objects). } // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. // TODO: set large fields to null. CGraphLib.agclose(_graph); disposedValue = true; } }
internal NodeLayout(NodeLayout parent, object nodeObject, bool isSubGraph = false) { _nodeObject = nodeObject; _isSubGraph = isSubGraph; _parentNode = parent; if (parent != null) { Debug.Assert(parent.IsSubGraph); _graph = parent.Graph; if (_isSubGraph) { _graphVizSubGraph = CGraphLib.agsubg(parent.GraphVizSubGraph, "cluster" + (++SubGraphCounter), true); } else { _graphVizSubGraph = parent.GraphVizSubGraph; } if (!_isSubGraph) { _graphVizNode = CGraphLib.agnode(_graphVizSubGraph, null, true); } //else _graphVizNode = _graphVizSubGraph; /*if (_isSubGraph) * { * CGraphLib.agxset(_graphVizNode, _graph._nodeWidthAttribute, "0"); * CGraphLib.agxset(_graphVizNode, _graph._nodeHeightAttribute, "0"); * CGraphLib.agxset(_graphVizNode, _graph._nodeStyleAttribute, "invis"); * }*/ } else { _graph = (GraphLayout)this; _graphVizSubGraph = CGraphLib.agopen(null, Agdesc_t.none, IntPtr.Zero); _graphVizNode = CGraphLib.agnode(_graphVizSubGraph, null, true); } }
public void ComputeLayout() { if (!_dirty) { return; } foreach (var node in _objectToNodeMap.Values) { if (!node.IsSubGraph) { if (node.PreferredPosition != null) { CGraphLib.agxset(node.GraphVizNode, _nodePosAttribute, node.PreferredPosition.ToString()); } else { CGraphLib.agxset(node.GraphVizNode, _nodePosAttribute, ""); } if (node.PreferredSize != null) { CGraphLib.agxset(node.GraphVizNode, _nodeWidthAttribute, node.PreferredSize?.X.ToString()); CGraphLib.agxset(node.GraphVizNode, _nodeHeightAttribute, node.PreferredSize?.Y.ToString()); } else { CGraphLib.agxset(node.GraphVizNode, _nodeWidthAttribute, ""); CGraphLib.agxset(node.GraphVizNode, _nodeHeightAttribute, ""); } } else { //CGraphLib.agxset(node.GraphVizSubGraph, _nodePosAttribute, ""); //CGraphLib.agxset(node.GraphVizSubGraph, _nodeWidthAttribute, ""); //CGraphLib.agxset(node.GraphVizSubGraph, _nodeHeightAttribute, ""); CGraphLib.agxset(node.GraphVizSubGraph, _graphMarginAttribute, (this.NodeMargin * DefaultDpi).ToString()); } } CGraphLib.agxset(_graph, _graphNodeSepAttribute, this.NodeSeparation.ToString()); CGraphLib.agxset(_graph, _graphRankSepAttribute, this.RankSeparation.ToString()); CGraphLib.agxset(_graph, _graphLenAttribute, this.EdgeLength.ToString()); //CGraphLib.agxset(_graph, _graphMarginAttribute, this.NodeMargin.ToString()); _dot = GraphVizLib.Instance.Layout(_graph, _engine); var graphBb = Marshal.PtrToStringAnsi(CGraphLib.agxget(_graph, _graphBbAttribute)); if (!string.IsNullOrEmpty(graphBb)) { var parts = graphBb.Trim().Split(','); if (parts.Length == 4) { double x1, y1, x2, y2; for (int i = 0; i < parts.Length; i++) { var charSubParts = parts[i].Split('.'); if (charSubParts.Length > 1) { var subPart = charSubParts[0] + ',' + charSubParts[1]; parts[i] = subPart; } } if (Double.TryParse(parts[0], out x1) && Double.TryParse(parts[1], out y1) && Double.TryParse(parts[2], out x2) && Double.TryParse(parts[3], out y2)) { x1 /= DefaultDpi; y1 /= DefaultDpi; x2 /= DefaultDpi; y2 /= DefaultDpi; this.Position = new Point2D((x1 + x2) / 2, (y1 + y2) / 2); this.Size = new Point2D(x2 - x1, y2 - y1); } CGraphLib.agxset(_graph, _graphBbAttribute, ""); } } foreach (var node in _objectToNodeMap.Values) { if (node.IsSubGraph) { var gvBb = Marshal.PtrToStringAnsi(CGraphLib.agxget(node.GraphVizSubGraph, _graphBbAttribute)); if (!string.IsNullOrEmpty(gvBb)) { var parts = gvBb.Trim().Split(','); if (parts.Length == 4) { double x1, y1, x2, y2; for (int i = 0; i < parts.Length; i++) { var charSubParts = parts[i].Split('.'); if (charSubParts.Length > 1) { var subPart = charSubParts[0] + ',' + charSubParts[1]; parts[i] = subPart; } } if (double.TryParse(parts[0], out x1) && double.TryParse(parts[1], out y1) && double.TryParse(parts[2], out x2) && double.TryParse(parts[3], out y2)) { x1 /= DefaultDpi; y1 /= DefaultDpi; x2 /= DefaultDpi; y2 /= DefaultDpi; node.Position = new Point2D((x1 + x2) / 2, (y1 + y2) / 2); node.Size = new Point2D(x2 - x1, y2 - y1); } } CGraphLib.agxset(node.GraphVizSubGraph, _graphBbAttribute, ""); } else { if (node.PreferredSize != null) { node.Size = node.PreferredSize.Value; } } } else { var gvPos = Marshal.PtrToStringAnsi(CGraphLib.agxget(node.GraphVizNode, _nodePosAttribute)); if (!string.IsNullOrEmpty(gvPos)) { node.Position = new Point2D(gvPos, GraphLayout.DefaultDpi); CGraphLib.agxset(node.GraphVizNode, _nodePosAttribute, ""); } var gvWidth = Marshal.PtrToStringAnsi(CGraphLib.agxget(node.GraphVizNode, _nodeWidthAttribute)); var gvHeight = Marshal.PtrToStringAnsi(CGraphLib.agxget(node.GraphVizNode, _nodeHeightAttribute)); if (!string.IsNullOrEmpty(gvWidth) && !string.IsNullOrEmpty(gvHeight)) { if (double.TryParse(gvWidth, out var width) && double.TryParse(gvHeight, out var height)) { node.Size = new Point2D(width, height); } } else { if (node.PreferredSize != null) { node.Size = node.PreferredSize.Value; } } } } foreach (var edge in _objectToEdgeMap.Values) { var gvPos = Marshal.PtrToStringAnsi(CGraphLib.agxget(edge.GraphVizEdge, _edgePosAttribute)); if (!string.IsNullOrEmpty(gvPos)) { edge.SetControlPoints(gvPos); CGraphLib.agxset(edge.GraphVizEdge, _edgePosAttribute, ""); } } _dirty = false; }