private static YOrientedRectangle GetNodeLabelLocation(LayoutGraph graph, Node n, INodeLabelLayout nll) { return(nll.LabelModel.GetLabelPlacement( nll.BoundingBox, graph.GetLayout(n), nll.ModelParameter)); }
public override void OptimizeAfterLayering(LayoutGraph graph, ILayers layers, ILayoutDataProvider ldp, IItemFactory itemFactory) { if (coreOptimizer != null) { coreOptimizer.OptimizeAfterLayering(graph, layers, ldp, itemFactory); } }
public override void ApplyLayout(LayoutGraph graph) { var affectedEdges = graph.GetDataProvider(BusRouter.DefaultAffectedEdgesDpKey); var selectedNodes = graph.GetDataProvider(SelectedNodesDpKey); var hider = new LayoutGraphHider(graph); var hiddenEdges = new HashSet <Edge>(); foreach (var edge in graph.Edges) { if (affectedEdges.GetBool(edge) && selectedNodes != null && !selectedNodes.GetBool(edge.Source) && !selectedNodes.GetBool(edge.Target)) { var path = graph.GetPath(edge).ToArray(); for (var i = 1; i < path.Length; i++) { var p1 = path[i - 1]; var p2 = path[i]; if (Math.Abs(p1.X - p2.X) >= 0.0001 && Math.Abs(p1.Y - p2.Y) >= 0.0001) { hiddenEdges.Add(edge); } } } } foreach (var edge in hiddenEdges) { hider.Hide(edge); } ApplyLayoutCore(graph); hider.UnhideEdges(); }
private void ApplyHierarchicLayout(LayoutGraph graph) { HierarchicLayout hl = new HierarchicLayout(); hl.OrthogonalRouting = true; hl.RecursiveGroupLayering = false; hl.ComponentLayoutEnabled = false; hl.FromScratchLayerer = new BackLoopLayerer(); hl.MinimumLayerDistance = MinimumNodeDistance; hl.NodeToNodeDistance = MinimumNodeDistance; ((SimplexNodePlacer)hl.NodePlacer).BarycenterMode = true; ((SimplexNodePlacer)hl.NodePlacer).StraightenEdges = true; hl.LayoutOrientation = LayoutOrientation == LayoutOrientation.LeftToRight ? Layout.LayoutOrientation.LeftToRight : Layout.LayoutOrientation.TopToBottom; hl.HierarchicLayoutCore.PortConstraintOptimizer = new BalancingPortOptimizer(new PortCandidateOptimizer()); if (Scope == Scope.SelectedElements) { hl.FixedElementsLayerer = new AsIsLayerer { MaximumNodeSize = 5 }; hl.LayoutMode = LayoutMode.Incremental; } hl.ApplyLayout(graph); }
/// <summary> /// Copy the given node. Delegate to the type specific implementations. /// </summary> /// <param name="pageLayoutGraph">The layout graph for the page.</param> /// <param name="layoutNode">The node in the layout graph.</param> /// <param name="pageView">The view graph to copy the node to.</param> /// <returns>The copied node.</returns> private INode CopyNode(LayoutGraph pageLayoutGraph, Node layoutNode, IGraph pageView) { INodeInfo nodeInfo = result.GetNodeInfo(layoutNode); INode viewNode; switch (nodeInfo.Type) { case NodeType.Normal: viewNode = CreateNormalNode(pageLayoutGraph, layoutNode, pageView); break; case NodeType.Group: viewNode = CreateGroupNode(pageLayoutGraph, layoutNode, pageView); break; case NodeType.Connector: viewNode = CreateConnectorNode(pageLayoutGraph, layoutNode, pageView); break; case NodeType.Proxy: viewNode = CreateProxyNode(pageLayoutGraph, layoutNode, pageView); break; case NodeType.ProxyReference: viewNode = CreateProxyReferenceNode(pageLayoutGraph, layoutNode, pageView); break; default: throw new ArgumentException("unknown node type"); } return(viewNode); }
/// <summary> /// Create a proxy reference edge. /// </summary> /// <remarks> /// A proxy reference edge is an edge connected to a proxy reference node, i.e., a node that /// refers to a proxy of an original node located on a different page. /// </remarks> /// <param name="pageLayoutGraph">The layout graph representing the current page</param> /// <param name="layoutEdge">The edge of the layout graph that should be copied</param> /// <param name="pageView">The <see cref="IGraph"/> that is built to show the multi-page layout in a graph canvas</param> /// <returns>The created edge</returns> /// <seealso cref="CreateEdgeCore"/> protected IEdge CreateProxyReferenceEdge(LayoutGraph pageLayoutGraph, Edge layoutEdge, IGraph pageView) { IEdge representedEdge = GetRepresentedEdge(layoutEdge); IEdge viewEdge = CreateEdgeCore(pageLayoutGraph, pageView, layoutEdge, representedEdge, ProxyReferenceEdgeDefaults); return(viewEdge); }
public override void ApplyLayout(LayoutGraph graph) { // determine the single node to keep at the center. var provider = graph.GetDataProvider("NodeLayouts"); Node centerNode = null; if (provider != null) { centerNode = graph.Nodes.FirstOrDefault(n => provider.Get(n) != null); } if (CoreLayout != null) { if (centerNode != null) { // remember old center RectD oldLayout = (RectD)provider.Get(centerNode); var fixedLocation = new YPoint(graph.GetX(centerNode) + graph.GetWidth(centerNode), graph.GetY(centerNode)); //Set to saved size (this is important for collapsed nodes to ensure correct size) graph.SetSize(centerNode, oldLayout.Width, oldLayout.Height); // run layout CoreLayout.ApplyLayout(graph); // obtain new center var newFixedLocation = new YPoint(graph.GetX(centerNode) + graph.GetWidth(centerNode), graph.GetY(centerNode)); // and adjust the layout LayoutGraphUtilities.MoveSubgraph(graph, graph.GetNodeCursor(), fixedLocation.X - newFixedLocation.X, fixedLocation.Y - newFixedLocation.Y); } else { CoreLayout.ApplyLayout(graph); } } }
private void RouteMarkedEdges(LayoutGraph graph, IDataMap markedEdgesMap) { if (MarkedEdgeRouter == null) { return; } IDataProvider backupDp = null; if (EdgeSelectionKey != null) { backupDp = graph.GetDataProvider(EdgeSelectionKey); graph.AddDataProvider(EdgeSelectionKey, markedEdgesMap); } if (MarkedEdgeRouter is StraightLineEdgeRouter) { var router = (StraightLineEdgeRouter)MarkedEdgeRouter; router.Scope = Scope.RouteAffectedEdges; router.AffectedEdgesDpKey = EdgeSelectionKey; } MarkedEdgeRouter.ApplyLayout(graph); if (EdgeSelectionKey != null) { graph.RemoveDataProvider(EdgeSelectionKey); if (backupDp != null) { graph.AddDataProvider(EdgeSelectionKey, backupDp); } } }
/// <summary> /// Called by the various node creation callbacks to create a node in the resulting graph view /// that corresponds to the provided <paramref name="layoutNode"/>. /// </summary> /// <remarks> /// If a model node is provided, the ports of the original node will be copied to the created view node. /// Also, a clone of the original node style will be used as the style of the created node. /// </remarks> /// <param name="pageLayoutGraph">The layout graph representing the current page</param> /// <param name="pageView">The <see cref="IGraph"/> that is built to show the multi-page layout in a graph canvas</param> /// <param name="layoutNode">The node of the layout graph that should be copied</param> /// <param name="modelNode">The node of the original input graph that corresponds to the <paramref name="layoutNode"/> (may be <see langword="null"/>)</param> /// <param name="isReferenceNode"></param> /// <param name="nodeDefaults"></param> /// <returns>the created node</returns> /// <seealso cref="CreateConnectorNode"/> /// <seealso cref="CreateNormalNode"/> /// <seealso cref="CreateGroupNode"/> /// <seealso cref="CreateProxyNode"/> /// <seealso cref="CreateProxyReferenceNode"/> protected INode CreateNodeCore(LayoutGraph pageLayoutGraph, IGraph pageView, Node layoutNode, INode modelNode, bool isReferenceNode, INodeDefaults nodeDefaults) { // get the layout from the layout graph INodeLayout nodeLayout = pageLayoutGraph.GetLayout(layoutNode); // get the style from the node defaults or the model node (or the default style if none is provided) INodeStyle style = (INodeStyle)(nodeDefaults.Style != NullNodeStyle ? nodeDefaults.GetStyleInstance() : (modelNode != null ? modelNode.Style.Clone() : pageView.NodeDefaults.Style.Clone())); var tag = modelNode != null ? modelNode.Tag : null; // create the copied node INode viewNode = pageView.CreateNode(new RectD(nodeLayout.X, nodeLayout.Y, nodeLayout.Width, nodeLayout.Height), style, tag); // copy the ports of the model node if (modelNode != null) { CopyPorts(pageView, layoutNode, viewNode, modelNode); } viewToLayoutNode[viewNode] = layoutNode; IMapper <INode, NodeData> referencingMapper = pageView.MapperRegistry.GetMapper <INode, NodeData>(MapperKeyNodeData); NodeData data = new NodeData { IsReferenceNode = isReferenceNode }; referencingMapper[viewNode] = data; return(viewNode); }
private void PaintNodeAndChildren(Graphics g, LayoutGraph graph, Node node) { PaintNode(g, graph, node); INodeLabelLayout[] labels = layoutGraph.GetLabelLayout(node); if (labels != null && labels.Length > 0) { foreach (INodeLabelLayout label in labels) { PaintNodeLabel(g, layoutGraph, node, label); } } if (grouping.IsGroupNode(node)) { SolidBrush oldBrush = this.nodeFillBrush; Color color = Color.FromArgb(Math.Min(255, (int)(oldBrush.Color.R * 0.9f)), Math.Min(255, (int)(oldBrush.Color.G * 0.9f)), Math.Min(255, (int)(oldBrush.Color.B * 0.9f))); this.nodeFillBrush = new SolidBrush(color); for (ListCell cell = this.grouping.GetChildren(node).FirstCell; cell != null; cell = cell.Succ()) { Node child = (Node)cell.Info; PaintNodeAndChildren(g, layoutGraph, child); } this.nodeFillBrush.Dispose(); this.nodeFillBrush = oldBrush; } }
/// <summary> /// Adjusts the edge end points so they don't end outside the shape of the node they are attached to. /// </summary> private static void AdjustPortLocation(LayoutGraph graph, Edge e, YPointPath path, bool atSource) { Node node = atSource ? e.Source : e.Target; YPoint pointRel = atSource ? graph.GetSourcePointRel(e) : graph.GetTargetPointRel(e); // get offset from the node center to the end of the shape at the node side the edge connects to LineSegment segment = path.GetLineSegment(atSource ? 0 : path.Length() - 2); double offset = Math.Min(graph.GetWidth(node), graph.GetHeight(node)) / 2; double offsetX = segment.DeltaX > 0 ^ atSource ? -offset : offset; double offsetY = segment.DeltaY > 0 ^ atSource ? -offset : offset; // if the edge end point is at the center of this side, we use the calculated offset to put the end point on // the node bounds, otherwise we prolong the last segment to the center line of the node so it doesn't end // outside the node's shape YPoint newPortLocation = segment.IsHorizontal ? new YPoint(pointRel.Y != 0 ? 0 : offsetX, pointRel.Y) : new YPoint(pointRel.X, pointRel.X != 0 ? 0 : offsetY); if (atSource) { graph.SetSourcePointRel(e, newPortLocation); } else { graph.SetTargetPointRel(e, newPortLocation); } }
///<inheritdoc/> public override async Task Start(ILookup newContext) { LayoutGraph layoutGraph = newContext.Lookup <LayoutGraph>(); if (layoutGraph == null) { IGraph graph = newContext.Lookup <IGraph>(); if (graph != null) { await StartWithIGraph(graph, newContext); } } else { try { await base.Start(newContext); } catch (InvalidGraphStructureException wex) { MessageBox.Show("Exception " + wex.Message + " when launching layout algorithm!", "InvalidGraphStructureException", MessageBoxButton.OK, MessageBoxImage.Error); Trace.WriteLine("InvalidGraphStructureException when launching layout algorithm!" + wex.StackTrace); } catch (AlgorithmAbortedException) { //that's ok. do nothing then. throw; } catch (Exception ex) { MessageBox.Show("Exception " + ex.Message + " when launching layout algorithm!\nStackTrace: " + ex.StackTrace, "Exception", MessageBoxButton.OK, MessageBoxImage.Error); //if we are debugging in the IDE, we also want a trace entry Trace.WriteLine("Exception when launching layout algorithm!" + ex.StackTrace); throw; } } }
/// <summary> /// Create a proxy node, i.e., a node that "partially" represents a node of the input graph. /// </summary> /// <remarks> /// This implementation copies the labels of the represented node and applies the <c>ProxyNodeStyle</c>. /// </remarks> /// <param name="pageLayoutGraph">The layout graph representing the current page</param> /// <param name="layoutNode">The node of the layout graph that should be copied</param> /// <param name="pageView">The <see cref="IGraph"/> that is built to show the multi-page layout in a graph canvas</param> /// <returns>The created node</returns> /// <seealso cref="CreateNodeCore"/> protected INode CreateProxyNode(LayoutGraph pageLayoutGraph, Node layoutNode, IGraph pageView) { INode representedNode = GetRepresentedNode(layoutNode); INode viewNode = CreateNodeCore(pageLayoutGraph, pageView, layoutNode, representedNode, true, ProxyNodeDefaults); CopyNodeLabels(pageLayoutGraph, pageView, layoutNode, viewNode, representedNode); return(viewNode); }
/// <summary> /// Create a connector edge. /// </summary> /// <remarks>A connector edge is an edge connected to a connector node, i.e., it represents an edge /// of the input graph whose endpoints lie on different pages. /// </remarks> /// <param name="pageLayoutGraph">The layout graph representing the current page</param> /// <param name="layoutEdge">The edge of the layout graph that should be copied</param> /// <param name="pageView">The <see cref="IGraph"/> that is built to show the multi-page layout in a graph canvas</param> /// <returns>The created edge</returns> /// <seealso cref="CreateEdgeCore"/> protected IEdge CreateConnectorEdge(LayoutGraph pageLayoutGraph, Edge layoutEdge, IGraph pageView) { IEdge representedEdge = GetRepresentedEdge(layoutEdge); IEdge viewEdge = CreateEdgeCore(pageLayoutGraph, pageView, layoutEdge, representedEdge, ConnectorEdgeDefaults); CopyEdgeLabels(pageLayoutGraph, pageView, layoutEdge, viewEdge, representedEdge, ConnectorEdgeDefaults.Labels); return(viewEdge); }
/// <summary> /// Create a normal edge, i.e., an edge that directly corresponds to an edge of the original input graph. /// </summary> /// <param name="pageLayoutGraph">The layout graph representing the current page</param> /// <param name="layoutEdge">The edge of the layout graph that should be copied</param> /// <param name="pageView">The <see cref="IGraph"/> that is built to show the multi-page layout in a graph canvas</param> /// <returns>The created edge</returns> /// <seealso cref="CreateEdgeCore"/> protected IEdge CreateNormalEdge(LayoutGraph pageLayoutGraph, Edge layoutEdge, IGraph pageView) { IEdge modelEdge = GetModelEdge(layoutEdge); IEdge edge = CreateEdgeCore(pageLayoutGraph, pageView, layoutEdge, modelEdge, NormalEdgeDefaults); CopyEdgeLabels(pageLayoutGraph, pageView, layoutEdge, edge, modelEdge, NormalEdgeDefaults.Labels); return(edge); }
public override void ApplyLayout(LayoutGraph graph) { var dataProvider = graph.GetDataProvider(SelectedLabelsAtItemKey); graph.AddDataProvider(ProviderKey, new MyDataProviderAdapter(dataProvider, graph)); ApplyLayoutCore(graph); graph.RemoveDataProvider(ProviderKey); }
/// <summary>Compares two edges by the x-coordinates of the centers of their target nodes.</summary> /// <param name="edge1">the first edge</param> /// <param name="edge2">the second edge</param> /// <returns>a negative value if the first target node is left of the second target node, a positive value if it's the /// other way round and <c>0</c> if both target nodes are at the same x-coordinate</returns> public virtual int Compare(object edge1, object edge2) { Node va = ((Edge)edge1).Target; Node vb = ((Edge)edge2).Target; LayoutGraph graph = (LayoutGraph)va.Graph; return((int)((100.0 * (graph.GetCenterX(va) - graph.GetCenterX(vb))))); }
/// <summary> /// Create a group node, i.e., a node that directly corresponds to a group node of the original input graph. /// </summary> /// <remarks> /// This implementation copies the labels of the corresponding node in the original input graph. /// Also the style of the original node is used for the returned node, unless the <c>GroupNodeStyle</c> is set. /// </remarks> /// <param name="pageLayoutGraph">The layout graph representing the current page</param> /// <param name="layoutNode">The node of the layout graph that should be copied</param> /// <param name="pageView">The <see cref="IGraph"/> that is built to show the multi-page layout in a graph canvas</param> /// <returns>The created node</returns> /// <seealso cref="CreateNodeCore"/> protected INode CreateGroupNode(LayoutGraph pageLayoutGraph, Node layoutNode, IGraph pageView) { INode modelNode = GetModelNode(layoutNode); INode viewNode = CreateNodeCore(pageLayoutGraph, pageView, layoutNode, modelNode, false, GroupNodeDefaults); CopyNodeLabels(pageLayoutGraph, pageView, layoutNode, viewNode, modelNode); return(viewNode); }
/// <summary> /// Removes all edges that are incident to group nodes and passes it to the core layout algorithm. /// </summary> /// <remarks> /// This stage removes some edges from the graph such that no edges incident to group nodes /// exist. Then, it applies the core layout algorithm to the reduced graph. /// After it produces the result, it re-inserts the previously removed edges and routes them. /// </remarks> public override void ApplyLayout(LayoutGraph graph) { var groupingSupport = new yWorks.Layout.Grouping.GroupingSupport(graph); if (!GroupingSupport.IsGrouped(graph)) { ApplyLayoutCore(graph); } else { var hiddenEdgesMap = Maps.CreateHashedEdgeMap(); var edgeHider = new LayoutGraphHider(graph); var existHiddenEdges = false; foreach (var edge in graph.Edges) { if (groupingSupport.IsGroupNode(edge.Source) || groupingSupport.IsGroupNode(edge.Target)) { hiddenEdgesMap.Set(edge, true); edgeHider.Hide(edge); existHiddenEdges = true; } else { hiddenEdgesMap.Set(edge, false); } } ApplyLayoutCore(graph); if (existHiddenEdges) { edgeHider.UnhideAll(); // routes the marked edges RouteMarkedEdges(graph, hiddenEdgesMap); if (ConsiderEdgeLabels) { // all labels of hidden edges should be marked var affectedLabelsDpKey = "affectedLabelsDpKey"; var nonTreeLabelsMap = Maps.CreateHashedDataMap(); foreach (var edge in graph.Edges) { var ell = graph.GetLabelLayout(edge); foreach (var labelLayout in ell) { nonTreeLabelsMap.Set(labelLayout, hiddenEdgesMap.Get(edge)); } } // add selection marker graph.AddDataProvider(affectedLabelsDpKey, nonTreeLabelsMap); // place marked labels var labeling = new GenericLabeling { PlaceNodeLabels = false, PlaceEdgeLabels = true, AffectedLabelsDpKey = affectedLabelsDpKey, }; labeling.ApplyLayout(graph); // dispose selection key graph.RemoveDataProvider(affectedLabelsDpKey); } } } }
/// <summary> /// Copies a single page into the given view graph. /// </summary> /// <param name="pageNo">The page number.</param> /// <param name="mapper">The mapper that is used to store the <see cref="NodeData"/></param> /// <returns>The view graph where the page was created in.</returns> public IGraph CreatePageView(int pageNo, IMapper <INode, NodeData> mapper) { LayoutGraph pageLayoutGraph = result.GetPage(pageNo); IGraph pageView = new DefaultGraph(); pageView.MapperRegistry.AddMapper(MapperKeyNodeData, mapper); CopyPage(pageLayoutGraph, pageView, pageNo, mapper); return(pageView); }
public void AddLayoutGraph(LayoutGraph graph, string hierarchicalLayoutStyle) { TabItem tab = new TabItem { Header = hierarchicalLayoutStyle }; tab.Content = new GraphCanvas(graph); TC_Graphs.Items.Add(tab); }
public override void ApplyLayout(LayoutGraph graph) { foreach (var node in graph.Nodes) { AdjustNodeSize(node, graph); } // run the core layout ApplyLayoutCore(graph); }
private static YOrientedRectangle GetEdgeLabelLocation(LayoutGraph graph, Edge e, IEdgeLabelLayout ell) { YOrientedRectangle ellp = ell.LabelModel.GetLabelPlacement( ell.BoundingBox, graph.GetLayout(e), graph.GetLayout(e.Source), graph.GetLayout(e.Target), ell.ModelParameter); return(ellp); }
/// <summary> /// Returns the calculated location of the edge label. Note that the labeling /// machinery returns the edge labels positions as a parameter /// of the model that belongs to the label. This model parameter can be used /// to retrieve the actual location of the label as shown in this method. /// </summary> private static YPoint GetEdgeLabelLocation(LayoutGraph graph, Edge e, IEdgeLabelLayout ell) { var placement = ell.LabelModel.GetLabelPlacement( ell.BoundingBox, graph.GetLayout(e), graph.GetLayout(e.Source), graph.GetLayout(e.Target), ell.ModelParameter); YPoint ellp = new YPoint(placement.Anchor.X, placement.Anchor.Y - placement.Height); return(ellp); }
/// <summary> /// Copy all labels of the given edge. /// </summary> private void CopyEdgeLabels(LayoutGraph pageLayoutGraph, IGraph pageView, Edge layoutEdge, IEdge copiedEdge, IEdge modelEdge, ILabelDefaults labelDefaults) { IEdgeLabelLayout[] edgeLabels = pageLayoutGraph.GetLabelLayout(layoutEdge); for (int i = 0; i < edgeLabels.Length; i++) { // get the label layout from the layout graph IEdgeLabelLayout edgeLabelLayout = edgeLabels[i]; // get the original label from the model graph ILabel edgeModelLabel = modelEdge.Labels[i]; CopyEdgeLabel(pageView, edgeLabelLayout, edgeModelLabel, copiedEdge, labelDefaults); } }
private void ApplyLabeling(LayoutGraph graph) { GenericLabeling labeling = new GenericLabeling(); labeling.MaximumDuration = 0; labeling.ReduceAmbiguity = true; labeling.PlaceNodeLabels = true; labeling.PlaceEdgeLabels = true; labeling.AffectedLabelsDpKey = AffectedLabelsDpKey; labeling.ProfitModel = new BpmnLabelProfitModel(graph); labeling.CustomProfitModelRatio = 0.15; labeling.ApplyLayout(graph); }
/// <summary> /// Copy all labels of the given node. /// </summary> private void CopyNodeLabels(LayoutGraph pageLayoutGraph, IGraph pageView, Node layoutNode, INode copiedNode, INode modelNode) { INodeLabelLayout[] nodeLabels = pageLayoutGraph.GetLabelLayout(layoutNode); // for each label for (int i = 0; i < nodeLabels.Length; i++) { // get the layout from the layout graph INodeLabelLayout nodeLabelLayout = nodeLabels[i]; // get the original label from the model graph ILabel nodeModelLabel = modelNode.Labels[i]; CopyNodeLabel(pageView, nodeLabelLayout, nodeModelLabel, layoutNode, copiedNode); } }
public void AddLayoutGraph(LayoutGraph graph, String title) { LayoutGraphPanel panel = new LayoutGraphPanel(graph); panel.BorderStyle = BorderStyle.None; TabPage tp = new TabPage(title); tp.Controls.Add(panel); panel.Dock = DockStyle.Fill; this.tabControl.Controls.Add(tp); }
public GraphViewer(LayoutGraph graph, String title) { this.Text = "yFiles LayoutGraph Viewer"; this.AutoScroll = false; InitializeComponent(); if (graph != null) { AddLayoutGraph(graph, title); } }
private void AdjustNodeSize(Node node, LayoutGraph graph) { double width = 60; double height = 40; var leftEdgeSpace = CalcRequiredSpace(node.InEdges, graph); var rightEdgeSpace = CalcRequiredSpace(node.OutEdges, graph); if (LayoutOrientation == LayoutOrientation.TopToBottom || LayoutOrientation == LayoutOrientation.BottomToTop) { // we have to enlarge the width such that the in-/out-edges can be placed side by side without overlaps width = Math.Max(width, leftEdgeSpace); width = Math.Max(width, rightEdgeSpace); } else { // we have to enlarge the height such that the in-/out-edges can be placed side by side without overlaps height = Math.Max(height, leftEdgeSpace); height = Math.Max(height, rightEdgeSpace); } // adjust size for edges with strong port constraints var edgeThicknessDP = graph.GetDataProvider(HierarchicLayout.EdgeThicknessDpKey); if (edgeThicknessDP != null) { foreach (var edge in node.Edges) { var thickness = edgeThicknessDP.GetDouble(edge); var spc = PortConstraint.GetSPC(graph, edge); if (edge.Source == node && spc != null && spc.Strong) { var sourcePoint = graph.GetSourcePointRel(edge); width = Math.Max(width, Math.Abs(sourcePoint.X) * 2 + thickness); height = Math.Max(height, Math.Abs(sourcePoint.Y) * 2 + thickness); } var tpc = PortConstraint.GetTPC(graph, edge); if (edge.Target == node && tpc != null && tpc.Strong) { var targetPoint = graph.GetTargetPointRel(edge); width = Math.Max(width, Math.Abs(targetPoint.X) * 2 + thickness); height = Math.Max(height, Math.Abs(targetPoint.Y) * 2 + thickness); } } } graph.SetSize(node, width, height); }