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(); }
/// <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); } } } }
/// <inheritdoc/> public override void AssignLayers(LayoutGraph graph, ILayers layers, ILayoutDataProvider ldp) { // get core layer assignment base.AssignLayers(graph, layers, ldp); // Hide all edges that are no sequence flows var graphHider = new LayoutGraphHider(graph); foreach (var edge in graph.GetEdgeArray()) { if (!BpmnLayout.IsSequenceFlow(edge, graph)) { graphHider.Hide(edge); } } // determine current layer of all nodes currentLayers = new int[graph.NodeCount]; for (int i = 0; i < layers.Size(); i++) { for (INodeCursor nc = layers.GetLayer(i).List.Nodes(); nc.Ok; nc.Next()) { currentLayers[nc.Node.Index] = i; } } // mark nodes on a back-loop and candidates that may be on a back loop if other back-loop nodes are reassigned nodeStates = new NodeState[graph.NodeCount]; NodeList candidates = new NodeList(); NodeList backLoopNodes = new NodeList(); for (int i = layers.Size() - 1; i >= 0; i--) { // check from last to first layer to detect candidates as well NodeList nodes = layers.GetLayer(i).List; UpdateNodeStates(nodes, backLoopNodes, candidates); } // swap layer for back-loop nodes while (backLoopNodes.Count > 0) { for (INodeCursor nc = backLoopNodes.Nodes(); nc.Ok; nc.Next()) { Node node = nc.Node; int currentLayer = currentLayers[node.Index]; // the target layer is the next layer after the highest fixed target node layer int targetLayer = 0; for (Edge edge = node.FirstOutEdge; edge != null; edge = edge.NextOutEdge) { int targetNodeIndex = edge.Target.Index; if (nodeStates[targetNodeIndex] == NodeState.Fixed) { targetLayer = Math.Max(targetLayer, currentLayers[targetNodeIndex] + 1); } } if (targetLayer == 0) { // no fixed target found, so all targets must be candidates // -> we skip the node as we don't know where the candidates will be placed at the end continue; } if (targetLayer < currentLayer) { layers.GetLayer(currentLayer).Remove(node); layers.GetLayer(targetLayer).Add(node); currentLayers[node.Index] = targetLayer; nodeStates[node.Index] = NodeState.Fixed; } } backLoopNodes.Clear(); // update states of the candidates candidates = UpdateNodeStates(candidates, backLoopNodes, new NodeList()); } // remove empty layers for (int i = layers.Size() - 1; i >= 0; i--) { if (layers.GetLayer(i).List.Count == 0) { layers.Remove(i); } } // cleanup graphHider.UnhideAll(); nodeStates = null; currentLayers = null; }