Example #1
0
        /// <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;
        }