コード例 #1
0
        ///<summary>
        /// Execute the layout algorithm.
        /// </summary>
        private async Task ApplyLayout()
        {
            var treeLayout = new TreeLayout();
            var executor   = new LayoutExecutor(graphControl, treeLayout)
            {
                AnimateViewport   = true,
                Duration          = TimeSpan.FromMilliseconds(500),
                UpdateContentRect = true,
                LayoutData        = new TreeLayoutData {
                    NodePlacers      = { Mapper = placers },
                    AssistantNodes   = { Mapper = assistants },
                    OutEdgeComparers =
                    {
                        Constant       = (edge1, edge2) => {
                            var value1 = GetOrdinal(edge1);
                            int value2 = GetOrdinal(edge2);
                            return(value1 - value2);
                        }
                    }
                }
            };

            try {
                await executor.Start();
            } catch (Exception e) {
                MessageBox.Show(this,
                                "Layout did not complete successfully.\n" + e.Message);
            }
        }
        /// <summary>
        /// Starts a layout calculation if none is already running.
        /// </summary>
        public async void RunLayout()
        {
            if (layoutIsRunning)
            {
                // if another layout is running: request a new layout and exit
                layoutPending = true;
                return;
            }
            do
            {
                // prevent other layouts from running
                layoutIsRunning = true;
                // clear the pending flag: the requested layout will run now
                layoutPending = false;
                // before the layout run
                OnExecutorStarting();
                await executor.Start();

                // after the layout run
                OnExecutorFinished();
                // free the executor for the next layout
                layoutIsRunning = false;
                // repeat if another layout has been requested in the meantime
            } while (layoutPending);
        }
コード例 #3
0
        /// <summary>
        /// Routes the edges given in the list according to the current
        /// EdgeRouter settings stored in the PolylineEdgeRouterCustomConfig
        /// </summary>
        private async Task RouteAffectedEdges(IEnumerable <IEdge> edges)
        {
            try {
                // route the affected edges
                edgeRouterConfig.ScopeItem = Scope.RouteAffectedEdges;

                // get the layout algorithm with current settings
                var layoutAlgorithm = GetLayoutAlgorithm();

                // create a layout executor with 0.5 seconds execution time and the affected edges
                var layoutExecutor = new LayoutExecutor(graphControl, fullGraph, layoutAlgorithm)
                {
                    LayoutData = new EdgeRouterData {
                        AffectedEdges = { Source = edges }
                    },
                    Duration          = TimeSpan.FromSeconds(0.5),
                    AnimateViewport   = true,
                    EasedAnimation    = true,
                    UpdateContentRect = true
                };

                await layoutExecutor.Start();
            } catch (Exception e) {
                MessageBox.Show(this, "Layout did not complete successfully.\n" + e.Message);
            }
        }
コード例 #4
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();
        }
コード例 #5
0
        /// <summary>
        /// Applies this configuration to the given <see cref="GraphControl"/>.
        /// </summary>
        /// <remarks>
        /// This is the main method of this class. Typically, it calls <see cref="CreateConfiguredLayout"/> to create and
        /// configure a layout and <see cref="CreateConfiguredLayoutData"/> to get a suitable <see cref="LayoutData"/> instance
        /// for the layout.
        /// </remarks>
        /// <param name="graphControl">The <c>GraphControl</c> to apply the configuration on.</param>
        /// <param name="doneHandler">A callback that is called after the configuration is applied. Can be <see langword="null"/></param>
        public virtual async Task Apply(GraphControl graphControl, Action doneHandler)
        {
            if (layoutRunning)
            {
                await graphControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, doneHandler);

                return;
            }

            var layout = CreateConfiguredLayout(graphControl);

            if (layout == null)
            {
                await graphControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, doneHandler);

                return;
            }

            var layoutData = CreateConfiguredLayoutData(graphControl, layout);

            // configure the LayoutExecutor
            var layoutExecutor = new LayoutExecutor(graphControl, new MinimumNodeSizeStage(layout))
            {
                Duration             = TimeSpan.FromSeconds(0.75),
                AnimateViewport      = true,
                EasedAnimation       = true,
                PortAdjustmentPolicy = PortAdjustmentPolicy.Lengthen
            };

            // set the cancel duration for the layout computation to 20s
            layoutExecutor.AbortHandler.CancelDuration = TimeSpan.FromSeconds(20);

            // set the layout data to the LayoutExecutor
            if (layoutData != null)
            {
                layoutExecutor.LayoutData = layoutData;
            }

            // start the LayoutExecutor
            try {
                await layoutExecutor.Start();

                layoutRunning = false;
            } catch (AlgorithmAbortedException) {
                MessageBox.Show(
                    "The layout computation has been canceled because the maximum configured runtime of 20 seconds has been exceeded.");
            } catch (Exception e) {
                MessageBox.Show(
                    "Running the layout has encountered an error: " + e.Message);
            } finally {
                PostProcess(graphControl);
                // clean up mapperRegistry
                graphControl.Graph.MapperRegistry.RemoveMapper(
                    LayoutGraphAdapter.EdgeLabelLayoutPreferredPlacementDescriptorDpKey
                    );
                doneHandler();
            }
        }
        /// <summary>
        /// Applies this configuration to the given <see cref="GraphControl"/>.
        /// </summary>
        /// <remarks>
        /// This is the main method of this class. Typically, it calls <see cref="CreateConfiguredLayout"/> to create and
        /// configure a layout and <see cref="CreateConfiguredLayoutData"/> to get a suitable <see cref="LayoutData"/> instance
        /// for the layout.
        /// </remarks>
        /// <param name="graphControl">The <c>GraphControl</c> to apply the configuration on.</param>
        /// <param name="doneHandler">A callback that is called after the configuration is applied. Can be <see langword="null"/></param>
        public virtual async Task Apply(GraphControl graphControl, Action doneHandler)
        {
            if (layoutRunning)
            {
                graphControl.BeginInvoke(doneHandler);
                return;
            }

            var layout = CreateConfiguredLayout(graphControl);

            if (layout == null)
            {
                graphControl.BeginInvoke(doneHandler);
                return;
            }

            var layoutData = CreateConfiguredLayoutData(graphControl, layout);

            // configure the LayoutExecutor
            var layoutExecutor = new LayoutExecutor(graphControl, new MinimumNodeSizeStage(layout))
            {
                Duration        = TimeSpan.FromSeconds(1),
                AnimateViewport = true
            };

            // set the cancel duration for the layout computation to 20s
            layoutExecutor.AbortHandler.CancelDuration = TimeSpan.FromSeconds(20);

            // set the layout data to the LayoutExecutor
            if (layoutData != null)
            {
                layoutExecutor.LayoutData = layoutData;
            }

            // start the LayoutExecutor
            try {
                await layoutExecutor.Start();

                layoutRunning = false;
            } catch (AlgorithmAbortedException) {
                MessageBox.Show(
                    "The layout computation has been canceled because the maximum configured runtime of 20 seconds has been exceeded.");
            } catch (Exception e) {
                MessageBox.Show(
                    "Running the layout has encountered an error: " + e.Message);
            } finally {
                PostProcess(graphControl);
                doneHandler();
            }
        }
コード例 #7
0
        private async Task RunLayout(ILayoutAlgorithm layout, LayoutData layoutData)
        {
            var executor = new LayoutExecutor(graphControl, layout)
            {
                LayoutData      = layoutData,
                Duration        = TimeSpan.FromMilliseconds(500),
                AnimateViewport = true
            };

            try {
                await executor.Start();
            } catch (Exception e) {
                MessageBox.Show(this, "Layout did not complete successfully.\n" + e.Message);
            }
            EnableButtons();
        }
        /// <summary>
        /// Invokes a layout specified by the current layout type.
        /// </summary>
        /// <remarks>
        /// If there is a fixed node, the layout is calculated incrementally.
        /// </remarks>
        /// <param name="fixedNode">If defined, the layout will be incrementally and this node remains at its location.</param>
        public async Task RunLayout(INode fixedNode = null)
        {
            if (layoutRunning)
            {
                return;
            }
            layoutRunning = true;
            var incremental = fixedNode != null;

            // configure layout
            var layout     = layoutType == LayoutHierarchic ? (ILayoutAlgorithm)GetHierarchicLayout(incremental) : GetOrthogonalLayout();
            var layoutData = layoutType == LayoutHierarchic ? (LayoutData)GetHierarchicLayoutData() : GetOrthogonalLayoutData();

            if (incremental)
            {
                // fixate the location of the given fixed node
                layout = new FixNodeLayoutStage(layout)
                {
                    FixPointPolicy = FixPointPolicy.LowerLeft
                };
                layoutData = new CompositeLayoutData(layoutData,
                                                     new FixNodeLayoutData {
                    FixedNodes = new ItemCollection <INode> {
                        Item = fixedNode
                    }
                }
                                                     );
            }

            EnableUI(false);

            // configure layout execution to not move the view port
            var executor = new LayoutExecutor(graphControl, layout)
            {
                LayoutData        = layoutData,
                AnimateViewport   = !incremental,
                Duration          = TimeSpan.FromMilliseconds(500),
                UpdateContentRect = true,
            };

            // start layout
            await executor.Start();

            layoutRunning = false;
            EnableUI(true);
        }
コード例 #9
0
 /// <summary>
 /// Does the label placement using the generic labeling algorithm. Before this, the model of the labels is
 /// set according to the option handlers settings.
 /// </summary>
 private async Task DoLayout(bool fitViewToContent)
 {
     // fix node layout stage is used to keep the bounding box of the graph in the view port
     var layoutExecutor = new LayoutExecutor(graphControl, new FixNodeLayoutStage(layoutAlgorithm))
     {
         Duration        = TimeSpan.FromMilliseconds(500),
         AnimateViewport = fitViewToContent,
         LayoutData      =
             new CompositeLayoutData(
                 new FixNodeLayoutData {
             FixedNodes = { Delegate = node => true }
         },
                 new LabelingData {
             EdgeLabelPreferredPlacement = { Mapper = descriptorMapper }
         })
     };
     await layoutExecutor.Start();
 }
コード例 #10
0
        /// <summary>
        /// Perform the layout operation
        /// </summary>
        private async Task ApplyLayout(ILayoutAlgorithm layout, LayoutData layoutData, bool animateViewport)
        {
            // layout starting, disable button
            hlLayoutButton.IsEnabled        = false;
            orthoEdgeRouterButton.IsEnabled = false;
            // do the layout
            var executor = new LayoutExecutor(graphControl, layout)
            {
                LayoutData      = layoutData,
                Duration        = TimeSpan.FromSeconds(1),
                AnimateViewport = animateViewport
            };
            await executor.Start();

            // layout finished, enable layout button again
            hlLayoutButton.IsEnabled        = true;
            orthoEdgeRouterButton.IsEnabled = true;
        }
コード例 #11
0
        /// <summary>
        /// Helper method that refreshes the layout after children or parent nodes have been added
        /// or removed.
        /// </summary>
        private async Task RefreshLayout(int count, INode centerNode)
        {
            if (doingLayout)
            {
                return;
            }
            doingLayout = true;
            if (count != hiddenNodesSet.Count)
            {
                // tell our filter to refresh the graph
                filteredGraphWrapper.NodePredicateChanged();
                // the commands CanExecute state might have changed - suggest a requery.
                CommandManager.InvalidateRequerySuggested();

                // now layout the graph in animated fashion
                IGraph tree = graphControl.Graph;

                // configure the layout data
                var layoutData = CreateLayoutData(tree, centerNode);

                // create the layout algorithm (with a stage that fixes the center node in the coordinate system
                var layout = new BendDuplicatorStage(new FixNodeLayoutStage(new TreeLayout()));

                // configure a LayoutExecutor
                var executor = new LayoutExecutor(graphControl, layout)
                {
                    AnimateViewport   = centerNode == null,
                    EasedAnimation    = true,
                    RunInThread       = true,
                    UpdateContentRect = true,
                    LayoutData        = layoutData,
                    Duration          = TimeSpan.FromMilliseconds(500)
                };
                await executor.Start();

                graphControl.Graph.MapperRegistry.RemoveMapper("CenterNode");
                doingLayout = false;
                LimitViewport();
            }
        }
コード例 #12
0
        private async Task RunLayout(bool animateViewport)
        {
            if (currentLayout != null)
            {
                // provide additional data to configure the FixNodeLayoutStage
                FixNodeLayoutData fixNodeLayoutData = new FixNodeLayoutData();
                // specify the node whose position is to be fixed during layout
                fixNodeLayoutData.FixedNodes.Item = toggledNode;

                // run the layout and animate the result
                var layoutExecutor = new LayoutExecutor(graphControl, currentLayout)
                {
                    UpdateContentRect = true,
                    AnimateViewport   = animateViewport,
                    Duration          = TimeSpan.FromSeconds(0.3d),
                    LayoutData        = fixNodeLayoutData
                };
                await layoutExecutor.Start();

                toggledNode = null;
            }
        }
コード例 #13
0
        /// <summary>
        /// Calculates a layout taking the node types into account.
        /// </summary>
        private async Task ApplyLayout(bool animate)
        {
            var sample        = (Sample)SampleGraphComboBox.SelectedItem;
            var considerTypes = ConsiderTypes.IsChecked == true;

            var layout     = sample.Layout;
            var layoutData = considerTypes ? sample.LayoutData : null;

            var layoutExecutor = new LayoutExecutor(graphControl, layout)
            {
                LayoutData           = layoutData,
                Duration             = animate ? TimeSpan.FromMilliseconds(700) : TimeSpan.Zero,
                PortAdjustmentPolicy = PortAdjustmentPolicy.Always,
                RunInThread          = false,
                AnimateViewport      = true
            };

            EnableUi(false);
            await layoutExecutor.Start();

            EnableUi(true);
        }
コード例 #14
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();
        }
コード例 #15
0
        /// <summary>
        /// Starts a layout calculation if none is already running.
        /// </summary>
        public async void RunLayout()
        {
            if (layoutIsRunning)
            {
                // if another layout is running: request a new layout and exit
                layoutPending = true;
                return;
            }
            do
            {
                // prevent other layouts from running
                layoutIsRunning = true;
                // clear the pending flag: the requested layout will run now
                layoutPending = false;
                // start the layout
                if (canceled)
                {
                    // reset to original graph layout
                    executor = CreateCanceledLayoutExecutor();
                }
                else if (finished)
                {
                    // calculate the final layout
                    executor = CreateFinishedLayoutExecutor();
                }
                else
                {
                    // update the location of the components outline
                    UpdateOutline();
                }
                await executor.Start();

                // free the executor for the next layout
                layoutIsRunning = false;
                // repeat if another layout has been requested in the meantime
            } while (layoutPending);
        }
        ///<summary>
        /// Runs either the table or the three tiers layout depending on the selected scenario.
        ///</summary>
        private async Task RunLayout()
        {
            DisableButtons();
            var layoutData = new PartialLayoutData {
                AffectedEdges = { Mapper = partialEdgesMapper },
                AffectedNodes = { Mapper = partialNodesMapper }
            };
            var executor = new LayoutExecutor(
                graphControl, CreateConfiguredPartialLayout())
            {
                Duration        = TimeSpan.FromMilliseconds(500),
                AnimateViewport = true,
                LayoutData      = layoutData
            };

            try {
                await executor.Start();
            } catch (Exception e) {
                MessageBox.Show(this,
                                "Layout did not complete successfully.\n" + e.Message);
            }

            EnableButtons();
        }
コード例 #17
0
        /// <summary>
        /// Does the label placement using the generic labeling algorithm. Before this, the model and size of the labels is
        /// set according to the option handlers settings.
        /// </summary>
        private async Task DoLabelPlacement()
        {
            if (inLayout)
            {
                return;
            }
            inLayout = true;

            toolBar.IsEnabled       = false;
            editorControl.IsEnabled = false;


            //desired label model
            ILabelModel labelModel = LabelModels[(string)handler[LABEL_MODEL].Value];
            int         size       = (int)handler[LABEL_SIZE].Value;

            foreach (var label in graphControl.Graph.Labels)
            {
                if (label.Owner is INode)
                {
                    // only update the label model parameter if the label model changed
                    if (labelModel != graphControl.Graph.NodeDefaults.Labels.LayoutParameter.Model)
                    {
                        graphControl.Graph.SetLabelLayoutParameter(label, labelModel.CreateDefaultParameter());
                    }
                    var cityLabelStyle = label.Style as CityLabelStyle;
                    if (cityLabelStyle != null && cityLabelStyle.InnerLabelStyle is DefaultLabelStyle)
                    {
                        ((DefaultLabelStyle)cityLabelStyle.InnerLabelStyle).TextSize = size;
                    }
                    graphControl.Graph.AdjustLabelPreferredSize(label);
                }
            }
            {
                // set as default label model parameter
                graphControl.Graph.NodeDefaults.Labels.LayoutParameter = labelModel.CreateDefaultParameter();
                var cityLabelStyle = graphControl.Graph.NodeDefaults.Labels.Style as CityLabelStyle;
                if (cityLabelStyle != null && cityLabelStyle.InnerLabelStyle is DefaultLabelStyle)
                {
                    ((DefaultLabelStyle)cityLabelStyle.InnerLabelStyle).TextSize = size;
                }
            }
            graphControl.Invalidate();

            // configure and run the layout algorithm
            var labelingAlgorithm = new GenericLabeling
            {
                MaximumDuration      = 0,
                OptimizationStrategy = OptimizationStrategy.Balanced,
                PlaceEdgeLabels      = false,
                PlaceNodeLabels      = true,
                ReduceLabelOverlaps  = true,
                ProfitModel          = new ExtendedLabelCandidateProfitModel(),
            };

            var layoutExecutor = new LayoutExecutor(graphControl, graphControl.Graph, labelingAlgorithm)
            {
                Duration          = TimeSpan.FromMilliseconds(500),
                EasedAnimation    = true,
                AnimateViewport   = false,
                UpdateContentRect = true
            };

            await layoutExecutor.Start();

            toolBar.IsEnabled       = true;
            editorControl.IsEnabled = true;
            inLayout = false;
        }
        /// <summary>
        /// Does the label placement using the generic labeling algorithm. Before this, the model and size of the labels is
        /// set according to the option handlers settings.
        /// </summary>
        private async Task DoLabelPlacement()
        {
            if (inLayout)
            {
                return;
            }
            inLayout = true;

            toolStrip.Enabled = false;

            //desired label model
            ILabelModel labelModel = LabelModels[labelModelComboBox.SelectedItem.ToString()];
            //desired label size
            int size = Convert.ToInt32(sizeNumericUpDown.NumericUpDownControl.Text);

            foreach (var label in graphControl.Graph.Labels)
            {
                if (label.Owner is INode)
                {
                    // only update the label model parameter if the label model changed
                    if (labelModel != graphControl.Graph.NodeDefaults.Labels.LayoutParameter.Model)
                    {
                        graphControl.Graph.SetLabelLayoutParameter(label, labelModel.CreateDefaultParameter());
                    }
                    var cityLabelStyle = label.Style as CityLabelStyle;
                    if (cityLabelStyle != null && cityLabelStyle.InnerLabelStyle is DefaultLabelStyle)
                    {
                        var font = ((DefaultLabelStyle)cityLabelStyle.InnerLabelStyle).Font;
                        ((DefaultLabelStyle)cityLabelStyle.InnerLabelStyle).Font = new Font(font.FontFamily, size);
                    }
                    graphControl.Graph.AdjustLabelPreferredSize(label);
                }
            }
            {
                // set as default label model parameter
                graphControl.Graph.NodeDefaults.Labels.LayoutParameter = labelModel.CreateDefaultParameter();
                var cityLabelStyle = graphControl.Graph.NodeDefaults.Labels.Style as CityLabelStyle;
                if (cityLabelStyle != null && cityLabelStyle.InnerLabelStyle is DefaultLabelStyle)
                {
                    var font = ((DefaultLabelStyle)cityLabelStyle.InnerLabelStyle).Font;
                    ((DefaultLabelStyle)cityLabelStyle.InnerLabelStyle).Font = new Font(font.FontFamily, size);
                }
            }
            graphControl.Invalidate();

            // configure and run the layout algorithm
            var labelingAlgorithm = new GenericLabeling
            {
                MaximumDuration      = 0,
                OptimizationStrategy = OptimizationStrategy.Balanced,
                PlaceEdgeLabels      = false,
                PlaceNodeLabels      = true,
                ReduceLabelOverlaps  = true,
                ProfitModel          = new ExtendedLabelCandidateProfitModel(),
            };

            var layoutExecutor = new LayoutExecutor(graphControl, graphControl.Graph, labelingAlgorithm)
            {
                Duration          = TimeSpan.FromMilliseconds(500),
                EasedAnimation    = true,
                AnimateViewport   = false,
                UpdateContentRect = true
            };

            await layoutExecutor.Start();

            toolStrip.Enabled = true;
            inLayout          = false;
        }