/// <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; }