/// <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);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        /// <summary>
        /// Perform a hierarchic layout that also configures the tables
        /// </summary>
        /// <remarks>Table support is automatically enabled in <see cref="LayoutExecutor"/>. The layout will:
        /// <list type="bullet">
        /// <item>
        /// Arrange all leaf nodes in a hierarchic layout inside their respective table cells
        /// </item>
        /// <item>Resize all table cells to encompass their child nodes. Optionally, <see cref="TableLayoutConfigurator.Compaction"/> allows to shrink table cells, other wise, table cells
        /// can only grow.</item>
        /// </list>
        /// </remarks>
        private async void LayoutButton_Click(object sender, EventArgs e)
        {
            var hl = new HierarchicLayout
            {
                ComponentLayoutEnabled = false,
                LayoutOrientation      = LayoutOrientation.LeftToRight,
                OrthogonalRouting      = true,
                RecursiveGroupLayering = false
            };

            ((SimplexNodePlacer)hl.NodePlacer).BarycenterMode = true;

            //We use Layout executor convenience method that already sets up the whole layout pipeline correctly
            var layoutExecutor = new LayoutExecutor(graphControl, hl)
            {
                //Table layout is enabled by default already...
                ConfigureTableLayout = true,
                Duration             = TimeSpan.FromMilliseconds(500),
                AnimateViewport      = true,
                UpdateContentRect    = true,
                TargetBoundsInsets   = graphEditorInputMode.ContentRectMargins,
                RunInThread          = true,
                //Table cells may only grow by an automatic layout.
                TableLayoutConfigurator = { Compaction = false }
            };
            await layoutExecutor.Start();
        }
 static PartialLayoutForm()
 {
     SubGraphLayouts[LayoutIncremental] = new HierarchicLayout();
     SubGraphLayouts[LayoutOrganic]     = new OrganicLayout();
     SubGraphLayouts[LayoutOrthogonal]  = new OrthogonalLayout();
     SubGraphLayouts[LayoutCircular]    = new CircularLayout();
     SubGraphLayouts[LayoutUnchanged]   = null;
 }
コード例 #5
0
        /// <summary>
        /// Gets the layout algorithm selected by the user.
        /// </summary>
        /// <returns></returns>
        private ILayoutAlgorithm GetLayoutAlgorithm()
        {
            var graph               = graphControl.Graph;
            var item                = layoutChooserBox.SelectedItem as ComboBoxItem;
            var layoutName          = item != null ? item.Tag as String: null;
            ILayoutAlgorithm layout = new HierarchicLayout();

            if (layoutName != null)
            {
                if (layoutName == "hierarchic")
                {
                    layout = new HierarchicLayout();
                }
                else if (layoutName == "organic")
                {
                    layout = new OrganicLayout {
                        PreferredEdgeLength = 1.5 * Math.Max(graph.NodeDefaults.Size.Width, graph.NodeDefaults.Size.Height)
                    };
                }
                else if (layoutName == "orthogonal")
                {
                    layout = new OrthogonalLayout();
                }
                else if (layoutName == "circular")
                {
                    layout = new CircularLayout();
                }
                else if (layoutName == "tree")
                {
                    layout = new TreeReductionStage(new TreeLayout())
                    {
                        NonTreeEdgeRouter = new OrganicEdgeRouter()
                    };
                }
                else if (layoutName == "balloon")
                {
                    layout = new TreeReductionStage(new BalloonLayout())
                    {
                        NonTreeEdgeRouter = new OrganicEdgeRouter()
                    };
                }
                else if (layoutName == "radial")
                {
                    layout = new RadialLayout();
                }
                else if (layoutName == "router-polyline")
                {
                    layout = new EdgeRouter();
                }
                else if (layoutName == "router-organic")
                {
                    layout = new OrganicEdgeRouter {
                        EdgeNodeOverlapAllowed = false
                    };
                }
            }
            return(layout);
        }
コード例 #6
0
        /// <summary>
        /// Gets the layout algorithm selected by the user.
        /// </summary>
        /// <returns></returns>
        private ILayoutAlgorithm GetLayoutAlgorithm()
        {
            var graph               = graphControl.Graph;
            var layoutName          = layoutBox.SelectedItem as string;
            ILayoutAlgorithm layout = new HierarchicLayout();

            if (layoutName != null)
            {
                if (layoutName == "Layout: Hierarchic")
                {
                    layout = new HierarchicLayout();
                }
                else if (layoutName == "Layout: Organic")
                {
                    layout = new OrganicLayout {
                        PreferredEdgeLength = 1.5 * Math.Max(graph.NodeDefaults.Size.Width, graph.NodeDefaults.Size.Height)
                    };
                }
                else if (layoutName == "Layout: Orthogonal")
                {
                    layout = new OrthogonalLayout();
                }
                else if (layoutName == "Layout: Circular")
                {
                    layout = new CircularLayout();
                }
                else if (layoutName == "Layout: Tree")
                {
                    layout = new TreeReductionStage(new TreeLayout())
                    {
                        NonTreeEdgeRouter = new OrganicEdgeRouter()
                    };
                }
                else if (layoutName == "Layout: Balloon")
                {
                    layout = new TreeReductionStage(new BalloonLayout())
                    {
                        NonTreeEdgeRouter = new OrganicEdgeRouter()
                    };
                }
                else if (layoutName == "Layout: Radial")
                {
                    layout = new RadialLayout();
                }
                else if (layoutName == "Routing: Polyline")
                {
                    layout = new EdgeRouter();
                }
                else if (layoutName == "Routing: Organic")
                {
                    layout = new OrganicEdgeRouter {
                        EdgeNodeOverlapAllowed = false
                    };
                }
            }
            return(layout);
        }
コード例 #7
0
        /// <summary>
        /// Performs the layout operation after applying all required constraints
        /// </summary>
        private async Task DoLayout()
        {
            // layout starting, disable button
            runButton.Enabled = false;

            // we want to use the hl
            var hl = new HierarchicLayout()
            {
                OrthogonalRouting = true
            };

            // we only configure sequence constraints, so we can just use a new SequenceConstraintData
            // if HierarchicLayout should be configured further, we could also use HierarchicLayoutData.SequenceConstraintData
            var scData = new SequenceConstraintData {
                // we provide the item Values directly as IComparable instead of using the Add* methods on SequenceConstraintData
                ItemComparables =
                {
                    Delegate     = item => {
                        // get the constraints info for the item
                        // Note that 'item' can be an INode or IEdge but we only use SequenceConstraintsInfo for nodes
                        var data = (item).Tag as SequenceConstraintsInfo;
                        if (data != null && data.Constraints)
                        {
                            // the item shall be constrained so we use its Value as comparable
                            return(data.Value);
                        }
                        // otherwise we don't add constraints for the item
                        return(null);
                    }
                }
            };

            // additionally enforce all nodes with a SequenceConstraintInfo.Value of 0 or 7 to be placed at head/tail
            foreach (var node in graphControl.Graph.Nodes)
            {
                var data = node.Tag as SequenceConstraintsInfo;
                if (data != null && data.Constraints)
                {
                    if (data.Value == 0)
                    {
                        // add constraint to put this node at the head
                        scData.PlaceAtHead(node);
                    }
                    else if (data.Value == 7)
                    {
                        // add constraint to put this node at the tail
                        scData.PlaceAtTail(node);
                    }
                }
            }

            // do the layout
            await graphControl.MorphLayout(hl, TimeSpan.FromSeconds(1), scData);

            // enable button again
            runButton.Enabled = true;
        }
        /// <summary>
        /// Populates the layout combo box.
        /// </summary>
        private void PopulateLayoutComboBox()
        {
            layouts["Hierarchic Layout"] = new HierarchicLayout();
            layouts["Organic Layout"]    = new OrganicLayout {
                MinimumNodeDistance = 40
            };
            layouts["Orthogonal Layout"] = new OrthogonalLayout();

            layoutComboBox.Items.AddRange(layouts.Keys.ToArray());
        }
コード例 #9
0
        private static ILayoutAlgorithm CreateHierarchicLayout(LayoutOrientation layoutOrientation)
        {
            var hl = new HierarchicLayout
            {
                IntegratedEdgeLabeling = true,
                LayoutOrientation      = layoutOrientation
            };

            DisableAutoFlipping(hl);
            return(hl);
        }
コード例 #10
0
        ///<inheritdoc/>
        protected override void ConfigureLayout()
        {
            OptionGroup layoutGroup   = Handler.GetGroupByName(GENERAL);
            var         partialLayout = new PartialLayout
            {
                MinimumNodeDistance   = (int)layoutGroup[MIN_NODE_DIST].Value,
                ConsiderNodeAlignment = (bool)layoutGroup[CONSIDER_SNAPLINES].Value,
                SubgraphPlacement     =
                    subgraphPlacementStrategies[
                        (string)layoutGroup[SUBGRAPH_POSITION_STRATEGY].Value]
            };

            string componentAssignmentStr = (string)layoutGroup[MODE_COMPONENT_ASSIGNMENT].Value;

            partialLayout.ComponentAssignmentStrategy =
                componentAssignment[componentAssignmentStr];

            partialLayout.LayoutOrientation =
                layoutOrientation[(string)layoutGroup[ORIENTATION_MAIN_GRAPH].Value];

            partialLayout.EdgeRoutingStrategy =
                routingStrategies[(string)layoutGroup[ROUTING_TO_SUBGRAPH].Value];

            ILayoutAlgorithm subgraphLayout = null;

            if (componentAssignmentStr != MODE_COMPONENT_SINGLE)
            {
                var subGraphLayoutStr = (string)layoutGroup[SUBGRAPH_LAYOUT].Value;
                switch (subGraphLayoutStr)
                {
                case SUBGRAPH_LAYOUT_IHL:
                    subgraphLayout = new HierarchicLayout();
                    break;

                case SUBGRAPH_LAYOUT_ORGANIC:
                    subgraphLayout = new OrganicLayout();
                    break;

                case SUBGRAPH_LAYOUT_CIRCULAR:
                    subgraphLayout = new CircularLayout();
                    break;

                case SUBGRAPH_LAYOUT_ORTHOGONAL:
                    subgraphLayout = new OrthogonalLayout();
                    break;

                default:
                    break;
                }
            }
            partialLayout.CoreLayout = subgraphLayout;

            LayoutAlgorithm = partialLayout;
        }
コード例 #11
0
        ///<summary>
        /// Creates a new instance of <c>ThreeTierLayout</c>.
        ///</summary>
        /// <param name="fromSketch"/> Whether the <see cref="HierarchicLayout"/> shall be run in incremental layout mode.
        public ThreeTierLayout(bool fromSketch)
        {
            HierarchicLayout hl = new HierarchicLayout
            {
                LayoutOrientation = LayoutOrientation.LeftToRight,
                LayoutMode        = fromSketch ? LayoutMode.Incremental : LayoutMode.FromScratch,
            };
            var rgl = new RecursiveGroupLayout(hl)
            {
                AutoAssignPortCandidates = true, FromSketchMode = true
            };

            CoreLayout = rgl;
        }
コード例 #12
0
 /// <summary>
 /// Creates the core layouts and populates the layouts box
 /// </summary>
 private void InitializeCoreLayouts()
 {
     coreLayouts = new Dictionary <string, ILayoutAlgorithm>();
     coreLayouts["Hierarchic"] = new HierarchicLayout {
         ConsiderNodeLabels = true, IntegratedEdgeLabeling = true, OrthogonalRouting = true
     };
     coreLayouts["Circular"]           = new CircularLayout();
     coreLayouts["Compact Orthogonal"] = new CompactOrthogonalLayout();
     coreLayouts["Organic"]            = new OrganicLayout {
         MinimumNodeDistance = 10, Deterministic = true
     };
     coreLayouts["Orthogonal"]        = new OrthogonalLayout();
     coreLayoutComboBox.ItemsSource   = coreLayouts.Keys;
     coreLayoutComboBox.SelectedIndex = 0;
 }
コード例 #13
0
        public TableLayout(bool fromSketch)
        {
            // incremental hierarchic layout is used for the core layout that connects the table nodes
            var hl = new HierarchicLayout
            {
                LayoutOrientation = LayoutOrientation.LeftToRight,
                LayoutMode        = fromSketch ? LayoutMode.Incremental : LayoutMode.FromScratch,
                OrthogonalRouting = true
            };

            var rgl = new RecursiveGroupLayout(hl)
            {
                AutoAssignPortCandidates = true, FromSketchMode = true
            };

            CoreLayout = rgl;
        }
コード例 #14
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
            });
        }
        /// <summary>
        /// Creates a configured hierarchic layout data.
        /// </summary>
        /// <param name="incremental"><code>true</code> in case the layout should be calculated incrementally.</param>
        public HierarchicLayout GetHierarchicLayout(bool incremental)
        {
            var layout = new HierarchicLayout {
                OrthogonalRouting      = true,
                NodeToEdgeDistance     = 50,
                MinimumLayerDistance   = 40,
                LabelingEnabled        = false,
                IntegratedEdgeLabeling = true,
                ConsiderNodeLabels     = true,
                GridSpacing            = 10
            };

            if (incremental)
            {
                layout.LayoutMode = LayoutMode.Incremental;
            }
            return(layout);
        }
コード例 #16
0
        /// <inheritdoc />
        protected override ILayoutAlgorithm CreateConfiguredLayout(GraphControl graphControl)
        {
            var layout = new PartialLayout();

            layout.ConsiderNodeAlignment       = AlignNodesItem;
            layout.MinimumNodeDistance         = MinimumNodeDistanceItem;
            layout.SubgraphPlacement           = SubgraphPlacementItem;
            layout.ComponentAssignmentStrategy = ComponentAssignmentStrategyItem;
            layout.LayoutOrientation           = OrientationItem;
            layout.EdgeRoutingStrategy         = RoutingToSubgraphItem;
            layout.AllowMovingFixedElements    = MoveFixedElementsItem;

            ILayoutAlgorithm subgraphLayout = null;

            if (ComponentAssignmentStrategyItem != ComponentAssignmentStrategy.Single)
            {
                switch (SubgraphLayoutItem)
                {
                case EnumSubgraphLayouts.Hierarchic:
                    subgraphLayout = new HierarchicLayout();
                    break;

                case EnumSubgraphLayouts.Organic:
                    subgraphLayout = new OrganicLayout();
                    break;

                case EnumSubgraphLayouts.Circular:
                    subgraphLayout = new CircularLayout();
                    break;

                case EnumSubgraphLayouts.Orthogonal:
                    subgraphLayout = new OrthogonalLayout();
                    break;
                }
            }
            layout.CoreLayout = subgraphLayout;

            return(layout);
        }
コード例 #17
0
        public HierarchicLayout ConfigureHierarchicLayout(bool fromSketchMode)
        {
            var hierarchicLayout = new HierarchicLayout
            {
                LayoutOrientation    = LayoutOrientation.LeftToRight,
                LayoutMode           = fromSketchMode ? LayoutMode.Incremental : LayoutMode.FromScratch,
                NodeToNodeDistance   = 30,
                BackLoopRouting      = true,
                EdgeLayoutDescriptor =
                {
                    MinimumFirstSegmentLength = 120,
                    MinimumLastSegmentLength  = 120,
                },
            };

            // a port border gap ratio of zero means that ports can be placed directly on the corners of the nodes
            var portBorderRatio = 1;

            hierarchicLayout.NodeLayoutDescriptor.PortBorderGapRatios = portBorderRatio;
            // configures the generic labeling algorithm which produces more compact results, here
            var genericLabeling = (GenericLabeling)hierarchicLayout.Labeling;

            genericLabeling.ReduceAmbiguity  = false;
            genericLabeling.PlaceNodeLabels  = false;
            genericLabeling.PlaceEdgeLabels  = true;
            hierarchicLayout.LabelingEnabled = true;

            // for Sankey diagrams, the nodes should be adjusted to the incoming/outgoing flow (enlarged if necessary)
            // -> use NodeResizingStage for that purpose
            var nodeResizingStage = new NodeResizingStage(hierarchicLayout);

            nodeResizingStage.LayoutOrientation  = hierarchicLayout.LayoutOrientation;
            nodeResizingStage.PortBorderGapRatio = portBorderRatio;
            hierarchicLayout.PrependStage(nodeResizingStage);

            return(hierarchicLayout);
        }
コード例 #18
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;
        }
コード例 #19
0
        public static void Main()
        {
            DefaultLayoutGraph graph = new DefaultLayoutGraph();

            //construct graph. assign sizes to nodes
            Node v1 = graph.CreateNode();

            graph.SetSize(v1, 30, 30);
            Node v2 = graph.CreateNode();

            graph.SetSize(v2, 30, 30);
            Node v3 = graph.CreateNode();

            graph.SetSize(v3, 30, 30);

            // add a label to one node
            var nodeLabelLayoutModel = new DiscreteNodeLabelLayoutModel(DiscreteNodeLabelPositions.InternalMask, 4);
            var labelLayoutFactory   = LayoutGraphUtilities.GetLabelFactory(graph);

            labelLayoutFactory.AddLabelLayout(v1, labelLayoutFactory.CreateLabelLayout(v1,
                                                                                       new YOrientedRectangle(0, 0, 80, 20), nodeLabelLayoutModel));

            Edge e1 = graph.CreateEdge(v1, v2);
            Edge e2 = graph.CreateEdge(v1, v3);

            // add a label to an edge
            var edgeLabelLayoutModel = new SliderEdgeLabelLayoutModel(SliderMode.Side);

            labelLayoutFactory.AddLabelLayout(e1, labelLayoutFactory.CreateLabelLayout(e1,
                                                                                       new YOrientedRectangle(0, 0, 80, 20), edgeLabelLayoutModel,
                                                                                       PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.LeftOfEdge)));

            //optionally setup some port constraints for HierarchicLayout
            IEdgeMap spc = graph.CreateEdgeMap();
            IEdgeMap tpc = graph.CreateEdgeMap();

            //e1 shall leave and enter the node on the right side
            spc.Set(e1, PortConstraint.Create(PortSide.East, false));
            //additionally set a strong port constraint on the target side.
            tpc.Set(e1, PortConstraint.Create(PortSide.East, true));
            //ports with strong port constraints will not be reset by the
            //layout algorithm.  So we specify the target port right now to connect
            //to the upper left corner of the node
            graph.SetTargetPointRel(e1, new YPoint(15, -15));

            //e2 shall leave and enter the node on the top side
            spc.Set(e2, PortConstraint.Create(PortSide.North, false));
            tpc.Set(e2, PortConstraint.Create(PortSide.North, false));

            graph.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, spc);
            graph.AddDataProvider(PortConstraintKeys.TargetPortConstraintDpKey, tpc);

            HierarchicLayout layout = new HierarchicLayout();

            layout.IntegratedEdgeLabeling = true;
            layout.ConsiderNodeLabels     = true;
            layout.LayoutMode             = LayoutMode.FromScratch;

            new BufferedLayout(layout).ApplyLayout(graph);

            Console.WriteLine("\n\nGRAPH LAID OUT HIERARCHICALLY FROM SCRATCH");
            Console.WriteLine("v1 center position = " + graph.GetCenter(v1));
            Console.WriteLine("v2 center position = " + graph.GetCenter(v2));
            Console.WriteLine("v3 center position = " + graph.GetCenter(v3));
            Console.WriteLine("e1 path = " + graph.GetPath(e1));
            Console.WriteLine("e2 path = " + graph.GetPath(e2));

            //display the graph in a simple viewer
            GraphViewer gv = new GraphViewer();

            gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Before Addition");

            // now add a node and two edges incrementally...
            Node v4 = graph.CreateNode();

            graph.SetSize(v4, 30, 30);

            Edge e4 = graph.CreateEdge(v4, v2);
            Edge e3 = graph.CreateEdge(v1, v4);

            //mark elements as newly added so that the layout algorithm can place
            //them nicely.
            IIncrementalHintsFactory ihf = layout.CreateIncrementalHintsFactory();
            IDataMap map = Maps.CreateHashedDataMap();

            map.Set(v4, ihf.CreateLayerIncrementallyHint(v4));
            map.Set(e3, ihf.CreateSequenceIncrementallyHint(e3));
            map.Set(e4, ihf.CreateSequenceIncrementallyHint(e4));
            graph.AddDataProvider(HierarchicLayout.IncrementalHintsDpKey, map);
            layout.LayoutMode = LayoutMode.Incremental;

            new BufferedLayout(layout).ApplyLayout(graph);

            Console.WriteLine("\n\nGRAPH AFTER ELEMENTS HAVE BEEN ADDED INCREMENTALLY");
            Console.WriteLine("v1 center position = " + graph.GetCenter(v1));
            Console.WriteLine("v2 center position = " + graph.GetCenter(v2));
            Console.WriteLine("v3 center position = " + graph.GetCenter(v3));
            Console.WriteLine("v4 center position = " + graph.GetCenter(v4));
            Console.WriteLine("e1 path = " + graph.GetPath(e1));
            Console.WriteLine("e2 path = " + graph.GetPath(e2));
            Console.WriteLine("e3 path = " + graph.GetPath(e3));
            Console.WriteLine("e4 path = " + graph.GetPath(e4));

            //clean up data maps
            graph.RemoveDataProvider(HierarchicLayout.IncrementalHintsDpKey);

            //display the graph in a simple viewer
            gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "After Addition");
            Application.Run(gv);
        }
コード例 #20
0
        private void SetupLayouts()
        {
            //using hierarchical layout style
            HierarchicLayout hierarchicLayout = new HierarchicLayout();

            hierarchicLayout.EdgeLayoutDescriptor.RoutingStyle = new yWorks.Layout.Hierarchic.RoutingStyle(
                yWorks.Layout.Hierarchic.EdgeRoutingStyle.Orthogonal);

            CurrentLayout = hierarchicLayout;
            layouts.Add("Hierarchic", hierarchicLayout);

            //using organic layout style
            OrganicLayout organic = new OrganicLayout
            {
                QualityTimeRatio       = 1.0,
                NodeOverlapsAllowed    = false,
                NodeEdgeOverlapAvoided = true,
                MinimumNodeDistance    = 10,
                PreferredEdgeLength    = 50,
            };

            layouts.Add("Organic", organic);

            //using orthogonal layout style
            OrthogonalLayout orthogonal = new OrthogonalLayout
            {
                GridSpacing            = 15,
                OptimizePerceivedBends = true
            };

            layouts.Add("Orthogonal", orthogonal);

            //using circular layout style
            CircularLayout circular = new CircularLayout();

            circular.BalloonLayout.MinimumEdgeLength = 50;
            circular.BalloonLayout.CompactnessFactor = 0.1;
            layouts.Add("Circular", circular);

            // a tree layout algorithm
            TreeLayout treeLayout = new TreeLayout {
                ConsiderNodeLabels = true
            };

            treeLayout.AppendStage(new TreeReductionStage()
            {
                NonTreeEdgeRouter       = new OrganicEdgeRouter(),
                NonTreeEdgeSelectionKey = OrganicEdgeRouter.AffectedEdgesDpKey,
            });
            layouts.Add("Tree", treeLayout);

            //using Polyline Router
            var polylineRouter = new EdgeRouter
            {
                Grid            = new Grid(0, 0, 10),
                PolylineRouting = true,
                Rerouting       = true
            };

            polylineRouter.DefaultEdgeLayoutDescriptor.PenaltySettings.BendPenalty         = 3;
            polylineRouter.DefaultEdgeLayoutDescriptor.PenaltySettings.EdgeCrossingPenalty = 5;
            layouts.Add("Polyline Edge Router", polylineRouter);
        }
コード例 #21
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
                           )
                       ));
        }
コード例 #22
0
        public static void Main()
        {
            DefaultLayoutGraph graph = new DefaultLayoutGraph();

            //construct graph and assign sizes to its nodes
            Node[] nodes = new Node[16];
            for (int i = 0; i < 16; i++)
            {
                nodes[i] = graph.CreateNode();
                graph.SetSize(nodes[i], 30, 30);
            }
            graph.CreateEdge(nodes[0], nodes[1]);
            graph.CreateEdge(nodes[0], nodes[2]);
            graph.CreateEdge(nodes[0], nodes[3]);
            graph.CreateEdge(nodes[0], nodes[14]);
            graph.CreateEdge(nodes[2], nodes[4]);
            graph.CreateEdge(nodes[3], nodes[5]);
            graph.CreateEdge(nodes[3], nodes[6]);
            graph.CreateEdge(nodes[3], nodes[9]);
            graph.CreateEdge(nodes[4], nodes[7]);
            graph.CreateEdge(nodes[4], nodes[8]);
            graph.CreateEdge(nodes[5], nodes[9]);
            graph.CreateEdge(nodes[6], nodes[10]);
            graph.CreateEdge(nodes[7], nodes[11]);
            graph.CreateEdge(nodes[8], nodes[12]);
            graph.CreateEdge(nodes[8], nodes[15]);
            graph.CreateEdge(nodes[9], nodes[13]);
            graph.CreateEdge(nodes[10], nodes[13]);
            graph.CreateEdge(nodes[10], nodes[14]);
            graph.CreateEdge(nodes[12], nodes[15]);

            GraphViewer gv = new GraphViewer();

            //using organic layout style
            OrganicLayout organic = new OrganicLayout();

            organic.QualityTimeRatio    = 1.0;
            organic.NodeOverlapsAllowed = false;
            organic.MinimumNodeDistance = 10;
            organic.PreferredEdgeLength = 40;
            new BufferedLayout(organic).ApplyLayout(graph);
            LayoutGraphUtilities.ClipEdgesOnBounds(graph);
            gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Organic Layout Style");

            //using orthogonal edge router (node positions stay fixed)
            EdgeRouter router = new EdgeRouter();

            new BufferedLayout(router).ApplyLayout(graph);
            gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Polyline Edge Router");


            //using orthogonal layout style
            OrthogonalLayout orthogonal = new OrthogonalLayout();

            orthogonal.GridSpacing            = 15;
            orthogonal.OptimizePerceivedBends = true;
            new BufferedLayout(orthogonal).ApplyLayout(graph);
            gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Orthogonal Layout Style");


            //using circular layout style
            CircularLayout circular = new CircularLayout();

            circular.BalloonLayout.MinimumEdgeLength = 20;
            circular.BalloonLayout.CompactnessFactor = 0.1;
            new BufferedLayout(circular).ApplyLayout(graph);
            LayoutGraphUtilities.ClipEdgesOnBounds(graph);
            gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Circular Layout Style");

            //using hierarchical layout style
            var hierarchic = new HierarchicLayout();

            new BufferedLayout(hierarchic).ApplyLayout(graph);
            gv.AddLayoutGraph(graph, "Hierarchical Layout Style");

            var application = new System.Windows.Application();

            application.Run(gv);
        }
コード例 #23
0
        /// <summary>
        /// Creates a small graph and applies a hierarchic group layout to it.
        /// The output of the calculated coordinates will be displayed in the
        /// console.
        /// </summary>
        public void Run()
        {
            DefaultLayoutGraph graph = new DefaultLayoutGraph();

            //construct graph. assign sizes to nodes
            Node v1 = graph.CreateNode();

            graph.SetSize(v1, 30, 30);
            Node v2 = graph.CreateNode();

            graph.SetSize(v2, 30, 30);
            Node v3 = graph.CreateNode();

            graph.SetSize(v3, 30, 30);
            Node v4 = graph.CreateNode();

            graph.SetSize(v4, 30, 30);

            Node groupNode = graph.CreateNode();

            graph.SetSize(groupNode, 100, 100);

            Edge e1 = graph.CreateEdge(v1, v2);
            Edge e2 = graph.CreateEdge(v4, groupNode);
            Edge e3 = graph.CreateEdge(v1, v3);
            Edge e4 = graph.CreateEdge(v1, v1);
            Edge e5 = graph.CreateEdge(v2, groupNode);
            Edge e6 = graph.CreateEdge(groupNode, v2);

            //optionally setup some edge groups
            IEdgeMap spg = graph.CreateEdgeMap();
            IEdgeMap tpg = graph.CreateEdgeMap();

            graph.AddDataProvider(PortConstraintKeys.SourceGroupIdDpKey, spg);
            graph.AddDataProvider(PortConstraintKeys.TargetGroupIdDpKey, tpg);

            spg.Set(e1, "SGroup1");
            spg.Set(e3, "SGroup1");
            tpg.Set(e1, "TGroup1");
            tpg.Set(e3, "TGroup1");

            //optionally setup the node grouping
            INodeMap nodeId       = graph.CreateNodeMap();
            INodeMap parentNodeId = graph.CreateNodeMap();
            INodeMap groupKey     = graph.CreateNodeMap();

            graph.AddDataProvider(GroupingKeys.NodeIdDpKey, nodeId);
            graph.AddDataProvider(GroupingKeys.ParentNodeIdDpKey, parentNodeId);
            graph.AddDataProvider(GroupingKeys.GroupDpKey, groupKey);

            //mark a node as a group node
            groupKey.SetBool(groupNode, true);

            // add ids for each node
            nodeId.Set(v1, "v1");
            nodeId.Set(v2, "v2");
            nodeId.Set(v3, "v3");
            nodeId.Set(v4, "v4");
            nodeId.Set(groupNode, "groupNode");

            // set the parent for each grouped node
            parentNodeId.Set(v2, "groupNode");
            parentNodeId.Set(v3, "groupNode");

            HierarchicLayout layout = new HierarchicLayout();

            layout.MinimumLayerDistance = 0;
            layout.EdgeLayoutDescriptor.MinimumDistance = 10;

            new BufferedLayout(layout).ApplyLayout(graph);

            Console.WriteLine("\n\nGRAPH LAID OUT USING HIERARCHICLAYOUT");
            Console.WriteLine("v1 center position = " + graph.GetCenter(v1));
            Console.WriteLine("v2 center position = " + graph.GetCenter(v2));
            Console.WriteLine("v3 center position = " + graph.GetCenter(v3));
            Console.WriteLine("v4 center position = " + graph.GetCenter(v4));
            Console.WriteLine("group center position = " + graph.GetCenter(groupNode));
            Console.WriteLine("group size = " + graph.GetSize(groupNode));
            Console.WriteLine("e1 path = " + graph.GetPath(e1));
            Console.WriteLine("e2 path = " + graph.GetPath(e2));
            Console.WriteLine("e3 path = " + graph.GetPath(e3));
            Console.WriteLine("e4 path = " + graph.GetPath(e4));
            Console.WriteLine("e5 path = " + graph.GetPath(e5));
            Console.WriteLine("e6 path = " + graph.GetPath(e4));

            //display the result in a simple viewer
            Application.Run(new Demo.yWorks.LayoutGraphViewer.GraphViewer(graph, "Hierarchical Group Layout"));
        }
コード例 #24
0
        ///<inheritdoc/>
        protected override void ConfigureLayout()
        {
            LayoutGraph      graph = CurrentLayoutGraph;
            HierarchicLayout hl    = new HierarchicLayout();

            LayoutAlgorithm = hl;

            //  mark incremental elements if required
            IDataMap    incrementalElements;
            OptionGroup generalGroup  = (OptionGroup)Handler.GetGroupByName(GENERAL);
            OptionGroup currentGroup  = (OptionGroup)generalGroup.GetGroupByName(INTERACTION);
            OptionGroup groupingGroup = (OptionGroup)Handler.GetGroupByName(GROUPING);

            bool fromSketch        = (bool)currentGroup[USE_DRAWING_AS_SKETCH].Value;
            bool incrementalLayout = (bool)currentGroup[SELECTED_ELEMENTS_INCREMENTALLY].Value;
            bool selectedElements  = !IsEdgeSelectionEmpty() || !IsNodeSelectionEmpty();

            if (incrementalLayout && selectedElements)
            {
                // create storage for both nodes and edges
                incrementalElements = Maps.CreateHashedDataMap();
                // configure the mode
                hl.LayoutMode = LayoutMode.Incremental;
                IIncrementalHintsFactory ihf = hl.CreateIncrementalHintsFactory();

                foreach (Node node in graph.Nodes)
                {
                    if (IsSelected(node))
                    {
                        incrementalElements.Set(node, ihf.CreateLayerIncrementallyHint(node));
                    }
                }

                foreach (Edge edge in graph.Edges)
                {
                    if (IsSelected(edge))
                    {
                        incrementalElements.Set(edge, ihf.CreateSequenceIncrementallyHint(edge));
                    }
                }
                graph.AddDataProvider(HierarchicLayout.IncrementalHintsDpKey, incrementalElements);
            }
            else if (fromSketch)
            {
                hl.LayoutMode = LayoutMode.Incremental;
            }
            else
            {
                hl.LayoutMode = LayoutMode.FromScratch;
            }


            // cast to implementation simplex
            var np = (SimplexNodePlacer)hl.NodePlacer;

            np.BarycenterMode  = (bool)generalGroup[SYMMETRIC_PLACEMENT].Value;
            np.StraightenEdges = (bool)Handler.GetValue(EDGE_SETTINGS, EDGE_STRAIGHTENING_OPTIMIZATION_ENABLED);

            hl.ComponentLayoutEnabled = (bool)generalGroup[LAYOUT_COMPONENTS_SEPARATELY].Value;

            currentGroup = (OptionGroup)generalGroup.GetGroupByName(MINIMUM_DISTANCES);

            hl.MinimumLayerDistance = (double)currentGroup[MINIMUM_LAYER_DISTANCE].Value;
            hl.NodeToEdgeDistance   = (double)currentGroup[NODE_TO_EDGE_DISTANCE].Value;
            hl.NodeToNodeDistance   = (double)currentGroup[NODE_TO_NODE_DISTANCE].Value;
            hl.EdgeToEdgeDistance   = (double)currentGroup[EDGE_TO_EDGE_DISTANCE].Value;

            NodeLayoutDescriptor nld = hl.NodeLayoutDescriptor;
            EdgeLayoutDescriptor eld = hl.EdgeLayoutDescriptor;

            currentGroup = (OptionGroup)Handler.GetGroupByName(EDGE_SETTINGS);

            hl.AutomaticEdgeGrouping = (bool)currentGroup[AUTOMATIC_EDGE_GROUPING_ENABLED].Value;

            string edgeRoutingChoice = (string)currentGroup[EDGE_ROUTING].Value;

            eld.RoutingStyle = edgeRoutingEnum[edgeRoutingChoice];
            eld.MinimumFirstSegmentLength = (double)currentGroup[MINIMUM_FIRST_SEGMENT_LENGTH].Value;
            eld.MinimumLastSegmentLength  = (double)currentGroup[MINIMUM_LAST_SEGMENT_LENGTH].Value;

            eld.MinimumDistance = (double)currentGroup[MINIMUM_EDGE_DISTANCE].Value;
            eld.MinimumLength   = (double)currentGroup[MINIMUM_EDGE_LENGTH].Value;

            eld.MinimumSlope = (double)currentGroup[MINIMUM_SLOPE].Value;

            eld.SourcePortOptimization = (bool)currentGroup[PC_OPTIMIZATION_ENABLED].Value;
            eld.TargetPortOptimization = (bool)currentGroup[PC_OPTIMIZATION_ENABLED].Value;

            var isIncrementalModeEnabled = (fromSketch || (incrementalLayout && selectedElements));
            var recursiveRoutingMode     = Handler.GetValue(EDGE_SETTINGS, RECURSIVE_EDGE_ROUTING);

            if (!isIncrementalModeEnabled && recursiveRoutingMode == RECURSIVE_EDGE_ROUTING_DIRECTED)
            {
                eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Directed;
            }
            else if (!isIncrementalModeEnabled && recursiveRoutingMode == RECURSIVE_EDGE_ROUTING_UNDIRECTED)
            {
                eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Undirected;
            }
            else
            {
                eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Off;
            }

            nld.MinimumDistance    = Math.Min(hl.NodeToNodeDistance, hl.NodeToEdgeDistance);
            nld.MinimumLayerHeight = 0;

            OptionGroup rankGroup            = (OptionGroup)Handler.GetGroupByName(RANKS);
            string      layerAlignmentChoice = (string)rankGroup[LAYER_ALIGNMENT].Value;

            nld.LayerAlignment = alignmentEnum[layerAlignmentChoice];

            ol = (OrientationLayout)hl.OrientationLayout;
            string orientationChoice = (string)generalGroup[ORIENTATION].Value;

            ol.Orientation = orientEnum[orientationChoice];

            OptionGroup labelingGroup = (OptionGroup)Handler.GetGroupByName(LABELING);

            currentGroup = (OptionGroup)labelingGroup.GetGroupByName(LABELING_EDGE_PROPERTIES);
            string el = (string)currentGroup[EDGE_LABELING].Value;

            if (!el.Equals(EDGE_LABELING_NONE))
            {
                if (el.Equals(EDGE_LABELING_GENERIC))
                {
                    var la = new GenericLabeling();
                    la.MaximumDuration = 0;
                    la.PlaceNodeLabels = false;
                    la.PlaceEdgeLabels = true;
                    la.AutoFlipping    = true;
                    la.ProfitModel     = new SimpleProfitModel();
                    hl.PrependStage(la);
                }
                else if (el.Equals(EDGE_LABELING_HIERARCHIC))
                {
                    bool copactEdgeLabelPlacement = (bool)currentGroup[COMPACT_EDGE_LABEL_PLACEMENT].Value;
                    if (hl.NodePlacer is SimplexNodePlacer)
                    {
                        np.LabelCompaction = copactEdgeLabelPlacement;
                    }
                    hl.IntegratedEdgeLabeling = true;
                }
            }
            else
            {
                hl.IntegratedEdgeLabeling = false;
            }

            currentGroup = (OptionGroup)labelingGroup.GetGroupByName(NODE_PROPERTIES);
            if ((bool)currentGroup[CONSIDER_NODE_LABELS].Value)
            {
                hl.ConsiderNodeLabels = true;
                hl.NodeLayoutDescriptor.NodeLabelMode = NodeLabelMode.ConsiderForDrawing;
            }
            else
            {
                hl.ConsiderNodeLabels = false;
            }

            string rp = (string)rankGroup[RANKING_POLICY].Value;

            hl.FromScratchLayeringStrategy = rankingPolicies[rp];
            if (rp.Equals(BFS_LAYERS))
            {
                CurrentLayoutGraph.AddDataProvider(BFSLayerer.CoreNodesDpKey, new SelectedNodesDP(this));
            }

            hl.ComponentArrangementPolicy = componentAlignmentEnum[(string)rankGroup[COMPONENT_ARRANGEMENT_POLICY].Value];

            //configure AsIsLayerer
            Object layerer = (hl.LayoutMode == LayoutMode.FromScratch)
                         ? hl.FromScratchLayerer
                         : hl.FixedElementsLayerer;

//      if (layerer is OldLayererWrapper) {
//        layerer = ((OldLayererWrapper)layerer).OldLayerer;
//      }
            if (layerer is AsIsLayerer)
            {
                AsIsLayerer ail = (AsIsLayerer)layerer;
                currentGroup          = (OptionGroup)rankGroup.GetGroupByName(FROM_SKETCH_PROPERTIES);
                ail.NodeHalo          = (double)currentGroup[HALO].Value;
                ail.NodeScalingFactor = (double)currentGroup[SCALE].Value;
                ail.MinimumNodeSize   = (double)currentGroup[MINIMUM_SIZE].Value;
                ail.MaximumNodeSize   = (double)currentGroup[MAXIMUM_SIZE].Value;
            }

            //configure grouping
            np.GroupCompactionStrategy = groupHorizCompactionEnum[(string)groupingGroup[GROUP_HORIZONTAL_COMPACTION].Value];

            if (!fromSketch && groupStrategyEnum[(string)groupingGroup[GROUP_LAYERING_STRATEGY].Value])
            {
                GroupAlignmentPolicy alignmentPolicy = groupAlignmentEnum[(string)groupingGroup[GROUP_ALIGNMENT].Value];
                hl.GroupAlignmentPolicy   = alignmentPolicy;
                hl.CompactGroups          = (bool)groupingGroup[GROUP_ENABLE_COMPACTION].Value;
                hl.RecursiveGroupLayering = true;
            }
            else
            {
                hl.RecursiveGroupLayering = false;
            }

            OptionGroup swimGroup = (OptionGroup)Handler.GetGroupByName(SWIMLANES);

            if ((bool)swimGroup[TREAT_ROOT_GROUPS_AS_SWIMLANES].Value)
            {
                TopLevelGroupToSwimlaneStage stage = new TopLevelGroupToSwimlaneStage();
                stage.OrderSwimlanesFromSketch = (bool)swimGroup[USE_ORDER_FROM_SKETCH].Value;
                stage.Spacing = (double)swimGroup[SWIMLANE_SPACING].Value;
                hl.AppendStage(stage);
            }

            hl.BackLoopRouting = (bool)Handler.GetValue(EDGE_SETTINGS, BACKLOOP_ROUTING);
            hl.MaximumDuration = ((int)Handler.GetValue(GENERAL, MAXIMUM_DURATION)) * 1000;


            bool gridEnabled = (bool)Handler.GetValue(GRID, GRID_ENABLED);

            if (gridEnabled)
            {
                hl.GridSpacing = (double)Handler.GetValue(GRID, GRID_SPACING);
                String             portAssignment = (string)Handler.GetValue(GRID, GRID_PORT_ASSIGNMENT);
                PortAssignmentMode gridPortAssignment;
                switch (portAssignment)
                {
                case GRID_PORT_ASSIGNMENT_ON_GRID:
                    gridPortAssignment = PortAssignmentMode.OnGrid;
                    break;

                case GRID_PORT_ASSIGNMENT_ON_SUBGRID:
                    gridPortAssignment = PortAssignmentMode.OnSubgrid;
                    break;

                default:
                    gridPortAssignment = PortAssignmentMode.Default;
                    break;
                }
                graph.AddDataProvider(HierarchicLayoutCore.NodeLayoutDescriptorDpKey,
                                      new NodeLayoutDescriptorAdapter(hl.NodeLayoutDescriptor, graph, gridPortAssignment));
            }
        }
コード例 #25
0
        public static void Main()
        {
            DefaultLayoutGraph graph = new DefaultLayoutGraph();

            //construct graph. assign sizes to nodes
            Node v1 = graph.CreateNode();

            graph.SetSize(v1, 30, 30);
            Node v2 = graph.CreateNode();

            graph.SetSize(v2, 30, 30);
            Node v3 = graph.CreateNode();

            graph.SetSize(v3, 30, 30);

            Edge e1 = graph.CreateEdge(v1, v2);
            Edge e2 = graph.CreateEdge(v2, v3);
            Edge e3 = graph.CreateEdge(v1, v3);

            //optionally setup some port constraints for HierarchicLayout
            IEdgeMap spc = graph.CreateEdgeMap();
            IEdgeMap tpc = graph.CreateEdgeMap();

            //e1 shall leave and enter the node on the right side
            spc.Set(e1, PortConstraint.Create(PortSide.East));
            //additionally set a strong port constraint on the target side.
            tpc.Set(e1, PortConstraint.Create(PortSide.East, true));
            //ports with strong port constraints will not be reset by the
            //layout algorithm.  So we specify the target port right now to connect
            //to the upper left corner of the node
            graph.SetTargetPointRel(e1, new YPoint(15, -15));

            //e2 shall leave and enter the node on the top side
            spc.Set(e2, PortConstraint.Create(PortSide.North));
            tpc.Set(e2, PortConstraint.Create(PortSide.North));
            //e3 uses no port constraints, i.e. layout will choose best side
            graph.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, spc);
            graph.AddDataProvider(PortConstraintKeys.TargetPortConstraintDpKey, tpc);

            //setup two edge labels for edge e1. The size of the edge labels will be set to
            //80x20. Usually the size of the labels will be determined by
            //calculaing the bounding box of a piece text that is displayed
            //with a specific font.

            var labelFactory = LayoutGraphUtilities.GetLabelFactory(graph);

            graph.SetLabelLayout(e1, new[]
            {
                CreateEdgeLabelLayout(labelFactory, e1,
                                      new SliderEdgeLabelLayoutModel(SliderMode.Center),
                                      PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter)),
                CreateEdgeLabelLayout(labelFactory, e1,
                                      new SliderEdgeLabelLayoutModel(SliderMode.Side),
                                      PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.LeftOfEdge))
            });

            var layout = new HierarchicLayout();

            layout.LabelingEnabled = true;
            layout.Labeling        = new GenericLabeling();

            new BufferedLayout(layout).ApplyLayout(graph);

            Console.WriteLine("\n\nGRAPH LAID OUT USING GENERIC EDGE LABELING");
            Console.WriteLine("v1 center position = " + graph.GetCenter(v1));
            Console.WriteLine("v2 center position = " + graph.GetCenter(v2));
            Console.WriteLine("v3 center position = " + graph.GetCenter(v3));
            Console.WriteLine("e1 path = " + graph.GetPath(e1));
            Console.WriteLine("e2 path = " + graph.GetPath(e2));
            Console.WriteLine("e3 path = " + graph.GetPath(e3));
            Console.WriteLine("ell1 upper left location = " + GetEdgeLabelLocation(graph, e1, CreateEdgeLabelLayout(labelFactory, e1,
                                                                                                                    new SliderEdgeLabelLayoutModel(SliderMode.Center),
                                                                                                                    PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter))));
            Console.WriteLine("ell2 upper left location = " + GetEdgeLabelLocation(graph, e1, graph.GetLabelLayout(e1)[1]));

            GraphViewer gv = new GraphViewer();

            gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Layout with Generic Labeling");

            var freeModel = new FreeEdgeLabelLayoutModel();

            graph.SetLabelLayout(e1, new[]
            {
                CreateEdgeLabelLayout(labelFactory, e1, freeModel,
                                      PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter)),
                CreateEdgeLabelLayout(labelFactory, e1, freeModel,
                                      PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.LeftOfEdge))
            });

            layout.LabelingEnabled = true;
            layout.Labeling        = new LabelLayoutTranslator();

            new BufferedLayout(layout).ApplyLayout(graph);

            Console.WriteLine("\n\nGRAPH LAID OUT USING HIERACHIC LAYOUT SPECIFIC EDGE LABELING");
            Console.WriteLine("v1 center position = " + graph.GetCenter(v1));
            Console.WriteLine("v2 center position = " + graph.GetCenter(v2));
            Console.WriteLine("v3 center position = " + graph.GetCenter(v3));
            Console.WriteLine("e1 path = " + graph.GetPath(e1));
            Console.WriteLine("e2 path = " + graph.GetPath(e2));
            Console.WriteLine("e3 path = " + graph.GetPath(e3));
            Console.WriteLine("ell1 upper left location = " + GetEdgeLabelLocation(graph, e1, CreateEdgeLabelLayout(labelFactory, e1,
                                                                                                                    new SliderEdgeLabelLayoutModel(SliderMode.Center),
                                                                                                                    PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter))));
            Console.WriteLine("ell2 upper left location = " + GetEdgeLabelLocation(graph, e1, graph.GetLabelLayout(e1)[1]));

            //display the result in a simple viewer
            gv.AddLayoutGraph(graph, "Layout with Integrated Labeling");
            var application = new System.Windows.Application();

            application.Run(gv);
        }
コード例 #26
0
        /// <summary>
        /// Perform the layout operation
        /// </summary>
        private async Task ApplyLayout()
        {
            // layout starting, disable button
            layoutButton.IsEnabled = false;

            // create the layout algorithm
            var layout = new HierarchicLayout
            {
                OrthogonalRouting = true,
                LayoutOrientation = LayoutOrientation.TopToBottom
            };

            // do the layout
            await graphControl.MorphLayout(layout,
                                           TimeSpan.FromSeconds(1),
                                           new HierarchicLayoutData {
                //Automatically determine port constraints for source and target
                NodePortCandidateSets =
                {
                    Delegate              = node => {
                        var candidateSet  = new PortCandidateSet();
                        // iterate the port descriptors
                        var descriptors   = PortDescriptor.CreatePortDescriptors(((FlowChartNodeStyle)node.Style).FlowChartType);
                        foreach (var portDescriptor in descriptors)
                        {
                            PortCandidate candidate;
                            // isn't a fixed port candidate (location is variable)
                            if (portDescriptor.X == int.MaxValue)
                            {
                                // create a port candidate at the specified side (east, west, north, south) and apply a cost to it
                                candidate = PortCandidate.CreateCandidate(portDescriptor.Side, portDescriptor.Cost);
                            }
                            else
                            {
                                // create a candidate at a fixed location and side
                                var x     = portDescriptor.X - node.Layout.Width / 2;
                                var y     = portDescriptor.Y - node.Layout.Height / 2;
                                candidate = PortCandidate.CreateCandidate(x, y, portDescriptor.Side, portDescriptor.Cost);
                            }
                            candidateSet.Add(candidate, portDescriptor.Capacity);
                        }
                        return(candidateSet);
                    }
                },
                SourceGroupIds = { Delegate           = edge => {
                                       // create bus-like edge groups for outgoing edges at Start nodes
                                       var sourceNode = edge.SourcePort.Owner as INode;
                                       if (sourceNode != null && ((((FlowChartNodeStyle)sourceNode.Style).FlowChartType)) == FlowChartType.Start)
                                       {
                                           return(sourceNode);
                                       }
                                       return(null);
                                   } },

                TargetGroupIds = { Delegate           = edge => {
                                       // create bus-like edge groups for incoming edges at Branch nodes
                                       var targetNode = edge.TargetPort.Owner as INode;
                                       if (targetNode != null && (((FlowChartNodeStyle)targetNode.Style).FlowChartType) == FlowChartType.Branch)
                                       {
                                           return(targetNode);
                                       }
                                       return(null);
                                   } }
            });

            // enable button again
            layoutButton.IsEnabled = true;
        }
コード例 #27
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);
        }
コード例 #28
0
        /// <inheritdoc />
        protected override ILayoutAlgorithm CreateConfiguredLayout(GraphControl graphControl)
        {
            var layout = new HierarchicLayout();

            //  mark incremental elements if required
            var fromSketch        = UseDrawingAsSketchItem;
            var incrementalLayout = SelectedElementsIncrementallyItem;
            var selectedElements  = graphControl.Selection.SelectedEdges.Any() || graphControl.Selection.SelectedNodes.Any();

            if (incrementalLayout && selectedElements)
            {
                layout.LayoutMode = LayoutMode.Incremental;
            }
            else if (fromSketch)
            {
                layout.LayoutMode = LayoutMode.Incremental;
            }
            else
            {
                layout.LayoutMode = LayoutMode.FromScratch;
            }

            ((SimplexNodePlacer)layout.NodePlacer).BarycenterMode = SymmetricPlacementItem;


            layout.ComponentLayoutEnabled = LayoutComponentsSeparatelyItem;


            layout.MinimumLayerDistance = MinimumLayerDistanceItem;
            layout.NodeToEdgeDistance   = NodeToEdgeDistanceItem;
            layout.NodeToNodeDistance   = NodeToNodeDistanceItem;
            layout.EdgeToEdgeDistance   = EdgeToEdgeDistanceItem;

            var nld = layout.NodeLayoutDescriptor;
            var eld = layout.EdgeLayoutDescriptor;

            layout.AutomaticEdgeGrouping = AutomaticEdgeGroupingEnabledItem;

            eld.RoutingStyle = new RoutingStyle(EdgeRoutingItem);
            eld.RoutingStyle.CurveShortcuts     = CurveShortcutsItem;
            eld.RoutingStyle.CurveUTurnSymmetry = CurveUTurnSymmetryItem;
            eld.MinimumFirstSegmentLength       = MinimumFirstSegmentLengthItem;
            eld.MinimumLastSegmentLength        = MinimumLastSegmentLengthItem;

            eld.MinimumDistance = MinimumEdgeDistanceItem;
            eld.MinimumLength   = MinimumEdgeLengthItem;

            eld.MinimumSlope = MinimumSlopeItem;

            eld.SourcePortOptimization = PcOptimizationEnabledItem;
            eld.TargetPortOptimization = PcOptimizationEnabledItem;

            eld.RecursiveEdgeStyle = RecursiveEdgeStyleItem;

            nld.MinimumDistance    = Math.Min(layout.NodeToNodeDistance, layout.NodeToEdgeDistance);
            nld.MinimumLayerHeight = 0;
            nld.LayerAlignment     = LayerAlignmentItem;


            var ol = (OrientationLayout)layout.OrientationLayout;

            ol.Orientation = OrientationItem;

            if (ConsiderNodeLabelsItem)
            {
                layout.ConsiderNodeLabels = true;
                layout.NodeLayoutDescriptor.NodeLabelMode = NodeLabelMode.ConsiderForDrawing;
            }
            else
            {
                layout.ConsiderNodeLabels = false;
            }

            if (EdgeLabelingItem != EnumEdgeLabeling.None)
            {
                if (EdgeLabelingItem == EnumEdgeLabeling.Generic)
                {
                    layout.IntegratedEdgeLabeling = false;

                    var labeling = new GenericLabeling {
                        PlaceNodeLabels = false,
                        PlaceEdgeLabels = true,
                        AutoFlipping    = true,
                        ReduceAmbiguity = ReduceAmbiguityItem,
                        ProfitModel     = new SimpleProfitModel(),
                    };
                    layout.LabelingEnabled = true;
                    layout.Labeling        = labeling;
                }
                else if (EdgeLabelingItem == EnumEdgeLabeling.Integrated)
                {
                    layout.IntegratedEdgeLabeling = true;
                    ((SimplexNodePlacer)layout.NodePlacer).LabelCompaction = CompactEdgeLabelPlacementItem;
                }
            }
            else
            {
                layout.IntegratedEdgeLabeling = false;
            }

            layout.FromScratchLayeringStrategy = RankingPolicyItem;
            layout.ComponentArrangementPolicy  = ComponentArrangementPolicyItem;
            ((SimplexNodePlacer)layout.NodePlacer).NodeCompaction  = NodeCompactionItem;
            ((SimplexNodePlacer)layout.NodePlacer).StraightenEdges = StraightenEdgesItem;

            //configure AsIsLayerer
            var layerer = layout.LayoutMode == LayoutMode.FromScratch
                         ? layout.FromScratchLayerer
                         : layout.FixedElementsLayerer;
            var ail = layerer as AsIsLayerer;

            if (ail != null)
            {
                ail.NodeHalo          = HaloItem;
                ail.NodeScalingFactor = ScaleItem;
                ail.MinimumNodeSize   = MinimumSizeItem;
                ail.MaximumNodeSize   = MaximumSizeItem;
            }

            //configure grouping
            ((SimplexNodePlacer)layout.NodePlacer).GroupCompactionStrategy = GroupHorizontalCompactionItem;

            if (!fromSketch && GroupLayeringStrategyItem == GroupLayeringStrategyOptions.LayoutGroups)
            {
                layout.GroupAlignmentPolicy   = GroupAlignmentItem;
                layout.CompactGroups          = GroupEnableCompactionItem;
                layout.RecursiveGroupLayering = true;
            }
            else
            {
                layout.RecursiveGroupLayering = false;
            }

            if (TreatRootGroupAsSwimlanesItem)
            {
                var stage = new TopLevelGroupToSwimlaneStage {
                    OrderSwimlanesFromSketch = UseOrderFromSketchItem,
                    Spacing = SwimlineSpacingItem
                };
                layout.AppendStage(stage);
            }

            layout.BackLoopRouting             = BackloopRoutingItem;
            layout.BackLoopRoutingForSelfLoops = BackloopRoutingForSelfLoopsItem;
            layout.MaximumDuration             = MaximumDurationItem * 1000;

            if (GridEnabledItem)
            {
                layout.GridSpacing = GridSpacingItem;
            }

            return(layout);
        }
コード例 #29
0
        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;
        }
コード例 #30
0
        public static void Main()
        {
            DefaultLayoutGraph graph = new DefaultLayoutGraph();

            //construct graph. assign sizes to nodes
            Node v1 = graph.CreateNode();

            graph.SetSize(v1, 30, 30);
            Node v2 = graph.CreateNode();

            graph.SetSize(v2, 30, 30);
            Node v3 = graph.CreateNode();

            graph.SetSize(v3, 30, 30);
            Node v4 = graph.CreateNode();

            graph.SetSize(v4, 30, 30);

            // create some edges...
            Edge e1 = graph.CreateEdge(v1, v2);
            Edge e2 = graph.CreateEdge(v1, v3);
            Edge e3 = graph.CreateEdge(v2, v4);

            // create swim lane descriptors for two lanes
            var sl1 = new SwimlaneDescriptor(1);
            var sl2 = new SwimlaneDescriptor(2);

            // create a map to store the swim lane descriptors
            INodeMap slMap = graph.CreateNodeMap();

            // assign nodes to lanes
            slMap.Set(v1, sl1);
            slMap.Set(v2, sl2);
            slMap.Set(v3, sl2);
            slMap.Set(v4, sl1);

            // register the information
            graph.AddDataProvider(HierarchicLayout.SwimlaneDescriptorDpKey, slMap);

            // create the layout algorithm
            HierarchicLayout layout = new HierarchicLayout();

            // start the layout
            new BufferedLayout(layout).ApplyLayout(graph);


            Console.WriteLine("\n\nGRAPH LAID OUT HIERARCHICALLY IN SWIMLANES");
            Console.WriteLine("v1 center position = " + graph.GetCenter(v1));
            Console.WriteLine("v2 center position = " + graph.GetCenter(v2));
            Console.WriteLine("v3 center position = " + graph.GetCenter(v3));
            Console.WriteLine("v4 center position = " + graph.GetCenter(v4));
            Console.WriteLine("e1 path = " + graph.GetPath(e1));
            Console.WriteLine("e2 path = " + graph.GetPath(e2));
            Console.WriteLine("e3 path = " + graph.GetPath(e3));
            Console.WriteLine("SwimLane 1 index = " + sl1.ComputedLaneIndex);
            Console.WriteLine("SwimLane 1 position = " + sl1.ComputedLanePosition);
            Console.WriteLine("SwimLane 1 width = " + sl1.ComputedLaneWidth);
            Console.WriteLine("SwimLane 2 index = " + sl2.ComputedLaneIndex);
            Console.WriteLine("SwimLane 2 position = " + sl2.ComputedLanePosition);
            Console.WriteLine("SwimLane 2 width = " + sl2.ComputedLaneWidth);

            //clean up data maps
            graph.DisposeNodeMap(slMap);
            graph.RemoveDataProvider(HierarchicLayout.SwimlaneDescriptorDpKey);

            //display the graph in a simple viewer
            var viewer = new GraphViewer();

            viewer.AddLayoutGraph(graph, "Swimlane Demo");
            var application = new System.Windows.Application();

            application.Run(viewer);
        }