示例#1
0
        /// <summary>
        /// Creates the layout with an appropriate layout data which is selected by the layout combo box.
        /// </summary>
        private void CreateLayout()
        {
            switch (layoutComboBox.SelectedIndex)
            {
            default:
            case 0:
                layout = new HierarchicLayout();
                var hierarchicLayoutData = new HierarchicLayoutData();
                layoutData   = hierarchicLayoutData;
                abortHandler = hierarchicLayoutData.AbortHandler;
                break;

            case 1:
                layout = new OrganicLayout
                {
                    QualityTimeRatio      = 1.0,
                    MaximumDuration       = 1200000,
                    MultiThreadingAllowed = true
                };
                var organicLayoutData = new OrganicLayoutData();
                layoutData   = organicLayoutData;
                abortHandler = organicLayoutData.AbortHandler;
                break;

            case 2:
                layout = new OrthogonalLayout {
                    CrossingReduction = true
                };
                var orthogonalLayoutData = new OrthogonalLayoutData();
                layoutData   = orthogonalLayoutData;
                abortHandler = orthogonalLayoutData.AbortHandler;
                break;
            }
        }
        /// <summary>
        /// Applies the layout.
        /// </summary>
        /// <remarks>
        /// Uses an <see cref="HierarchicLayout"/>. If single graph
        /// items are created or removed, the incremental mode of this layout
        /// algorithm is used to keep most of the current layout of the graph
        /// unchanged.
        /// </remarks>
        /// <param name="incremental">if set to <see langword="true"/> [incremental].</param>
        /// <param name="incrementalNodes">The incremental nodes.</param>
        private async Task ApplyLayout(bool incremental, params EntityData[] incrementalNodes)
        {
            var layout = new HierarchicLayout {
                IntegratedEdgeLabeling = true, OrthogonalRouting = true
            };
            HierarchicLayoutData layoutData = null;

            if (!incremental)
            {
                layout.LayoutMode = LayoutMode.FromScratch;
            }
            else
            {
                layout.LayoutMode = LayoutMode.Incremental;

                if (incrementalNodes.Any())
                {
                    // we need to add hints for incremental nodes
                    layoutData = new HierarchicLayoutData {
                        IncrementalHints = { IncrementalLayeringNodes = { Source = incrementalNodes.Select(graphSource.GetNode) } }
                    };
                }
            }
            await graphControl.MorphLayout(layout, TimeSpan.FromSeconds(1), layoutData);
        }
        /// <summary>
        /// Creates the sample graph.
        /// </summary>
        private void CreateSampleGraph(IGraph graph)
        {
            INode n1, n2, n3, n4;

            layerIndices[n1 = graph.CreateNode()] = 0;
            layerIndices[n2 = graph.CreateNode()] = 1;
            layerIndices[n3 = graph.CreateNode()] = 2;
            layerIndices[n4 = graph.CreateNode()] = 2;

            graph.CreateEdge(n1, n2);
            graph.CreateEdge(n2, n3);
            graph.CreateEdge(n1, n4);

            // create an HierarchicLayout instance to provide an initial layout
            var hl = CreateLayout();

            // use the GivenLayersLayerer to respect the above node to layer assignment
            hl.FromScratchLayerer = new GivenLayersLayerer();

            // provide additional data to configure the layout
            // respect the above node to layer assignment
            var hlData = new HierarchicLayoutData {
                GivenLayersLayererIds = { Mapper = layerIndices }
            };

            // run the layout
            graph.ApplyLayout(hl, hlData);

            // and update the layer visualization
            layerVisualCreator.UpdateLayers(graph, layerIndices);
        }
        /// <summary>
        /// Creates a configured hierarchic layout data.
        /// </summary>
        public HierarchicLayoutData GetHierarchicLayoutData()
        {
            // use preferred placement descriptors to place the labels vertically on the edges
            var layoutData = new HierarchicLayoutData {
                EdgeLabelPreferredPlacement = new ItemMapping <ILabel, PreferredPlacementDescriptor> {
                    Constant = GetPreferredLabelPlacement()
                },
                IncrementalHints = new IncrementalHintItemMapping {
                    ContextDelegate = (item, hintsFactory) =>
                                      item is IEdge?hintsFactory.CreateSequenceIncrementallyHint(item) : null
                }
            };

            return(layoutData);
        }
        /// <summary>
        /// Core method that recalculates and updates the layout.
        /// </summary>
        private async void UpdateLayout(object sender, EventArgs e)
        {
            // make sure we are not reentrant
            if (updateLayout)
            {
                return;
            }
            updateLayout = true;

            // update the layers for moved nodes
            UpdateMovedNodes();

            // create and configure the HierarchicLayout
            var layout = CreateLayout();

            // rearrange only the incremental graph elements, the
            // remaining elements are not, or only slightly, changed
            layout.LayoutMode = LayoutMode.Incremental;
            // use the GivenLayersLayerer for all non-incremental nodes
            layout.FixedElementsLayerer = new GivenLayersLayerer();

            // provide additional data to configure the HierarchicLayout
            var hierarchicLayoutData = new HierarchicLayoutData {
                // specify the layer of each non-incremental node
                GivenLayersLayererIds = { Mapper = layerIndices },
                // retrieve the layer of each incremental node after the layout run to update the layer visualization
                LayerIndices = layerIndices,
                // specify port constrains for the source of each edge
                SourcePortConstraints = { Mapper = sourcePortConstraints },
                // specify port constrains for the target of each edge
                TargetPortConstraints = { Mapper = targetPortConstraints },
                IncrementalHints      =
                {
                    // specify the nodes to rearrange
                    IncrementalLayeringNodes   = { Source = incrementalNodes },
                    // specify the edges to rearrange
                    IncrementalSequencingItems = { Source = incrementalEdges },
                }
            };

            await graphControl.MorphLayout(layout, TimeSpan.FromSeconds(1), hierarchicLayoutData);

            // forget the nodes and edges for the next run
            incrementalNodes.Clear();
            incrementalEdges.Clear();
            layerVisualCreator.UpdateLayers(graphControl.Graph, layerIndices);
            updateLayout = false;
        }
示例#6
0
        /// <summary>
        /// Creates and configures the <see cref="HierarchicLayout"/> and the <see cref="HierarchicLayoutData"/>
        /// such that node types are considered.
        /// </summary>
        private Sample CreateHierarchicSample()
        {
            // create hierarchic layout - no further settings on the algorithm necessary to support types
            var layout = new HierarchicLayout();

            // the node types are specified as delegate on the nodeTypes property of the layout data
            var layoutData = new HierarchicLayoutData {
                NodeTypes = { Delegate = node => GetNodeType(node) }
            };

            return(new Sample {
                Name = "Hierarchic",
                File = "hierarchic",
                Layout = layout,
                LayoutData = layoutData,
                IsDirected = true
            });
        }
        public LayoutData Create(IGraph graph, ISelectionModel <IModelItem> selection, Scope layoutScope)
        {
            var data = new GenericLayoutData();
            var hierarchicLayoutData = new HierarchicLayoutData();

            // check if only selected elements should be laid out
            var layoutOnlySelection = layoutScope == Scope.SelectedElements;

            // mark 'flow' edges, i.e. sequence flows, default flows and conditional flows
            data.AddItemCollection(BpmnLayout.SequenceFlowEdgesDpKey).Delegate = IsSequenceFlow;

            // mark boundary interrupting edges for the BalancingPortOptimizer
            data.AddItemCollection(BpmnLayout.BoundaryInterruptingEdgesDpKey).Delegate = edge => edge.SourcePort.Style is EventPortStyle;



            // mark conversations, events and gateways so their port locations are adjusted
            data.AddItemCollection(PortLocationAdjuster.AffectedNodesDpKey).Delegate = (INode node) =>
                                                                                       (node.Style is ConversationNodeStyle || node.Style is EventNodeStyle || node.Style is GatewayNodeStyle);

            // add NodeHalos around nodes with event ports or specific exterior labels so the layout keeps space for the event ports and labels as well
            AddNodeHalos(data, graph, selection, layoutOnlySelection);

            // add PreferredPlacementDescriptors for labels on sequence, default or conditional flows to place them at source side
            AddEdgeLabelPlacementDescriptors(data);

            // mark nodes, edges and labels as either fixed or affected by the layout and configure port constraints and incremental hints
            MarkFixedAndAffectedItems(data, hierarchicLayoutData, selection, layoutOnlySelection);

            // mark associations and message flows as undirected so they have less impact on layering
            hierarchicLayoutData.EdgeDirectedness.Delegate = edge => (IsMessageFlow(edge) || IsAssociation(edge)) ? 0 : 1;

            // add layer constraints for start events, sub processes and message flows
            AddLayerConstraints(graph, hierarchicLayoutData);

            // add EdgeLayoutDescriptor to specify minimum edge length for edges
            AddMinimumEdgeLength(MinimumEdgeLength, hierarchicLayoutData);


            return(data.CombineWith(hierarchicLayoutData));
        }
        private void AddLayerConstraints(IGraph graph, HierarchicLayoutData hierarchicLayoutData)
        {
            // use layer constraints via HierarchicLayoutData
            var layerConstraintData = hierarchicLayoutData.LayerConstraints;

            foreach (var edge in graph.Edges)
            {
                if (IsMessageFlow(edge) && !CompactMessageFlowLayering)
                {
                    // message flow layering compaction is disabled, we add a 'weak' same layer constraint, i.e. source node shall be placed at
                    // least 0 layers above target node
                    layerConstraintData.PlaceAbove(edge.GetTargetNode(), edge.GetSourceNode(), 0, 1);
                }
                else if (IsSequenceFlow(edge))
                {
                    if ((IsSubprocess(edge.GetSourceNode()) && !(edge.SourcePort.Style is EventPortStyle)) ||
                        IsSubprocess(edge.GetTargetNode()))
                    {
                        // For edges to or from a subprocess that are not attached to an (interrupting) event port, the flow should be considered.
                        // If the subprocess is a group node, any constraints to it are ignored so we have to add the constraints to the content nodes
                        // of the subprocess
                        AddAboveLayerConstraint(layerConstraintData, edge, graph);
                    }
                }
            }

            // if start events should be pulled to the first layer, add PlaceNodeAtTop constraint.
            if (StartNodesFirst)
            {
                foreach (var node in graph.Nodes)
                {
                    if (node.Style is EventNodeStyle &&
                        ((EventNodeStyle)node.Style).Characteristic == EventCharacteristic.Start &&
                        graph.InDegree(node) == 0 &&
                        (graph.GetParent(node) == null || graph.GetParent(node).Style is PoolNodeStyle))
                    {
                        layerConstraintData.PlaceAtTop(node);
                    }
                }
            }
        }
 private void AddMinimumEdgeLength(double minimumEdgeLength, HierarchicLayoutData hierarchicLayoutData)
 {
     // each edge should have a minimum length so that all its labels can be placed on it one
     // after another with a minimum label-to-label distance
     hierarchicLayoutData.EdgeLayoutDescriptors.Delegate = edge => {
         var descriptor = new EdgeLayoutDescriptor {
             RoutingStyle = new RoutingStyle(EdgeRoutingStyle.Orthogonal)
         };
         double minLength = 0;
         foreach (var label in edge.Labels)
         {
             var labelSize = label.GetLayout().GetBounds();
             minLength += Math.Max(labelSize.Width, labelSize.Height);
         }
         if (edge.Labels.Count > 1)
         {
             minLength += (edge.Labels.Count - 1) * MinLabelToLabelDistance;
         }
         descriptor.MinimumLength = Math.Max(minLength, minimumEdgeLength);
         return(descriptor);
     };
 }
示例#10
0
        private async Task ApplyLayout()
        {
            // create a pre-configured HierarchicLayout
            var hl = CreateHierarchicLayout();

            // rearrange only the incremental graph elements, the
            // remaining elements are not, or only slightly, changed
            hl.LayoutMode = LayoutMode.Incremental;

            // provide additional data to configure the HierarchicLayout
            var hlData = new HierarchicLayoutData();

            // specify the nodes to rearrange
            hlData.IncrementalHints.IncrementalLayeringNodes.Source = incrementalNodes;
            // specify the edges to rearrange
            hlData.IncrementalHints.IncrementalSequencingItems.Source = incrementalEdges;

            // append the FixNodeLocationStage to fix the position of the upper right corner
            // of the currently expanded or collapsed group node so that the mouse cursor
            // remains on the expand/collapse button during layout
            var fixNodeLocationStage = new FixNodeLocationStage();

            hl.AppendStage(fixNodeLocationStage);

            // run the layout calculation and animate the result
            var executor = new LayoutExecutor(graphControl, hl)
            {
                AnimateViewport   = false,
                EasedAnimation    = true,
                RunInThread       = true,
                UpdateContentRect = true,
                Duration          = TimeSpan.FromMilliseconds(500),
                LayoutData        = hlData
            };
            // compose layout data from HierarchicLayoutData and FixNodeLayoutData
            await executor.Start();
        }
示例#11
0
        private async Task DoLayout()
        {
            // layout starting, disable button
            layoutButton.IsEnabled = false;

            // create a new layout algorithm
            var hl = new HierarchicLayout
            {
                OrthogonalRouting           = true,
                FromScratchLayeringStrategy = LayeringStrategy.HierarchicalTopmost,
                IntegratedEdgeLabeling      = true
            };

            // and layout data for it
            var hlData = new HierarchicLayoutData {
                ConstraintIncrementalLayererAdditionalEdgeWeights = { Delegate = GetEdgeWeight }
            };

            // we provide the LayerConstraintData.Values directly as IComparable instead of using the Add* methods on LayerConstraintData
            var layerConstraintData = hlData.LayerConstraints;

            layerConstraintData.NodeComparables.Delegate = node => {
                var data = node.Tag as LayerConstraintsInfo;
                if (data != null && data.Constraints)
                {
                    // the node shall be constrained so we use its Value as comparable
                    return(data.Value);
                }
                // otherwise we don't add constraints for the node
                return(null);
            };

            INode[] layerRep = new INode[8];

            // additionally enforce all nodes with a LayerConstraintInfo.Value of 0 or 7 to be placed at top/bottom
            // and all nodes with the same Value in the same layer
            foreach (var node in graphControl.Graph.Nodes)
            {
                var data = node.Tag as LayerConstraintsInfo;
                if (data != null && data.Constraints)
                {
                    if (data.Value == 0)
                    {
                        // add constraint to put this node at the top
                        layerConstraintData.PlaceAtTop(node);
                    }
                    else if (data.Value == 7)
                    {
                        // add constraint to put this node at the bottom
                        layerConstraintData.PlaceAtBottom(node);
                    }
                    if (layerRep[data.Value] == null)
                    {
                        // this is the first node found having this data.Value so we store it as representative
                        layerRep[data.Value] = node;
                    }
                    else
                    {
                        // add constraint to put this node in the same layer as its representative
                        layerConstraintData.PlaceInSameLayer(layerRep[data.Value], node);
                    }
                }
            }

            // perform the layout operation
            await graphControl.MorphLayout(hl, TimeSpan.FromSeconds(1), hlData);

            // code is executed once the layout operation is finished
            // enable button again
            layoutButton.IsEnabled = true;
        }
示例#12
0
            /// <summary>
            /// Creates a new instance configured for the specified graph.
            /// </summary>
            /// <param name="graph">The graph to configure the layout data for</param>
            /// <param name="fromSketch"/> Whether the <see cref="HierarchicLayout"/> shall be run in incremental layout mode.
            public LayoutData(IGraph graph, bool fromSketch)
            {
                // set up port candidates for edges (edges should be attached to the left/right side of the corresponding node
                var candidates = new List <PortCandidate>
                {
                    PortCandidate.CreateCandidate(PortDirections.West),
                    PortCandidate.CreateCandidate(PortDirections.East)
                };

                // configure the different sub group layout settings
                var leftToRightTreeLayout = new TreeReductionStage();

                leftToRightTreeLayout.NonTreeEdgeRouter = leftToRightTreeLayout.CreateStraightLineRouter();
                leftToRightTreeLayout.CoreLayout        = new TreeLayout {
                    LayoutOrientation = LayoutOrientation.LeftToRight,
                };

                var rightToLeftTreeLayout = new TreeReductionStage();

                rightToLeftTreeLayout.NonTreeEdgeRouter = rightToLeftTreeLayout.CreateStraightLineRouter();
                rightToLeftTreeLayout.CoreLayout        = new TreeLayout {
                    LayoutOrientation = LayoutOrientation.RightToLeft,
                };

                var view = graph.Lookup <IFoldingView>();

                Items.Add(new RecursiveGroupLayoutData {
                    SourcePortCandidates = { Constant = candidates },
                    TargetPortCandidates = { Constant = candidates },

                    // map each group node to the layout algorithm that should be used for its content
                    GroupNodeLayouts =
                    {
                        Delegate = node => {
                            switch (GetTierType(node, view, graph))
                            {
                            case TierType.LeftTreeGroupNode:
                                return(leftToRightTreeLayout);

                            case TierType.RightTreeGroupNode:
                                return(rightToLeftTreeLayout);

                            default:
                                return(null);
                            }
                        }
                    }
                });

                var hlData = new HierarchicLayoutData {
                    NodeLayoutDescriptors =
                    {
                        Delegate                   = node => {
                            // align tree group nodes within their layer
                            switch (GetTierType(node, view, graph))
                            {
                            case TierType.LeftTreeGroupNode:
                                return(new NodeLayoutDescriptor {
                                    LayerAlignment = 1
                                });

                            case TierType.RightTreeGroupNode:
                                return(new NodeLayoutDescriptor {
                                    LayerAlignment = 0
                                });

                            default:
                                return(null);
                            }
                        }
                    }
                };

                if (!fromSketch)
                {
                    // insert layer constraints to guarantee the desired placement for "left" and "right" group nodes
                    var layerConstraintData = hlData.LayerConstraints;
                    foreach (var node in graph.Nodes)
                    {
                        // align tree group nodes within their layer
                        TierType type = GetTierType(node, view, graph);
                        if (type == TierType.LeftTreeGroupNode)
                        {
                            layerConstraintData.PlaceAtTop(node);
                        }
                        else if (type == TierType.RightTreeGroupNode)
                        {
                            layerConstraintData.PlaceAtBottom(node);
                        }
                    }
                }
                Items.Add(hlData);
            }
示例#13
0
        protected override LayoutData CreateConfiguredLayoutData(GraphControl graphControl, ILayoutAlgorithm layout)
        {
            var layoutData = new HierarchicLayoutData();

            var incrementalLayout = SelectedElementsIncrementallyItem;
            var selection         = graphControl.Selection;
            var selectedElements  = selection.SelectedEdges.Any() || selection.SelectedNodes.Any();

            if (incrementalLayout && selectedElements)
            {
                // configure the mode
                var ihf = ((HierarchicLayout)layout).CreateIncrementalHintsFactory();
                layoutData.IncrementalHints.Delegate = item => {
                    // Return the correct hint type for each model item that appears in one of these sets
                    if (item is INode && selection.IsSelected(item))
                    {
                        return(ihf.CreateLayerIncrementallyHint(item));
                    }
                    if (item is IEdge && selection.IsSelected(item))
                    {
                        return(ihf.CreateSequenceIncrementallyHint(item));
                    }
                    return(null);
                };
            }

            if (RankingPolicyItem == LayeringStrategy.Bfs)
            {
                layoutData.BfsLayererCoreNodes.Delegate = selection.IsSelected;
            }

            if (GridEnabledItem)
            {
                var nld = ((HierarchicLayout)layout).NodeLayoutDescriptor;
                layoutData.NodeLayoutDescriptors.Delegate = node => {
                    var descriptor = new NodeLayoutDescriptor();
                    descriptor.LayerAlignment     = nld.LayerAlignment;
                    descriptor.MinimumDistance    = nld.MinimumDistance;
                    descriptor.MinimumLayerHeight = nld.MinimumLayerHeight;
                    descriptor.NodeLabelMode      = nld.NodeLabelMode;
                    // anchor nodes on grid according to their alignment within the layer
                    descriptor.GridReference  = new YPoint(0.0, (nld.LayerAlignment - 0.5) * node.Layout.Height);
                    descriptor.PortAssignment = this.GridPortAssignmentItem;
                    return(descriptor);
                };
            }

            if (EdgeDirectednessItem)
            {
                layoutData.EdgeDirectedness.Delegate = edge => {
                    if (edge.Style is IArrowOwner && !Equals(((IArrowOwner)edge.Style).TargetArrow, Arrows.None))
                    {
                        return(1);
                    }
                    return(0);
                };
            }

            if (EdgeThicknessItem)
            {
                layoutData.EdgeThickness.Delegate = edge => {
                    var style = edge.Style as PolylineEdgeStyle;
                    if (style != null)
                    {
                        return(style.Pen.Thickness);
                    }
                    return(1);
                };
            }

            if (SubComponentsItem)
            {
                // layout all siblings with label 'TL' separately with tree layout
                var treeLayout = new TreeLayout {
                    DefaultNodePlacer = new LeftRightNodePlacer()
                };
                foreach (var listOfNodes in FindSubComponents(graphControl.Graph, "TL"))
                {
                    layoutData.SubComponents.Add(treeLayout).Items = listOfNodes;
                }
                // layout all siblings with label 'HL' separately with hierarchical layout
                var hierarchicLayout = new HierarchicLayout {
                    LayoutOrientation = LayoutOrientation.LeftToRight
                };
                foreach (var listOfNodes in FindSubComponents(graphControl.Graph, "HL"))
                {
                    layoutData.SubComponents.Add(hierarchicLayout).Items = listOfNodes;
                }
                // layout all siblings with label 'OL' separately with organic layout
                var organicLayout = new OrganicLayout {
                    PreferredEdgeLength = 100, Deterministic = true
                };
                foreach (var listOfNodes in FindSubComponents(graphControl.Graph, "OL"))
                {
                    layoutData.SubComponents.Add(organicLayout).Items = listOfNodes;
                }
            }

            if (HighlightCriticalPath)
            {
                // highlight the longest path in the graph as critical path
                // since the longest path algorithm only works for acyclic graphs,
                // feedback edges and self loops have to be excluded here
                var feedbackEdgeSetResult = new FeedbackEdgeSet().Run(graphControl.Graph);
                var longestPath           = new LongestPath {
                    SubgraphEdges =
                    {
                        Excludes     =
                        {
                            Delegate = edge => feedbackEdgeSetResult.FeedbackEdgeSet.Contains(edge) || edge.IsSelfloop()
                        }
                    }
                }.Run(graphControl.Graph);
                if (longestPath.Edges.Any())
                {
                    layoutData.CriticalEdgePriorities.Delegate = edge => {
                        if (longestPath.Edges.Contains(edge))
                        {
                            return(10);
                        }
                        return(1);
                    };
                }
            }

            if (AutomaticBusRouting)
            {
                var allBusNodes = new HashSet <INode>();
                foreach (var node in graphControl.Graph.Nodes)
                {
                    if (!graphControl.Graph.IsGroupNode(node) && !allBusNodes.Contains(node))
                    {
                        // search for good opportunities for bus structures rooted at this node
                        if (graphControl.Graph.InDegree(node) >= 4)
                        {
                            var busDescriptor = new BusDescriptor();
                            var busEdges      = GetBusEdges(graphControl.Graph, node, allBusNodes,
                                                            graphControl.Graph.InEdgesAt(node));
                            if (busEdges.Any())
                            {
                                layoutData.Buses.Add(busDescriptor).Items = busEdges;
                            }
                        }
                        if (graphControl.Graph.OutDegree(node) >= 4)
                        {
                            var busDescriptor = new BusDescriptor();
                            var busEdges      = GetBusEdges(graphControl.Graph, node, allBusNodes, graphControl.Graph.OutEdgesAt(node));
                            if (busEdges.Any())
                            {
                                layoutData.Buses.Add(busDescriptor).Items = busEdges;
                            }
                        }
                    }
                }
            }

            return(layoutData.CombineWith(
                       CreateLabelingLayoutData(
                           graphControl.Graph,
                           LabelPlacementAlongEdgeItem,
                           LabelPlacementSideOfEdgeItem,
                           LabelPlacementOrientationItem,
                           LabelPlacementDistanceItem
                           )
                       ));
        }
        private static void MarkFixedAndAffectedItems(GenericLayoutData data, HierarchicLayoutData hierarchicLayoutData, ISelectionModel <IModelItem> graphSelection,
                                                      bool layoutOnlySelection)
        {
            if (layoutOnlySelection)
            {
                var affectedEdges = Mappers.FromDelegate((IEdge edge) =>
                                                         graphSelection.IsSelected(edge) ||
                                                         graphSelection.IsSelected(edge.GetSourceNode()) ||
                                                         graphSelection.IsSelected(edge.GetTargetNode()));
                data.AddItemCollection(LayoutKeys.AffectedEdgesDpKey).Mapper = affectedEdges;

                // fix ports of unselected edges and edges at event ports
                data.AddItemMapping(PortConstraintKeys.SourcePortConstraintDpKey).Delegate =
                    edge =>
                    (!affectedEdges[edge] || edge.SourcePort.Style is EventPortStyle)
              ? PortConstraint.Create(GetSide(edge, true))
              : null;
                data.AddItemMapping(PortConstraintKeys.TargetPortConstraintDpKey).Delegate =
                    edge => !affectedEdges[edge] ? PortConstraint.Create(GetSide(edge, false)) : null;

                // give core layout hints that selected nodes and edges should be incremental
                hierarchicLayoutData.IncrementalHints.ContextDelegate = (item, factory) => {
                    if (item is INode && graphSelection.IsSelected(item))
                    {
                        return(factory.CreateLayerIncrementallyHint(item));
                    }
                    else if (item is IEdge && affectedEdges[(IEdge)item])
                    {
                        return(factory.CreateSequenceIncrementallyHint(item));
                    }
                    return(null);
                };
                data.AddItemCollection(BpmnLayout.AffectedLabelsDpKey).Delegate = label => {
                    var edge = label.Owner as IEdge;
                    if (edge != null)
                    {
                        return(affectedEdges[edge]);
                    }
                    var node = label.Owner as INode;
                    if (node != null)
                    {
                        var  isInnerLabel   = node.Layout.Contains(label.GetLayout().GetCenter());
                        bool isPool         = node.Style is PoolNodeStyle;
                        bool isChoreography = node.Style is ChoreographyNodeStyle;
                        return(!isInnerLabel && !isPool && !isChoreography && graphSelection.IsSelected(node));
                    }
                    return(false);
                };
            }
            else
            {
                // fix source port of edges at event ports
                data.AddItemMapping(PortConstraintKeys.SourcePortConstraintDpKey).Delegate =
                    edge => edge.SourcePort.Style is EventPortStyle?PortConstraint.Create(GetSide(edge, true)) : null;

                data.AddItemCollection(BpmnLayout.AffectedLabelsDpKey).Delegate = label => {
                    if (label.Owner is IEdge)
                    {
                        return(true);
                    }
                    var node = label.Owner as INode;
                    if (node != null)
                    {
                        var  isInnerLabel   = node.Layout.Contains(label.GetLayout().GetCenter());
                        bool isPool         = node.Style is PoolNodeStyle;
                        bool isChoreography = node.Style is ChoreographyNodeStyle;
                        return(!isInnerLabel && !isPool && !isChoreography);
                    }
                    return(false);
                };
            }
        }
示例#15
0
        protected override LayoutData CreateConfiguredLayoutData(GraphControl graphControl, ILayoutAlgorithm layout)
        {
            var layoutData = new HierarchicLayoutData();

            var incrementalLayout = SelectedElementsIncrementallyItem;
            var selection         = graphControl.Selection;
            var selectedElements  = selection.SelectedEdges.Any() || selection.SelectedNodes.Any();

            if (incrementalLayout && selectedElements)
            {
                // configure the mode
                var ihf = ((HierarchicLayout)layout).CreateIncrementalHintsFactory();
                layoutData.IncrementalHints.Delegate = item => {
                    // Return the correct hint type for each model item that appears in one of these sets
                    if (item is INode && selection.IsSelected(item))
                    {
                        return(ihf.CreateLayerIncrementallyHint(item));
                    }
                    if (item is IEdge && selection.IsSelected(item))
                    {
                        return(ihf.CreateSequenceIncrementallyHint(item));
                    }
                    return(null);
                };
            }

            if (RankingPolicyItem == LayeringStrategy.Bfs)
            {
                layoutData.BfsLayererCoreNodes.Delegate = selection.IsSelected;
            }

            if (GridEnabledItem)
            {
                var nld = ((HierarchicLayout)layout).NodeLayoutDescriptor;
                layoutData.NodeLayoutDescriptors.Delegate = node => {
                    var descriptor = new NodeLayoutDescriptor();
                    descriptor.LayerAlignment     = nld.LayerAlignment;
                    descriptor.MinimumDistance    = nld.MinimumDistance;
                    descriptor.MinimumLayerHeight = nld.MinimumLayerHeight;
                    descriptor.NodeLabelMode      = nld.NodeLabelMode;
                    // anchor nodes on grid according to their alignment within the layer
                    descriptor.GridReference  = new YPoint(0.0, (nld.LayerAlignment - 0.5) * node.Layout.Height);
                    descriptor.PortAssignment = this.GridPortAssignmentItem;
                    return(descriptor);
                };
            }

            if (EdgeDirectednessItem)
            {
                layoutData.EdgeDirectedness.Delegate = edge => {
                    if (edge.Style is IArrowOwner && !Equals(((IArrowOwner)edge.Style).TargetArrow, Arrows.None))
                    {
                        return(1);
                    }
                    return(0);
                };
            }

            if (EdgeThicknessItem)
            {
                layoutData.EdgeThickness.Delegate = edge => {
                    var style = edge.Style as PolylineEdgeStyle;
                    if (style != null)
                    {
                        return(style.Pen.Width);
                    }
                    return(1);
                };
            }

            if (SubComponentsItem)
            {
                var treeLayout = new TreeLayout {
                    DefaultNodePlacer = new LeftRightNodePlacer()
                };
                layoutData.SubComponents.Add(treeLayout).Delegate =
                    node => node.Labels.Any() && node.Labels.First().Text == "TL";
                var hierarchicLayout = new HierarchicLayout {
                    LayoutOrientation = LayoutOrientation.LeftToRight
                };
                layoutData.SubComponents.Add(hierarchicLayout).Delegate =
                    node => node.Labels.Any() && node.Labels.First().Text == "HL";
                var organicLayout = new OrganicLayout {
                    PreferredEdgeLength = 100, Deterministic = true
                };
                layoutData.SubComponents.Add(organicLayout).Delegate =
                    node => node.Labels.Any() && node.Labels.First().Text == "OL";
            }

            if (BusesItem)
            {
                // Group edges ending at a node with the label "Bus" into a bus
                layoutData.Buses.Add(new BusDescriptor()).Delegate =
                    edge => edge.GetTargetNode().Labels.Count > 0 && edge.GetTargetNode().Labels[0].Text == "Bus";
            }

            return(layoutData);
        }
        private async Task DoLayout()
        {
            // layout starting, disable button
            runButton.Enabled = false;

            // create a new layout algorithm
            var hl = new HierarchicLayout
            {
                OrthogonalRouting           = true,
                FromScratchLayeringStrategy = LayeringStrategy.HierarchicalTopmost,
                IntegratedEdgeLabeling      = true
            };

            // and layout data for it
            var hlData = new HierarchicLayoutData {
                ConstraintIncrementalLayererAdditionalEdgeWeights = { Delegate = GetEdgeWeight }
            };

            // we provide the LayerConstraintData.Values directly as IComparable instead of using the Add* methods on LayerConstraintData
            var layerConstraintData = hlData.LayerConstraints;

            layerConstraintData.NodeComparables.Delegate = node => {
                var data = node.Tag as LayerConstraintsInfo;
                if (data != null && data.Constraints)
                {
                    // the node shall be constrained so we use its Value as comparable
                    return(data.Value);
                }
                // otherwise we don't add constraints for the node
                return(null);
            };

            INode[] layerRep = new INode[8];

            // additionally enforce all nodes with a LayerConstraintInfo.Value of 0 or 7 to be placed at top/bottom
            // and register the value in the NodeComparables Mapper for all other constrained nodes
            foreach (var node in graphControl.Graph.Nodes)
            {
                var data = node.Tag as LayerConstraintsInfo;
                if (data != null && data.Constraints)
                {
                    if (data.Value == 0)
                    {
                        // add constraint to put this node at the top
                        layerConstraintData.PlaceAtTop(node);
                    }
                    else if (data.Value == 7)
                    {
                        // add constraint to put this node at the bottom
                        layerConstraintData.PlaceAtBottom(node);
                    }
                    else
                    {
                        // for every node in between we record its value with the mapper, assuring that there
                        // will be no layer with different values and monotonically growing values per layer
                        layerConstraintData.NodeComparables.Mapper[node] = data.Value;
                    }
                }
            }

            // perform the layout operation
            await graphControl.MorphLayout(hl, TimeSpan.FromSeconds(1), hlData);

            // code is executed once the layout operation is finished
            // enable button again
            runButton.Enabled = true;
        }