diff --git a/Documents/CHANGELOG.txt b/Documents/CHANGELOG.txt index c02d7ac0..cb54a2c0 100644 --- a/Documents/CHANGELOG.txt +++ b/Documents/CHANGELOG.txt @@ -32,6 +32,9 @@ DETAILED CHANGELOG: + Added new EdgeControl template PART (PART_SelfLoopedEdge) for custom self looped edge indicator visualization. It represents FrameworkElement and if specified in the template will be positioned in the top left vertex corner. Also made indicator settings more flexible by implementing some dependency props [WPF, METRO] + Added StateStorage::SaveOrUpdateState() method for easier use [WPF,METRO] ++ Added new readonly property EdgeControl::IsParallel that identifies edge as currently parallel to other edge. Made GraphArea::ParalellizeEdges() method public to be able to refresh IsParallel property on manual graph operations [METRO, WPF] ++ Added EdgeLabelControl::FlipOnRotation dependency property which controls if label should be flipped when axis is changed while rotating [WPF, METRO] ++ Fixed edge routing when graph state has been loaded. Graph state now stores AlgorithmStorage too [ALL] + Fixed ZoomControl zoom out to the value equal to zoom in resulting in similar smooth zoom [WPF, METRO] + Fixed ZoomControl::Zoom cproperty change not firing [WPF, METRO] + Fixed manual graph composition routines in case of ER algorithm is set [ALL] @@ -89,6 +92,7 @@ BREAKING CHANGES: Please renew your custom templates. You can find an example in Generic.XAML template. * Self looped edges display logic has been slightly changed with the introduction of custom template PART (PART_SelfLoopedEdge). Now LogicCore::SelfLoopIndicatorOffset is (0,0) by default and indicator is shown in the top left vertex corner minus indicator size. You can change this behavior by overriding EdgeControl::PrepareSelfLoopedEdge() method. +* GetVertexSizeRectangles() method moved from GraphArea to LogicCore. RELEASE 2.1.8 + Added basic support for Image based edge pointers. Introduced new object for EdgeControl template: [WPF, METRO(bugged)] diff --git a/Examples/METRO.SimpleGraph/MainPage.xaml.cs b/Examples/METRO.SimpleGraph/MainPage.xaml.cs index e47d1f6c..36eed8fe 100644 --- a/Examples/METRO.SimpleGraph/MainPage.xaml.cs +++ b/Examples/METRO.SimpleGraph/MainPage.xaml.cs @@ -57,15 +57,21 @@ void OnFinishedLayout(object sender, EventArgs e) private async void butGenerate_Click(object sender, RoutedEventArgs e) { GraphAreaExample_Setup(); + try + { + await graph.GenerateGraphAsync(); + } + catch (OperationCanceledException) + { + // User may have canceled + } } async void butRelayout_Click(object sender, RoutedEventArgs e) { try { - var t0 = DateTime.Now; await graph.RelayoutGraphAsync(); - Debug.WriteLine("Time elapsed: {0}", DateTime.Now - t0); } catch (OperationCanceledException) { @@ -105,7 +111,7 @@ async void MainPage_Loaded(object sender, RoutedEventArgs e) try { - await graph.GenerateGraphAsync(true); + await graph.GenerateGraphAsync(); } catch (OperationCanceledException) { @@ -270,23 +276,7 @@ private void GraphAreaExample_Setup() { var logicCore = graph.GetLogicCore(); - var dataGraph = GraphExample_Setup(); - logicCore.Graph = dataGraph; - - - /*LogicCore.DefaultLayoutAlgorithmParams = LogicCore.AlgorithmFactory.CreateLayoutParameters(GraphX.LayoutAlgorithmTypeEnum.KK); - ((KKLayoutParameters)LogicCore.DefaultLayoutAlgorithmParams).MaxIterations = 100; - cboxOverlap.SelectedItem = OverlapRemovalAlgorithmTypeEnum.FSA; - - cboxEdgeRouting.SelectedItem = EdgeRoutingAlgorithmTypeEnum.SimpleER; - LogicCore.AsyncAlgorithmCompute = false; - - graph.SetVerticesHighlight(true, GraphControlType.VertexAndEdge, EdgesType.All); - graph.SetEdgesHighlight(true, GraphControlType.VertexAndEdge); - - - - */ + logicCore.Graph = GraphExample_Setup(); switch ((LayoutAlgorithmTypeEnum) cboxLayout.SelectedItem) { @@ -318,13 +308,6 @@ private void GraphAreaExample_Setup() graph.SetVerticesMathShape(VertexShape.Circle); graph.ShowAllVerticesLabels(); graph.ShowAllEdgesLabels(); - - - //graph.MouseOverAnimation = AnimationFactory.CreateMouseOverAnimation(MouseOverAnimation.Scale); - - /*cboxLayout_SelectionChanged(null, null); - cboxOverlap_SelectionChanged(null, null); - cboxEdgeRouting_SelectionChanged(null, null);*/ } void MoveAnimation_Completed(object sender, EventArgs e) diff --git a/Examples/ShowcaseApp.WPF/Models/ShowcaseHelper.cs b/Examples/ShowcaseApp.WPF/Models/ShowcaseHelper.cs index 460d6ec4..cd4557d7 100644 --- a/Examples/ShowcaseApp.WPF/Models/ShowcaseHelper.cs +++ b/Examples/ShowcaseApp.WPF/Models/ShowcaseHelper.cs @@ -38,7 +38,7 @@ public static void AddEdge(BidirectionalGraph graph, DataV Text = string.Empty, SourceConnectionPointId = sourcePoint, TargetConnectionPointId = targetPoint, - ToolTipText = "Default label" + ToolTipText = "Default label "+ source.ID }; graph.AddEdge(edge); diff --git a/Examples/ShowcaseApp.WPF/Pages/Mini/EdgesParallel.xaml.cs b/Examples/ShowcaseApp.WPF/Pages/Mini/EdgesParallel.xaml.cs index 64f3adf5..dce2a356 100644 --- a/Examples/ShowcaseApp.WPF/Pages/Mini/EdgesParallel.xaml.cs +++ b/Examples/ShowcaseApp.WPF/Pages/Mini/EdgesParallel.xaml.cs @@ -53,13 +53,14 @@ private void GenerateGraph() { var logicCore = new LogicCoreExample() { - Graph = ShowcaseHelper.GenerateDataGraph(3, false) + Graph = ShowcaseHelper.GenerateDataGraph(4, false) }; var vList = logicCore.Graph.Vertices.ToList(); //add edges ShowcaseHelper.AddEdge(logicCore.Graph, vList[0], vList[1]); ShowcaseHelper.AddEdge(logicCore.Graph, vList[1], vList[0]); + ShowcaseHelper.AddEdge(logicCore.Graph, vList[2], vList[3]); graphArea.LogicCore = logicCore; //set positions @@ -67,7 +68,8 @@ private void GenerateGraph() { {vList[0], new Point(0, 0)}, {vList[1], new Point(300, 0)}, - {vList[2], new Point(150, 100)}, + {vList[2], new Point(0, 300)}, + {vList[3], new Point(300, 300)}, }; //settings @@ -78,6 +80,11 @@ private void GenerateGraph() //preload graph graphArea.PreloadGraph(posList); //behaviors + var eList = graphArea.EdgesList.Values.ToList(); + eList[0].LabelVerticalOffset = 22; + eList[1].LabelVerticalOffset = 22; + eList[2].LabelVerticalOffset = 22; + graphArea.SetVerticesDrag(true, true); graphArea.ShowAllEdgesLabels(); graphArea.AlignAllEdgesLabels(); diff --git a/GraphX.Controls/Controls/EdgeControlBase.cs b/GraphX.Controls/Controls/EdgeControlBase.cs index 87ab7bd9..fc462c34 100644 --- a/GraphX.Controls/Controls/EdgeControlBase.cs +++ b/GraphX.Controls/Controls/EdgeControlBase.cs @@ -45,6 +45,11 @@ void IPositionChangeNotify.OnPositionChanged() public abstract void Clean(); protected DoubleCollection StrokeDashArray { get; set; } + /// + /// Gets if this edge is parallel (has another edge with the same source and target vertices) + /// + public bool IsParallel { get; internal set; } + /// /// Element presenting self looped edge /// diff --git a/GraphX.Controls/Controls/EdgeLabels/EdgeLabelControl.cs b/GraphX.Controls/Controls/EdgeLabels/EdgeLabelControl.cs index 1a45b80a..42991090 100644 --- a/GraphX.Controls/Controls/EdgeLabels/EdgeLabelControl.cs +++ b/GraphX.Controls/Controls/EdgeLabels/EdgeLabelControl.cs @@ -53,6 +53,27 @@ public bool DisplayForSelfLoopedEdges } } + public static readonly DependencyProperty FlipOnRotationProperty = DependencyProperty.Register("FlipOnRotation", + typeof(bool), + typeof(EdgeLabelControl), + new PropertyMetadata(true)); + /// + /// Gets or sets if label should flip on rotation when axis changes + /// + public bool FlipOnRotation + { + get + { + return (bool)GetValue(FlipOnRotationProperty); + } + set + { + SetValue(FlipOnRotationProperty, value); + } + } + + + public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(double), typeof(EdgeLabelControl), @@ -205,7 +226,7 @@ public virtual void UpdatePosition() { // If we're aligning labels to the edges make sure add the label vertical offset var yEdgeOffset = EdgeControl.LabelVerticalOffset; - if (flipAxis) // If we've flipped axis, move the offset to the other side of the edge + if (FlipOnRotation && flipAxis && !EdgeControl.IsParallel) // If we've flipped axis, move the offset to the other side of the edge yEdgeOffset = -yEdgeOffset; // Adjust offset for rotation. Remember, the offset is perpendicular from the edge tangent. diff --git a/GraphX.Controls/Controls/GraphArea.cs b/GraphX.Controls/Controls/GraphArea.cs index 7c19a3de..efe69be2 100644 --- a/GraphX.Controls/Controls/GraphArea.cs +++ b/GraphX.Controls/Controls/GraphArea.cs @@ -1082,65 +1082,16 @@ private void generateAllEdges(Visibility defaultVisibility = Visibility.Visible) //this.InvalidateVisual(); if (LogicCore.EnableParallelEdges) - ParallelizeEdges(); - if (_svShowEdgeLabels == true && LogicCore.EnableEdgeLabelsOverlapRemoval) - RemoveEdgeLabelsOverlap(); + UpdateParallelEdgesData(); + /*if (_svShowEdgeLabels == true && LogicCore.EnableEdgeLabelsOverlapRemoval) + RemoveEdgeLabelsOverlap();*/ } private void RemoveEdgeLabelsOverlap() { - /* var sz = GetVertexSizeRectangles(); - - var sizes = sz.ToDictionary(item => new LabelOverlapData() {Id = item.Key.ID, IsVertex = true}, item => item.Value); - foreach (var item in EdgesList) - { - item.Value.UpdateLabelLayout(); - sizes.Add(new LabelOverlapData() { Id = item.Key.ID, IsVertex = false }, item.Value.GetLabelSize().ToGraphX()); - } - - var orAlgo = LogicCore.AlgorithmFactory.CreateFSAA(sizes, 15f, 15f); - orAlgo.Compute(CancellationToken.None); - foreach (var item in orAlgo.Rectangles) - { - if (item.Key.IsVertex) - { - var vertex = VertexList.FirstOrDefault(a => a.Key.ID == item.Key.Id).Value; - if (vertex == null) throw new GX_InvalidDataException("RemoveEdgeLabelsOverlap() -> Vertex not found!"); - vertex.SetPosition(item.Value.X + item.Value.Width * .5, item.Value.Y + item.Value.Height * .5); - //vertex.Arrange(item.Value); - } - else - { - var edge = EdgesList.FirstOrDefault(a => a.Key.ID == item.Key.Id).Value; - if (edge == null) throw new GX_InvalidDataException("RemoveEdgeLabelsOverlap() -> Edge not found!"); - edge.SetCustomLabelSize(item.Value.ToWindows()); - } - } - //recalculate route path for new vertex positions - if (LogicCore.AlgorithmStorage.EdgeRouting != null) - { - LogicCore.AlgorithmStorage.EdgeRouting.VertexSizes = GetVertexSizeRectangles(); - LogicCore.AlgorithmStorage.EdgeRouting.VertexPositions = GetVertexPositions(); - LogicCore.AlgorithmStorage.EdgeRouting.Compute(CancellationToken.None); - if (LogicCore.AlgorithmStorage.EdgeRouting.EdgeRoutes != null) - foreach (var item in LogicCore.AlgorithmStorage.EdgeRouting.EdgeRoutes) - item.Key.RoutingPoints = item.Value; - } - foreach (var item in EdgesList) - { - item.Value.PrepareEdgePath(false, null, false); - }*/ - //update edges - // UpdateAllEdges(); } - /* private class LabelOverlapData - { - public bool IsVertex; - public int Id; - }*/ - /// /// Generates all possible valid edges for Graph vertexes /// @@ -1152,10 +1103,17 @@ public void GenerateAllEdges(Visibility defaultVisibility = Visibility.Visible, generateAllEdges(defaultVisibility); } - private void ParallelizeEdges() + /// + /// Update parallel edges information. Only needed to be run when edges has been added manualy and has to track parallel ones. + /// Essentialy refreshes EdgeControl::IsParallel property + /// + public void UpdateParallelEdgesData() { var usedIds = _edgeslist.Count > 20 ? new HashSet() as ICollection : new List(); + //clear IsParallel flag + EdgesList.Values.ForEach(a => a.IsParallel = false); + foreach (var item in EdgesList) { if (usedIds.Contains(item.Key.ID) || !item.Value.CanBeParallel) continue; @@ -1210,6 +1168,7 @@ private void ParallelizeEdges() } //change trigger to opposite viceversa = !viceversa; + list[i].IsParallel = true; } } @@ -1289,7 +1248,7 @@ public void UpdateAllEdges(bool performFullUpdate = false) throw new GX_InvalidDataException("LogicCore -> Not initialized!"); if (LogicCore.EnableParallelEdges) - ParallelizeEdges(); + UpdateParallelEdgesData(); foreach (var ec in _edgeslist.Values) { @@ -1453,20 +1412,9 @@ public void RebuildFromSerializationData(IEnumerable dat private void RestoreAlgorithmStorage() { - //if (LogicCore.AlgorithmStorage.Layout == null) - // { - /*var vPositions = GetVertexPositions(); - var vSizeRectangles = GetVertexSizeRectangles(); - var lay = LogicCore.GenerateLayoutAlgorithm(GetVertexSizes(), GetVertexPositions()); - var or = LogicCore.GenerateOverlapRemovalAlgorithm(vSizeRectangles); - var er = LogicCore.GenerateEdgeRoutingAlgorithm(DesiredSize.ToGraphX(), vPositions, vSizeRectangles); - LogicCore.CreateNewAlgorithmStorage(lay, or, er);*/ - IDictionary vPositions; - var vSizes = GetVertexSizesAndPositions(out vPositions); - + var vSizes = GetVertexSizesAndPositions(out vPositions); LogicCore.GenerateAlgorithmStorage(vSizes, vPositions); - // } } #endregion diff --git a/GraphX.Controls/Models/StateStorage.cs b/GraphX.Controls/Models/StateStorage.cs index a3eef16e..03101f4a 100644 --- a/GraphX.Controls/Models/StateStorage.cs +++ b/GraphX.Controls/Models/StateStorage.cs @@ -65,9 +65,9 @@ private GraphState GenerateGraphState(string id, string if (_area.LogicCore == null) throw new GX_InvalidDataException("LogicCore -> Not initialized!"); var vposlist = _area.VertexList.ToDictionary(item => item.Key, item => item.Value.GetPositionGraphX()); - var vedgelist = (from item in _area.EdgesList where item.Value.Visibility == Visibility.Visible select item.Key).ToList(); + var vedgelist = (from item in _area.EdgesList where item.Value.Visibility == Visibility.Visible select item.Key).ToList(); - return new GraphState(id, _area.LogicCore.Graph, vposlist, vedgelist, description); + return new GraphState(id, _area.LogicCore.Graph, _area.LogicCore.AlgorithmStorage, vposlist, vedgelist, description); } /// @@ -90,6 +90,8 @@ public void LoadState(string id) //One action: clear all, preload vertices, assign Graph property _area.PreloadVertexes(_states[id].Graph, true, true); _area.LogicCore.Graph = _states[id].Graph; + _area.LogicCore.AlgorithmStorage = _states[id].AlgorithmStorage; + //setup vertex positions foreach (var item in _states[id].VertexPositions) { diff --git a/GraphX.Controls/TypeExtensions.cs b/GraphX.Controls/TypeExtensions.cs index 84dd2ddf..e970948f 100644 --- a/GraphX.Controls/TypeExtensions.cs +++ b/GraphX.Controls/TypeExtensions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Media; @@ -83,5 +84,11 @@ public static IEnumerable FindLogicalChildren(this DependencyObject obj) .SelectMany(FindLogicalChildren)) yield return c; } + + public static void ForEach(this IEnumerable list, Action func) + { + foreach (var item in list) + func(item); + } } } diff --git a/GraphX.METRO.Controls/Controls/GraphArea.cs b/GraphX.METRO.Controls/Controls/GraphArea.cs index 073194dc..72a1c551 100644 --- a/GraphX.METRO.Controls/Controls/GraphArea.cs +++ b/GraphX.METRO.Controls/Controls/GraphArea.cs @@ -459,31 +459,6 @@ public Dictionary GetVertexSizesAndPositions(out IDictionary - /// Get visual vertex size rectangles (can be used by some algorithms) - /// - /// Vertex positions collection (auto filled if null) - /// Vertex sizes collection (auto filled if null) - /// True if you want center points returned instead of top-left (needed by overlap removal algo) - public Dictionary GetVertexSizeRectangles(IDictionary positions = null, Dictionary vertexSizes = null, bool getCenterPoints = false) - { - if (LogicCore == null) - throw new GX_InvalidDataException("LogicCore -> Not initialized!"); - - if (vertexSizes == null) vertexSizes = GetVertexSizes(); - if (positions == null) positions = GetVertexPositions(); - var rectangles = new Dictionary(); - foreach (var vertex in LogicCore.Graph.Vertices.Where(vc => vc.SkipProcessing != ProcessingOptionEnum.Exclude)) - { - Measure.Point position; Size size; - if (!positions.TryGetValue(vertex, out position) || !vertexSizes.TryGetValue(vertex, out size)) continue; - if (!getCenterPoints) rectangles[vertex] = new Rect(position.X, position.Y, size.Width, size.Height); - else rectangles[vertex] = new Rect(position.X - size.Width * (float)0.5, position.Y - size.Height * (float)0.5, size.Width, size.Height); - - } - return rectangles; - } - /// /// Returns all vertices positions list /// @@ -1010,65 +985,16 @@ private void generateAllEdges(Visibility defaultVisibility = Visibility.Visible) //this.InvalidateVisual(); if (LogicCore.EnableParallelEdges) - ParallelizeEdges(); - if (_svShowEdgeLabels == true && LogicCore.EnableEdgeLabelsOverlapRemoval) - RemoveEdgeLabelsOverlap(); + UpdateParallelEdgesData(); + //if (_svShowEdgeLabels == true && LogicCore.EnableEdgeLabelsOverlapRemoval) + // RemoveEdgeLabelsOverlap(); } private void RemoveEdgeLabelsOverlap() { - /* var sz = GetVertexSizeRectangles(); - - var sizes = sz.ToDictionary(item => new LabelOverlapData() {Id = item.Key.ID, IsVertex = true}, item => item.Value); - foreach (var item in EdgesList) - { - item.Value.UpdateLabelLayout(); - sizes.Add(new LabelOverlapData() { Id = item.Key.ID, IsVertex = false }, item.Value.GetLabelSize().ToGraphX()); - } - - var orAlgo = LogicCore.AlgorithmFactory.CreateFSAA(sizes, 15f, 15f); - orAlgo.Compute(CancellationToken.None); - foreach (var item in orAlgo.Rectangles) - { - if (item.Key.IsVertex) - { - var vertex = VertexList.FirstOrDefault(a => a.Key.ID == item.Key.Id).Value; - if (vertex == null) throw new GX_InvalidDataException("RemoveEdgeLabelsOverlap() -> Vertex not found!"); - vertex.SetPosition(item.Value.X + item.Value.Width * .5, item.Value.Y + item.Value.Height * .5); - //vertex.Arrange(item.Value); - } - else - { - var edge = EdgesList.FirstOrDefault(a => a.Key.ID == item.Key.Id).Value; - if (edge == null) throw new GX_InvalidDataException("RemoveEdgeLabelsOverlap() -> Edge not found!"); - edge.SetCustomLabelSize(item.Value.ToWindows()); - } - } - //recalculate route path for new vertex positions - if (LogicCore.AlgorithmStorage.EdgeRouting != null) - { - LogicCore.AlgorithmStorage.EdgeRouting.VertexSizes = GetVertexSizeRectangles(); - LogicCore.AlgorithmStorage.EdgeRouting.VertexPositions = GetVertexPositions(); - LogicCore.AlgorithmStorage.EdgeRouting.Compute(CancellationToken.None); - if (LogicCore.AlgorithmStorage.EdgeRouting.EdgeRoutes != null) - foreach (var item in LogicCore.AlgorithmStorage.EdgeRouting.EdgeRoutes) - item.Key.RoutingPoints = item.Value; - } - foreach (var item in EdgesList) - { - item.Value.PrepareEdgePath(false, null, false); - }*/ - //update edges - // UpdateAllEdges(); } - /* private class LabelOverlapData - { - public bool IsVertex; - public int Id; - }*/ - /// /// Generates all possible valid edges for Graph vertexes /// @@ -1080,10 +1006,17 @@ public void GenerateAllEdges(Visibility defaultVisibility = Visibility.Visible, generateAllEdges(defaultVisibility); } - private void ParallelizeEdges() + /// + /// Update parallel edges information. Only needed to be run if manualy add edges and need to track parallel ones. + /// Essentialy refreshes EdgeControl::IsParallel property + /// + public void UpdateParallelEdgesData() { var usedIds = _edgeslist.Count > 20 ? new HashSet() as ICollection : new List(); + //clear IsParallel flag + EdgesList.Values.ForEach(a=> a.IsParallel = false); + foreach (var item in EdgesList) { if (usedIds.Contains(item.Key.ID) || !item.Value.CanBeParallel) continue; @@ -1138,6 +1071,7 @@ private void ParallelizeEdges() } //change trigger to opposite viceversa = !viceversa; + list[i].IsParallel = true; } } @@ -1216,7 +1150,7 @@ public void UpdateAllEdges(bool performFullUpdate = false) if (LogicCore == null) throw new GX_InvalidDataException("LogicCore -> Not initialized!"); if (LogicCore.EnableParallelEdges) - ParallelizeEdges(); + UpdateParallelEdgesData(); foreach (var ec in _edgeslist.Values) { if (!performFullUpdate) ec.UpdateEdgeRendering(); @@ -1375,12 +1309,9 @@ public void RebuildFromSerializationData(IEnumerable dat private void RestoreAlgorithmStorage() { - var vPositions = GetVertexPositions(); - var vSizeRectangles = GetVertexSizeRectangles(); - var lay = LogicCore.GenerateLayoutAlgorithm(GetVertexSizes(), GetVertexPositions()); - var or = LogicCore.GenerateOverlapRemovalAlgorithm(vSizeRectangles); - var er = LogicCore.GenerateEdgeRoutingAlgorithm(DesiredSize.ToGraphX(), vPositions, vSizeRectangles); - LogicCore.CreateNewAlgorithmStorage(lay, or, er); + IDictionary vertexPositions; + var vertexSizes = GetVertexSizesAndPositions(out vertexPositions); + LogicCore.GenerateAlgorithmStorage(vertexSizes, vertexPositions); } #endregion diff --git a/GraphX.PCL.Common/GraphX.PCL.Common.csproj b/GraphX.PCL.Common/GraphX.PCL.Common.csproj index 8e2951ce..dac2272f 100644 --- a/GraphX.PCL.Common/GraphX.PCL.Common.csproj +++ b/GraphX.PCL.Common/GraphX.PCL.Common.csproj @@ -74,8 +74,6 @@ - - diff --git a/GraphX.PCL.Common/Interfaces/IAlgorithmStorage.cs b/GraphX.PCL.Common/Interfaces/IAlgorithmStorage.cs index 63cf84cc..6b21c014 100644 --- a/GraphX.PCL.Common/Interfaces/IAlgorithmStorage.cs +++ b/GraphX.PCL.Common/Interfaces/IAlgorithmStorage.cs @@ -1,9 +1,25 @@ namespace GraphX.PCL.Common.Interfaces { + /// + /// Base level interface for algorithm storage implementation + /// + /// Vertex data class + /// Edge data class public interface IAlgorithmStorage { + /// + /// Gets layout algorithm + /// IExternalLayout Layout { get; } + + /// + /// Gets overlap removal algorithm + /// IExternalOverlapRemoval OverlapRemoval { get; } + + /// + /// Gets edge routing algorithm + /// IExternalEdgeRouting EdgeRouting { get; } } } diff --git a/GraphX.PCL.Common/Interfaces/ICore.cs b/GraphX.PCL.Common/Interfaces/ICore.cs deleted file mode 100644 index 0ccb4845..00000000 --- a/GraphX.PCL.Common/Interfaces/ICore.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace GraphX.PCL.Common.Interfaces -{ - public interface ICore - { - } -} diff --git a/GraphX.PCL.Common/Interfaces/IEdgeRoutingAlgorithm.cs b/GraphX.PCL.Common/Interfaces/IEdgeRoutingAlgorithm.cs deleted file mode 100644 index b6ead073..00000000 --- a/GraphX.PCL.Common/Interfaces/IEdgeRoutingAlgorithm.cs +++ /dev/null @@ -1,15 +0,0 @@ -using QuickGraph; - -namespace GraphX.PCL.Common.Interfaces -{ - /// - /// obsolete? - /// - /// - /// - public interface IEdgeRoutingAlgorithm : IExternalEdgeRouting - where TEdge : IEdge - { - - } -} \ No newline at end of file diff --git a/GraphX.PCL.Common/Interfaces/IEdgeRoutingParameters.cs b/GraphX.PCL.Common/Interfaces/IEdgeRoutingParameters.cs index e900ad3e..70f7ecf6 100644 --- a/GraphX.PCL.Common/Interfaces/IEdgeRoutingParameters.cs +++ b/GraphX.PCL.Common/Interfaces/IEdgeRoutingParameters.cs @@ -1,6 +1,9 @@ namespace GraphX.PCL.Common.Interfaces { - public interface IEdgeRoutingParameters// : IAlgorithmParameters + /// + /// Base class for edge routing algorithm parameters + /// + public interface IEdgeRoutingParameters { } } \ No newline at end of file diff --git a/GraphX.PCL.Common/Interfaces/IExternalEdgeRouting.cs b/GraphX.PCL.Common/Interfaces/IExternalEdgeRouting.cs index 907d6970..e73e943a 100644 --- a/GraphX.PCL.Common/Interfaces/IExternalEdgeRouting.cs +++ b/GraphX.PCL.Common/Interfaces/IExternalEdgeRouting.cs @@ -4,6 +4,11 @@ namespace GraphX.PCL.Common.Interfaces { + /// + /// Base interface for an edge routing algorithm + /// + /// Vertex data class + /// Edge data class public interface IExternalEdgeRouting { /// @@ -25,22 +30,22 @@ public interface IExternalEdgeRouting void UpdateVertexData(TVertex vertex, Point position, Rect size); /// - /// Get visual vertex sizes (autofilled before Compute() call) + /// Gets or sets visual vertices sizes (autofilled before Compute() call) /// IDictionary VertexSizes { get; set; } /// - /// Get visual vertex positions (autofilled before Compute() call) + /// Gets or sets visual vertices positions (autofilled before Compute() call) /// IDictionary VertexPositions { get; set; } /// - /// Get resulting edge routes collection + /// Gets resulting edge routes collection /// IDictionary EdgeRoutes { get; } /// - /// GraphArea rendering size + /// Gets or sets GraphArea allowed rendering size /// Rect AreaRectangle { get; set; } diff --git a/GraphX.PCL.Common/Interfaces/IExternalLayout.cs b/GraphX.PCL.Common/Interfaces/IExternalLayout.cs index d6355f15..66aa03b6 100644 --- a/GraphX.PCL.Common/Interfaces/IExternalLayout.cs +++ b/GraphX.PCL.Common/Interfaces/IExternalLayout.cs @@ -4,6 +4,10 @@ namespace GraphX.PCL.Common.Interfaces { + /// + /// Base interface for layout algorithm + /// + /// Vertex data class public interface IExternalLayout { /// @@ -12,17 +16,17 @@ public interface IExternalLayout void Compute(CancellationToken cancellationToken); /// - /// Vertex positions: initial and resulting (after Compute) + /// Gets vertices positions: initial and resulting (after Compute) /// IDictionary VertexPositions { get; } /// - /// Stores visual vertex sizes (autofilled if NeedVertexSizes property is set to true) + /// Gets or sets visual vertices sizes (autofilled if NeedVertexSizes property is set to true) /// IDictionary VertexSizes { get; set; } /// - /// If algorithm needs to know visual vertex control sizes they will be set into VertexSizes property before calculation + /// Gets if algorithm needs to know visual VertexControl size (if True VertexSizes property will be filled before calculation) /// bool NeedVertexSizes { get; } diff --git a/GraphX.PCL.Common/Interfaces/IExternalOverlapRemoval.cs b/GraphX.PCL.Common/Interfaces/IExternalOverlapRemoval.cs index a4f9c219..c88b3163 100644 --- a/GraphX.PCL.Common/Interfaces/IExternalOverlapRemoval.cs +++ b/GraphX.PCL.Common/Interfaces/IExternalOverlapRemoval.cs @@ -4,10 +4,15 @@ namespace GraphX.PCL.Common.Interfaces { + /// + /// Base interface for overlap removal algorithm + /// + /// Vertex data class public interface IExternalOverlapRemoval { /// - /// Stores vertex rectangle sizes (filled automaticaly before calculation) + /// Gets or sets vertices rectangle sizes + /// This property is filled automaticaly before calculation in GenerateGraph()/RelayoutGraph() methods /// IDictionary Rectangles { get; set; } /// diff --git a/GraphX.PCL.Common/Interfaces/IGXLogicCore.cs b/GraphX.PCL.Common/Interfaces/IGXLogicCore.cs index 509d9b24..f621b741 100644 --- a/GraphX.PCL.Common/Interfaces/IGXLogicCore.cs +++ b/GraphX.PCL.Common/Interfaces/IGXLogicCore.cs @@ -12,45 +12,160 @@ public interface IGXLogicCore: IDisposable where TEdge : class, IGraphXEdge where TGraph : class, IMutableBidirectionalGraph { + /// + /// Get an algorithm factory that provides different algorithm creation methods + /// IAlgorithmFactory AlgorithmFactory { get; } - IAlgorithmStorage AlgorithmStorage { get; } + /// + /// Gets or sets algorithm storage that contain all currently defined algorithm objects by type (default or external) + /// Actual storage data is vital for correct edge routing operation after graph was regenerated. + /// + IAlgorithmStorage AlgorithmStorage { get; set; } + + /// + /// Gets or sets main graph object + /// TGraph Graph { get; set; } + + /// + /// Gets or sets if async algorithm computations are enabled + /// bool AsyncAlgorithmCompute { get; set; } + /// + /// Gets or sets if edge curving technique enabled for smoother edges. Default value is True. + /// bool EdgeCurvingEnabled { get; set; } + + /// + /// Gets or sets roughly the length of each line segment in the polyline + /// approximation to a continuous curve in WPF units. The smaller the + /// number the smoother the curve, but slower the performance. Default is 8. + /// double EdgeCurvingTolerance { get; set; } + /// + /// Gets or sets if parallel edges are enabled. All edges between the same nodes will be separated by ParallelEdgeDistance value. + /// This is post-process procedure and it may be performance-costly. + /// bool EnableParallelEdges { get; set; } + + /// + /// Gets or sets distance by which edges are parallelized if EnableParallelEdges is true. Default value is 5. + /// int ParallelEdgeDistance { get; set; } + + /// + /// Gets if edge routing will be performed on Compute() method execution + /// bool IsEdgeRoutingEnabled { get; } - bool EnableEdgeLabelsOverlapRemoval { get; set; } + + //bool EnableEdgeLabelsOverlapRemoval { get; set; } + + /// + /// Gets is LayoutAlgorithmTypeEnum.Custom (NOT external) layout selected and used. Custom layout used to manualy generate graph. + /// bool IsCustomLayout { get; } + /// + /// Gets or sets default layout algorithm that will be used on graph generation/relayouting + /// LayoutAlgorithmTypeEnum DefaultLayoutAlgorithm { get; set; } + + /// + /// Gets or sets default overlap removal algorithm that will be used on graph generation/relayouting + /// OverlapRemovalAlgorithmTypeEnum DefaultOverlapRemovalAlgorithm { get; set; } + + /// + /// Gets or sets default edge routing algorithm that will be used on graph generation/relayouting + /// EdgeRoutingAlgorithmTypeEnum DefaultEdgeRoutingAlgorithm { get; set; } + + /// + /// Gets or sets default layout algorithm parameters that will be used on graph generation/relayouting + /// ILayoutParameters DefaultLayoutAlgorithmParams { get; set; } + + /// + /// Gets or sets default overlap removal algorithm parameters that will be used on graph generation/relayouting + /// IOverlapRemovalParameters DefaultOverlapRemovalAlgorithmParams { get; set; } + + /// + /// Gets or sets default edge routing algorithm parameters that will be used on graph generation/relayouting + /// IEdgeRoutingParameters DefaultEdgeRoutingAlgorithmParams { get; set; } + /// + /// Gets or sets external layout algorithm that will be used instead of the default one. + /// Negates DefaultLayoutAlgorithm property value if set. + /// IExternalLayout ExternalLayoutAlgorithm { get; set; } + + /// + /// Gets or sets external overlap removal algorithm that will be used instead of the default one. + /// Negates DefaultOverlapRemovalAlgorithm property value if set. + /// IExternalOverlapRemoval ExternalOverlapRemovalAlgorithm { get; set; } + + /// + /// Gets or sets external edge routing algorithm that will be used instead of the default one. + /// Negates DefaultEdgeRoutingAlgorithm property value if set. + /// IExternalEdgeRouting ExternalEdgeRoutingAlgorithm { get; set; } + /// + /// Computes all edge routes related to specified vertex + /// + /// Vertex data + /// Vertex position + /// Vertex size void ComputeEdgeRoutesByVertex(TVertex dataVertex, Point? vertexPosition = null, Size? vertexSize = null); - void CreateNewAlgorithmFactory(); - void CreateNewAlgorithmStorage(IExternalLayout layout, IExternalOverlapRemoval or, IExternalEdgeRouting er); + //void CreateNewAlgorithmFactory(); + //void CreateNewAlgorithmStorage(IExternalLayout layout, IExternalOverlapRemoval or, IExternalEdgeRouting er); + + /// + /// Computes graph using parameters set in LogicCore properties + /// + /// Optional cancellation token for async operation abort IDictionary Compute(CancellationToken cancellationToken); + /// + /// Gets if current algorithm set needs vertices sizes + /// bool AreVertexSizesNeeded(); + + /// + /// Gets if current algorithms set actualy needs overlap removal algorithm + /// bool AreOverlapNeeded(); + + /// + /// Generate layout algorithm according to LogicCore layout algorithm default/external properties set + /// + /// Vertices sizes + /// Vertices positions IExternalLayout GenerateLayoutAlgorithm(Dictionary vertexSizes, IDictionary vertexPositions); + + /// + /// Generate overlap removal algorithm according to LogicCore overlap removal algorithm default/external properties set + /// + /// Vertices rectangular sizes IExternalOverlapRemoval GenerateOverlapRemovalAlgorithm(Dictionary rectangles = null); - IExternalEdgeRouting GenerateEdgeRoutingAlgorithm(Size desiredSize, IDictionary positions = null, IDictionary rectangles = null); /// - /// Creates algorithms by values in LogicCore properties and generates new AlgorithmStorage object + /// Generate layout algorithm according to LogicCore layout algorithm default/external properties set + /// + /// Desired rectangular area size that will be taken into account + /// Vertices positions + /// Vertices rectangular sizes + IExternalEdgeRouting GenerateEdgeRoutingAlgorithm(Size desiredSize, IDictionary vertexPositions = null, IDictionary rectangles = null); + + /// + /// Creates algorithm objects based on default/external LogicCore properies and stores them to be able to access them later by, for ex. edge recalculation logic. + /// Done automaticaly when graph is regenerated/relayouted. /// /// Vertex sizes /// Vertex positions diff --git a/GraphX.PCL.Common/Interfaces/IGraphXEdge.cs b/GraphX.PCL.Common/Interfaces/IGraphXEdge.cs index 1f763d97..29c987a5 100644 --- a/GraphX.PCL.Common/Interfaces/IGraphXEdge.cs +++ b/GraphX.PCL.Common/Interfaces/IGraphXEdge.cs @@ -7,11 +7,11 @@ public interface IGraphXEdge : IGraphXCommonEdge, IWeightedEdge { /// - /// Source vertex + /// Gets or sets source vertex /// new TVertex Source { get; set; } /// - /// Target vertex + /// Gets or sets target vertex /// new TVertex Target { get; set; } @@ -23,7 +23,7 @@ public interface IGraphXEdge : IGraphXCommonEdge, IWeightedEdge - /// If edge is self-looped + /// Gets if edge is self-looped /// bool IsSelfLoop { get; } /// diff --git a/GraphX.PCL.Common/Models/GraphState.cs b/GraphX.PCL.Common/Models/GraphState.cs index 94140d33..83f232e3 100644 --- a/GraphX.PCL.Common/Models/GraphState.cs +++ b/GraphX.PCL.Common/Models/GraphState.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using GraphX.Measure; +using GraphX.PCL.Common.Interfaces; namespace GraphX.PCL.Common.Models { @@ -30,10 +31,19 @@ public sealed class GraphState /// public List VisibleEdges { get; private set; } - public GraphState(string id, TGraph graph, Dictionary vPos, List vEdges, string description = "") + /// + /// Saved algorithm storage + /// + public IAlgorithmStorage AlgorithmStorage { get; private set; } + + public GraphState(string id, TGraph graph, IAlgorithmStorage storage, Dictionary vPos, List vEdges, string description = "") { - ID = id; Graph = graph; Description = description; VertexPositions = vPos; + ID = id; + Graph = graph; + Description = description; + VertexPositions = vPos; VisibleEdges = vEdges; + AlgorithmStorage = storage; } } } diff --git a/GraphX.PCL.Logic/Algorithms/LayoutAlgorithms/Hierarchical/SugiyamaLayoutAlgorithm.cs b/GraphX.PCL.Logic/Algorithms/LayoutAlgorithms/Hierarchical/SugiyamaLayoutAlgorithm.cs index bbf21606..c8fe6e90 100644 --- a/GraphX.PCL.Logic/Algorithms/LayoutAlgorithms/Hierarchical/SugiyamaLayoutAlgorithm.cs +++ b/GraphX.PCL.Logic/Algorithms/LayoutAlgorithms/Hierarchical/SugiyamaLayoutAlgorithm.cs @@ -8,7 +8,7 @@ namespace GraphX.PCL.Logic.Algorithms.LayoutAlgorithms { - public partial class SugiyamaLayoutAlgorithm : DefaultParameterizedLayoutAlgorithmBase/*, IEdgeRoutingAlgorithm*/ + public partial class SugiyamaLayoutAlgorithm : DefaultParameterizedLayoutAlgorithmBase where TVertex : class where TEdge : IEdge where TGraph : IVertexAndEdgeListGraph diff --git a/GraphX.PCL.Logic/Models/GXLogicCore.cs b/GraphX.PCL.Logic/Models/GXLogicCore.cs index 1920a9be..1d4f2819 100644 --- a/GraphX.PCL.Logic/Models/GXLogicCore.cs +++ b/GraphX.PCL.Logic/Models/GXLogicCore.cs @@ -17,7 +17,7 @@ public partial class GXLogicCore: IGXLogicCore - /// Provides different algorithm creation methods + /// Get an algorithm factory that provides different algorithm creation methods /// public IAlgorithmFactory AlgorithmFactory { get; private set; } @@ -25,9 +25,10 @@ public partial class GXLogicCore: IGXLogicCore - /// Get algorithm storage that contain all currently defined algorithms by type (default or external) + /// Gets or sets algorithm storage that contain all currently defined algorithm objects by type (default or external) + /// Actual storage data is vital for correct edge routing operation after graph was regenerated. /// - public IAlgorithmStorage AlgorithmStorage { get; private set; } + public IAlgorithmStorage AlgorithmStorage { get; set; } #endregion /// @@ -43,35 +44,73 @@ public partial class GXLogicCore: IGXLogicCore /// Gets or sets if if edge label overlap removal enabled /// - public bool EnableEdgeLabelsOverlapRemoval { get; set; } + private bool EnableEdgeLabelsOverlapRemoval { get; set; } /// - /// Gets is custom (NOT external) layout selected and used + /// Gets is LayoutAlgorithmTypeEnum.Custom (NOT external) layout selected and used. Custom layout used to manualy generate graph. /// public bool IsCustomLayout { get { return DefaultLayoutAlgorithm == LayoutAlgorithmTypeEnum.Custom && ExternalLayoutAlgorithm == null; } } - + + /// + /// Gets or sets external layout algorithm that will be used instead of the default one. + /// Negates DefaultLayoutAlgorithm property value if set. + /// public IExternalLayout ExternalLayoutAlgorithm { get; set; } + + /// + /// Gets or sets external overlap removal algorithm that will be used instead of the default one. + /// Negates DefaultOverlapRemovalAlgorithm property value if set. + /// public IExternalOverlapRemoval ExternalOverlapRemovalAlgorithm { get; set; } + + /// + /// Gets or sets external edge routing algorithm that will be used instead of the default one. + /// Negates DefaultEdgeRoutingAlgorithm property value if set. + /// public IExternalEdgeRouting ExternalEdgeRoutingAlgorithm { get; set; } private LayoutAlgorithmTypeEnum _defaultLayoutAlgorithm; + /// + /// Gets or sets default layout algorithm that will be used on graph generation/relayouting + /// public LayoutAlgorithmTypeEnum DefaultLayoutAlgorithm { get { return _defaultLayoutAlgorithm; } set { _defaultLayoutAlgorithm = value; SetDefaultParams(0); } } private OverlapRemovalAlgorithmTypeEnum _defaultOverlapRemovalAlgorithm; + /// + /// Gets or sets default overlap removal algorithm that will be used on graph generation/relayouting + /// public OverlapRemovalAlgorithmTypeEnum DefaultOverlapRemovalAlgorithm { get { return _defaultOverlapRemovalAlgorithm; } set { _defaultOverlapRemovalAlgorithm = value; SetDefaultParams(1);} } private EdgeRoutingAlgorithmTypeEnum _defaultEdgeRoutingAlgorithm; + /// + /// Gets or sets default edge routing algorithm that will be used on graph generation/relayouting + /// public EdgeRoutingAlgorithmTypeEnum DefaultEdgeRoutingAlgorithm { get { return _defaultEdgeRoutingAlgorithm; } set { _defaultEdgeRoutingAlgorithm = value; SetDefaultParams(2); } } + /// + /// Gets or sets default layout algorithm parameters that will be used on graph generation/relayouting + /// public ILayoutParameters DefaultLayoutAlgorithmParams { get; set; } + + /// + /// Gets or sets default overlap removal algorithm parameters that will be used on graph generation/relayouting + /// public IOverlapRemovalParameters DefaultOverlapRemovalAlgorithmParams { get; set; } + + /// + /// Gets or sets default edge routing algorithm parameters that will be used on graph generation/relayouting + /// public IEdgeRoutingParameters DefaultEdgeRoutingAlgorithmParams { get; set; } + + /// + /// Gets or sets if async algorithm computations are enabled + /// public bool AsyncAlgorithmCompute { get; set; } /// @@ -101,36 +140,36 @@ private void SetDefaultParams(int type) } /// - /// Use edge curving technique for smoother edges. Default value is false. + /// Gets or sets if edge curving technique enabled for smoother edges. Default value is True. /// public bool EdgeCurvingEnabled { get; set; } /// - /// This is roughly the length of each line segment in the polyline + /// Gets or sets roughly the length of each line segment in the polyline /// approximation to a continuous curve in WPF units. The smaller the /// number the smoother the curve, but slower the performance. Default is 8. /// public double EdgeCurvingTolerance { get; set; } /// - /// Main graph object + /// Gets or sets main graph object /// public virtual TGraph Graph { get; set; } /// - /// Enables parallel edges. All edges between the same nodes will be separated by ParallelEdgeDistance value. + /// Gets or sets if parallel edges are enabled. All edges between the same nodes will be separated by ParallelEdgeDistance value. /// This is post-process procedure and it may be performance-costly. /// public bool EnableParallelEdges { get; set; } /// - /// Distance by which edges are parallelized if EnableParallelEdges is true. Default value is 5. + /// Gets or sets distance by which edges are parallelized if EnableParallelEdges is true. Default value is 5. /// public int ParallelEdgeDistance { get; set; } #region IsEdgeRoutingEnabled /// - /// Value overloaded for extensibility purposes. Indicates if ER will be performed on Compute(). + /// Gets if edge routing will be performed on Compute() method execution /// public bool IsEdgeRoutingEnabled { @@ -147,6 +186,7 @@ public GXLogicCore(TGraph graph) CreateNewAlgorithmFactory(); CreateNewAlgorithmStorage(null, null, null); Graph = graph; + EdgeCurvingEnabled = true; EdgeCurvingTolerance = 8; ParallelEdgeDistance = 5; } @@ -169,11 +209,20 @@ public void Dispose() } + /// + /// Creates new algorithm factory + /// public void CreateNewAlgorithmFactory() { AlgorithmFactory = new AlgorithmFactory(); } + /// + /// Creates new algorithm storage + /// + /// Layout algorithm + /// Overlap removal algorithm + /// Edge routing algorithm public void CreateNewAlgorithmStorage(IExternalLayout layout, IExternalOverlapRemoval or, IExternalEdgeRouting er) { AlgorithmStorage = new AlgorithmStorage(layout, or, er); diff --git a/GraphX.PCL.Logic/Models/GXLogicCore_Calculation.cs b/GraphX.PCL.Logic/Models/GXLogicCore_Calculation.cs index 4d3f4601..f7f8a76d 100644 --- a/GraphX.PCL.Logic/Models/GXLogicCore_Calculation.cs +++ b/GraphX.PCL.Logic/Models/GXLogicCore_Calculation.cs @@ -15,6 +15,9 @@ public partial class GXLogicCore where TEdge : class, IGraphXEdge where TGraph : class, IMutableBidirectionalGraph { + /// + /// Gets if current algorithms set needs vertices sizes + /// public bool AreVertexSizesNeeded() { return (ExternalLayoutAlgorithm == null && AlgorithmFactory.NeedSizes(DefaultLayoutAlgorithm)) @@ -24,12 +27,19 @@ public bool AreVertexSizesNeeded() AreOverlapNeeded(); } + /// + /// Gets if current algorithms set actualy needs overlap removal algorithm + /// public bool AreOverlapNeeded() { return (ExternalOverlapRemovalAlgorithm == null && AlgorithmFactory.NeedOverlapRemoval(DefaultLayoutAlgorithm) && DefaultOverlapRemovalAlgorithm != OverlapRemovalAlgorithmTypeEnum.None) || (ExternalOverlapRemovalAlgorithm != null); } + /// + /// Generate overlap removal algorithm according to LogicCore overlap removal algorithm default/external properties set + /// + /// Vertices rectangular sizes public IExternalOverlapRemoval GenerateOverlapRemovalAlgorithm(Dictionary rectangles = null) { if (ExternalOverlapRemovalAlgorithm == null) @@ -42,6 +52,11 @@ public IExternalOverlapRemoval GenerateOverlapRemovalAlgorithm(Dictiona return overlap; } + /// + /// Generate layout algorithm according to LogicCore layout algorithm default/external properties set + /// + /// Vertices sizes + /// Vertices positions public IExternalLayout GenerateLayoutAlgorithm(Dictionary vertexSizes, IDictionary vertexPositions) { if (ExternalLayoutAlgorithm == null) return AlgorithmFactory.CreateLayoutAlgorithm(DefaultLayoutAlgorithm, Graph, vertexPositions, vertexSizes, DefaultLayoutAlgorithmParams); @@ -50,15 +65,28 @@ public IExternalLayout GenerateLayoutAlgorithm(Dictionary GenerateEdgeRoutingAlgorithm(Size desiredSize, IDictionary positions = null, IDictionary rectangles = null) + /// + /// Generate layout algorithm according to LogicCore layout algorithm default/external properties set + /// + /// Desired rectangular area size that will be taken into account + /// Vertices positions + /// Vertices rectangular sizes + public IExternalEdgeRouting GenerateEdgeRoutingAlgorithm(Size desiredSize, IDictionary vertexPositions = null, IDictionary rectangles = null) { if (ExternalEdgeRoutingAlgorithm == null && DefaultEdgeRoutingAlgorithm != EdgeRoutingAlgorithmTypeEnum.None) { - return AlgorithmFactory.CreateEdgeRoutingAlgorithm(DefaultEdgeRoutingAlgorithm, new Rect(desiredSize), Graph, positions, rectangles, DefaultEdgeRoutingAlgorithmParams); + return AlgorithmFactory.CreateEdgeRoutingAlgorithm(DefaultEdgeRoutingAlgorithm, new Rect(desiredSize), Graph, vertexPositions, rectangles, DefaultEdgeRoutingAlgorithmParams); } return ExternalEdgeRoutingAlgorithm; } + + /// + /// Computes all edge routes related to specified vertex + /// + /// Vertex data + /// Vertex position + /// Vertex size public void ComputeEdgeRoutesByVertex(TVertex dataVertex, Point? vertexPosition = null, Size? vertexSize = null) { if (AlgorithmStorage == null || AlgorithmStorage.EdgeRouting == null) @@ -67,14 +95,14 @@ public void ComputeEdgeRoutesByVertex(TVertex dataVertex, Point? vertexPosition var list = new List(); IEnumerable edges; Graph.TryGetInEdges(dataVertex, out edges); - list.AddRange(edges); + if(edges != null) + list.AddRange(edges); Graph.TryGetOutEdges(dataVertex, out edges); - list.AddRange(edges); + if(edges != null) + list.AddRange(edges); if (vertexPosition.HasValue && vertexSize.HasValue) - { UpdateVertexDataForEr(dataVertex, vertexPosition.Value, vertexSize.Value); - } foreach (var item in list) item.RoutingPoints = AlgorithmStorage.EdgeRouting.ComputeSingle(item);