Skip to content

Commit

Permalink
+ Added EdgeLabelControl::FlipOnRotation
Browse files Browse the repository at this point in the history
+ Fixed edge routing when graph state has been loaded
+ Interfaces documentation
+ Fixed METRO showcase app work
  • Loading branch information
panthernet committed Jun 28, 2015
1 parent e6f3524 commit fcfaf9c
Show file tree
Hide file tree
Showing 24 changed files with 367 additions and 247 deletions.
4 changes: 4 additions & 0 deletions Documents/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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)]
Expand Down
37 changes: 10 additions & 27 deletions Examples/METRO.SimpleGraph/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -105,7 +111,7 @@ async void MainPage_Loaded(object sender, RoutedEventArgs e)

try
{
await graph.GenerateGraphAsync(true);
await graph.GenerateGraphAsync();
}
catch (OperationCanceledException)
{
Expand Down Expand Up @@ -270,23 +276,7 @@ private void GraphAreaExample_Setup()
{

var logicCore = graph.GetLogicCore<GXLogicCoreExample>();
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)
{
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Examples/ShowcaseApp.WPF/Models/ShowcaseHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static void AddEdge(BidirectionalGraph<DataVertex, DataEdge> graph, DataV
Text = string.Empty,
SourceConnectionPointId = sourcePoint,
TargetConnectionPointId = targetPoint,
ToolTipText = "Default label"
ToolTipText = "Default label "+ source.ID
};

graph.AddEdge(edge);
Expand Down
11 changes: 9 additions & 2 deletions Examples/ShowcaseApp.WPF/Pages/Mini/EdgesParallel.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,23 @@ 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
var posList = new Dictionary<DataVertex, Point>()
{
{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
Expand All @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions GraphX.Controls/Controls/EdgeControlBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ void IPositionChangeNotify.OnPositionChanged()
public abstract void Clean();
protected DoubleCollection StrokeDashArray { get; set; }

/// <summary>
/// Gets if this edge is parallel (has another edge with the same source and target vertices)
/// </summary>
public bool IsParallel { get; internal set; }

/// <summary>
/// Element presenting self looped edge
/// </summary>
Expand Down
23 changes: 22 additions & 1 deletion GraphX.Controls/Controls/EdgeLabels/EdgeLabelControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ public bool DisplayForSelfLoopedEdges
}
}

public static readonly DependencyProperty FlipOnRotationProperty = DependencyProperty.Register("FlipOnRotation",
typeof(bool),
typeof(EdgeLabelControl),
new PropertyMetadata(true));
/// <summary>
/// Gets or sets if label should flip on rotation when axis changes
/// </summary>
public bool FlipOnRotation
{
get
{
return (bool)GetValue(FlipOnRotationProperty);
}
set
{
SetValue(FlipOnRotationProperty, value);
}
}



public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle",
typeof(double),
typeof(EdgeLabelControl),
Expand Down Expand Up @@ -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.
Expand Down
80 changes: 14 additions & 66 deletions GraphX.Controls/Controls/GraphArea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}*/

/// <summary>
/// Generates all possible valid edges for Graph vertexes
/// </summary>
Expand All @@ -1152,10 +1103,17 @@ public void GenerateAllEdges(Visibility defaultVisibility = Visibility.Visible,
generateAllEdges(defaultVisibility);
}

private void ParallelizeEdges()
/// <summary>
/// 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
/// </summary>
public void UpdateParallelEdgesData()
{
var usedIds = _edgeslist.Count > 20 ? new HashSet<int>() as ICollection<int> : new List<int>();

//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;
Expand Down Expand Up @@ -1210,6 +1168,7 @@ private void ParallelizeEdges()
}
//change trigger to opposite
viceversa = !viceversa;
list[i].IsParallel = true;
}
}

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -1453,20 +1412,9 @@ public void RebuildFromSerializationData(IEnumerable<GraphSerializationData> 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<TVertex, Measure.Point> vPositions;
var vSizes = GetVertexSizesAndPositions(out vPositions);

var vSizes = GetVertexSizesAndPositions(out vPositions);
LogicCore.GenerateAlgorithmStorage(vSizes, vPositions);
// }
}

#endregion
Expand Down
6 changes: 4 additions & 2 deletions GraphX.Controls/Models/StateStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ private GraphState<TVertex, TEdge, TGraph> 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<TVertex, TEdge, TGraph>(id, _area.LogicCore.Graph, vposlist, vedgelist, description);
return new GraphState<TVertex, TEdge, TGraph>(id, _area.LogicCore.Graph, _area.LogicCore.AlgorithmStorage, vposlist, vedgelist, description);
}

/// <summary>
Expand All @@ -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)
{
Expand Down
9 changes: 8 additions & 1 deletion GraphX.Controls/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
Expand Down Expand Up @@ -83,5 +84,11 @@ public static IEnumerable<T> FindLogicalChildren<T>(this DependencyObject obj)
.SelectMany(FindLogicalChildren<T>))
yield return c;
}

public static void ForEach<T>(this IEnumerable<T> list, Action<T> func)
{
foreach (var item in list)
func(item);
}
}
}
Loading

0 comments on commit fcfaf9c

Please sign in to comment.