TECH TREES WHOO

Implemented procedural tech tree generation by porting GraphSharp to Unity.
Also, some database editor convenience changes.
This commit is contained in:
hyperion51 2020-04-11 19:18:02 +01:00
commit d5f2e3734a
573 changed files with 31001 additions and 222 deletions

View file

@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using MessagePack;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
@ -28,6 +29,9 @@ public class DatabaseInspector : EditorWindow
private string[] _hardpointTypes;
private const int width = 100;
private const int labelWidth = 20;
private Material _galaxyMat;
private Texture2D _white;
private GUIStyle _warning;
public Color LabelColor => EditorGUIUtility.isProSkin ? Color.white : Color.black;
@ -61,14 +65,66 @@ public class DatabaseInspector : EditorWindow
DatabaseCache.OnDataUpdateRemote += _ => EditorDispatcher.Dispatch(Repaint);
wantsMouseMove = true;
_hardpointTypes = Enum.GetNames(typeof(HardpointType));
_galaxyMat = new Material(Shader.Find("Unlit/GalaxyMap"));
_white = Color.white.ToTexture();
_warning = new GUIStyle(EditorStyles.boldLabel);
_warning.normal.textColor = Color.red;
}
public void Inspect(object obj, bool inspectablesOnly = false)
{
foreach (var field in obj.GetType().GetFields())
foreach (var field in obj.GetType().GetFields().OrderBy(f=>f.GetCustomAttribute<KeyAttribute>()?.IntKey ?? 0))
{
Inspect(obj, field, inspectablesOnly);
}
if (obj is GalaxyMapLayerData mapLayer)
{
var global = DatabaseCache.GetAll<GlobalData>().FirstOrDefault();
if (global != null)
{
GUILayout.Label("Preview", EditorStyles.boldLabel);
_galaxyMat.SetFloat("Arms", global.Arms);
_galaxyMat.SetFloat("Twist", global.Twist);
_galaxyMat.SetFloat("TwistPower", global.TwistPower);
_galaxyMat.SetFloat("SpokeOffset", mapLayer.SpokeOffset);
_galaxyMat.SetFloat("SpokeScale", mapLayer.SpokeScale);
_galaxyMat.SetFloat("CoreBoost", mapLayer.CoreBoost);
_galaxyMat.SetFloat("CoreBoostOffset", mapLayer.CoreBoostOffset);
_galaxyMat.SetFloat("CoreBoostPower", mapLayer.CoreBoostPower);
_galaxyMat.SetFloat("EdgeReduction", mapLayer.EdgeReduction);
_galaxyMat.SetFloat("NoisePosition", mapLayer.NoisePosition);
_galaxyMat.SetFloat("NoiseAmplitude", mapLayer.NoiseAmplitude);
_galaxyMat.SetFloat("NoiseOffset", mapLayer.NoiseOffset);
_galaxyMat.SetFloat("NoiseGain", mapLayer.NoiseGain);
_galaxyMat.SetFloat("NoiseLacunarity", mapLayer.NoiseLacunarity);
_galaxyMat.SetFloat("NoiseFrequency", mapLayer.NoiseFrequency);
var rect = GetControlRect(false, Screen.width);
EditorGUI.DrawPreviewTexture(rect, _white, _galaxyMat);
}
}
if (obj is EquippableItemData equippableItemData)
{
var restricted = false;
var doubleRestricted = false;
HullType type = HullType.Ship;
foreach (var behavior in equippableItemData.Behaviors)
{
var restriction = behavior.GetType().GetCustomAttribute<EntityTypeRestrictionAttribute>();
if (restriction != null)
{
if (restricted && restriction.Type != type)
doubleRestricted = true;
restricted = true;
type = restriction.Type;
}
}
if(doubleRestricted)
GUILayout.Label("ITEM UNEQUIPPABLE: BEHAVIOR HULL TYPE CONFLICT", _warning);
else if (restricted)
GUILayout.Label($"Item restricted by behavior to hull type {Enum.GetName(typeof(HullType), type)}", EditorStyles.boldLabel);
}
}
public void Inspect(object obj, FieldInfo field, bool inspectablesOnly = false)
@ -255,6 +311,7 @@ public class DatabaseInspector : EditorWindow
{
using (new HorizontalScope())
{
//if (listType.IsInterface)
GUILayout.Label(o.GetType().Name.SplitCamelCase(), EditorStyles.boldLabel, GUILayout.ExpandWidth(true));
var rect = GetControlRect(false,
@ -399,7 +456,7 @@ public class DatabaseInspector : EditorWindow
{
GUILayout.Label(label, GUILayout.Width(width));
if(area)
return TextArea(value,GUILayout.MaxWidth(300));
return TextArea(value,GUILayout.Width(position.width-width-10), GUILayout.Height(100));
return DelayedTextField(value);
}
}
@ -565,7 +622,7 @@ public class DatabaseInspector : EditorWindow
{
using (var h = new HorizontalScope(_list.ListItemStyle))
{
GUILayout.Label("Nothing Here! Add an item by dragging from the list panel.");
GUILayout.Label("Drag from list to add item");
}
}
foreach (var ingredient in value.ToArray())
@ -611,7 +668,7 @@ public class DatabaseInspector : EditorWindow
{
using (var h = new HorizontalScope(_list.ListItemStyle))
{
GUILayout.Label("Nothing Here! Add an item by dragging from the list panel.");
GUILayout.Label("Drag from list to add item");
}
}
foreach (var ingredient in value.ToArray())
@ -657,7 +714,7 @@ public class DatabaseInspector : EditorWindow
{
using (var h = new HorizontalScope(_list.ListItemStyle))
{
GUILayout.Label($"Nothing Here! Add a {entryType.Name} by dragging from the list panel.");
GUILayout.Label($"Drag from list to add {entryType.Name}");
}
}
foreach (var guid in value.ToArray())

View file

@ -207,13 +207,13 @@ public class DatabaseListView : EditorWindow
}
}).WrapErrors();
// Get all galaxy map layer data from RethinkDB
// Get globaldata and all galaxy map layer data from RethinkDB
Task.Run(async () =>
{
var result = await R
.Db("Aetheria")
.Table("Galaxy")
.Filter(o => o["$type"]==typeof(GalaxyMapLayerData).Name)
.Filter(o => o["$type"]==typeof(GalaxyMapLayerData).Name || o["$type"]==typeof(GlobalData).Name)
.RunCursorAsync<DatabaseEntry>(_connection);
while (await result.MoveNextAsync())
{

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c3951a828808a3141be749fd521d02ac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fe100818283207a418b64e510fcdbbbd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,126 @@
using System;
using QuickGraph.Algorithms;
namespace GraphSharp.Algorithms
{
public abstract class AlgorithmBase : IAlgorithm
{
private volatile object syncRoot = new object();
private int cancelling;
private volatile ComputationState state = ComputationState.NotRunning;
public Object SyncRoot
{
get { return syncRoot; }
}
public ComputationState State
{
get
{
lock ( syncRoot )
{
return state;
}
}
}
protected bool IsAborting
{
get { return cancelling > 0; }
}
public void Compute()
{
BeginComputation();
InternalCompute();
EndComputation();
}
protected abstract void InternalCompute();
public virtual void Abort()
{
bool raise = false;
lock ( syncRoot )
{
if ( state == ComputationState.Running )
{
state = ComputationState.PendingAbortion;
System.Threading.Interlocked.Increment( ref cancelling );
raise = true;
}
}
if ( raise )
OnStateChanged( EventArgs.Empty );
}
public event EventHandler StateChanged;
protected virtual void OnStateChanged( EventArgs e )
{
EventHandler eh = StateChanged;
if ( eh != null )
eh( this, e );
}
public event EventHandler Started;
protected virtual void OnStarted( EventArgs e )
{
EventHandler eh = Started;
if ( eh != null )
eh( this, e );
}
public event EventHandler Finished;
protected virtual void OnFinished( EventArgs e )
{
EventHandler eh = Finished;
if ( eh != null )
eh( this, e );
}
public event EventHandler Aborted;
protected virtual void OnAborted( EventArgs e )
{
EventHandler eh = Aborted;
if ( eh != null )
eh( this, e );
}
protected void BeginComputation()
{
lock ( syncRoot )
{
if ( state != ComputationState.NotRunning )
throw new InvalidOperationException();
state = ComputationState.Running;
cancelling = 0;
OnStarted( EventArgs.Empty );
OnStateChanged( EventArgs.Empty );
}
}
protected void EndComputation()
{
lock ( syncRoot )
{
switch ( state )
{
case ComputationState.Running:
state = ComputationState.Finished;
OnFinished( EventArgs.Empty );
break;
case ComputationState.PendingAbortion:
state = ComputationState.Aborted;
OnAborted( EventArgs.Empty );
break;
default:
throw new InvalidOperationException();
}
cancelling = 0;
OnStateChanged( EventArgs.Empty );
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 840c4866f2043954bb4a43316aa0ba23
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d4af44a1cb169b047b47143756381bfb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,32 @@
using System.Collections.Generic;
using QuickGraph;
using QuickGraph.Algorithms;
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.EdgeRouting
{
public abstract class EdgeRoutingAlgorithmBase<TVertex, TEdge, TGraph> : AlgorithmBase<TGraph>, IEdgeRoutingAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IVertexAndEdgeListGraph<TVertex, TEdge>
{
protected IDictionary<TVertex, float2> vertexPositions;
/// <summary>
/// Gets or sets the routing points of the edges.
/// </summary>
public IDictionary<TEdge, float2[]> EdgeRoutes
{
get;
private set;
}
public EdgeRoutingAlgorithmBase(TGraph visitedGraph, IDictionary<TVertex, float2> vertexPositions)
: base(visitedGraph)
{
this.vertexPositions = vertexPositions;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bed8fe5597d81214294894077e52ba2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,18 @@
namespace GraphSharp.Algorithms.EdgeRouting
{
public class EdgeRoutingParameters : IEdgeRoutingParameters
{
public object Clone()
{
return this.MemberwiseClone();
}
protected void NotifyChanged( string propertyName )
{
if ( PropertyChanged != null )
PropertyChanged( this, new System.ComponentModel.PropertyChangedEventArgs( propertyName ) );
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4e98aa53af093bd418646cf9b584d57e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,16 @@
using System.Collections.Generic;
using QuickGraph.Algorithms;
using QuickGraph;
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.EdgeRouting
{
public interface IEdgeRoutingAlgorithm<TVertex, TEdge, TGraph> : IAlgorithm<TGraph>
where TEdge : IEdge<TVertex>
where TGraph : IVertexAndEdgeListGraph<TVertex, TEdge>
{
IDictionary<TEdge, float2[]> EdgeRoutes { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68d74f36ae422ac4081f5e347d001a87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,25 @@
using System.Collections.Generic;
using GraphSharp.Algorithms.Layout;
using QuickGraph;
namespace GraphSharp.Algorithms.EdgeRouting
{
public interface IEdgeRoutingAlgorithmFactory<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
/// <summary>
/// List of the available algorithms.
/// </summary>
IEnumerable<string> AlgorithmTypes { get; }
IEdgeRoutingAlgorithm<TVertex, TEdge, TGraph> CreateAlgorithm( string newAlgorithmType, ILayoutContext<TVertex, TEdge, TGraph> context, IEdgeRoutingParameters parameters);
IEdgeRoutingParameters CreateParameters( string algorithmType, IEdgeRoutingParameters oldParameters );
bool IsValidAlgorithm( string algorithmType );
string GetAlgorithmType( IEdgeRoutingAlgorithm<TVertex, TEdge, TGraph> algorithm );
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b27d7d08f55d06241aafc2dd2043377d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,6 @@
namespace GraphSharp.Algorithms.EdgeRouting
{
public interface IEdgeRoutingParameters : IAlgorithmParameters
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ac77f8617e945740be2953866a9af7d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,40 @@
using System.Collections.Generic;
using GraphSharp.Algorithms.Layout;
using System.Linq;
using QuickGraph;
namespace GraphSharp.Algorithms.EdgeRouting
{
public class StandardEdgeRoutingAlgorithmFactory<TVertex, TEdge, TGraph> : IEdgeRoutingAlgorithmFactory<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
protected static readonly string[] algorithmTypes = new string[] { };
public IEnumerable<string> AlgorithmTypes
{
get { return algorithmTypes; }
}
public IEdgeRoutingAlgorithm<TVertex, TEdge, TGraph> CreateAlgorithm( string newAlgorithmType, ILayoutContext<TVertex, TEdge, TGraph> context, IEdgeRoutingParameters parameters )
{
return null;
}
public IEdgeRoutingParameters CreateParameters( string algorithmType, IEdgeRoutingParameters oldParameters )
{
return null;
}
public bool IsValidAlgorithm( string algorithmType )
{
return AlgorithmTypes.Any( at => at == algorithmType );
}
public string GetAlgorithmType( IEdgeRoutingAlgorithm<TVertex, TEdge, TGraph> algorithm )
{
return string.Empty;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 42cb3c373dd36714799b300b45df721b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GraphSharp.Algorithms.Layout;
namespace GraphSharp.Algorithms
{
public static class FactoryHelper
{
public static TParam CreateNewParameter<TParam>(this ILayoutParameters oldParameters)
where TParam : class,ILayoutParameters,new()
{
return !(oldParameters is TParam)
? new TParam() :
(TParam)(oldParameters as TParam).Clone();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c7fcd3c9e6c0d54384f7de657ba87d2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6fd45e73b2ed38a44a5a653234eb266c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,66 @@
using System.ComponentModel;
using System.Diagnostics.Contracts;
using QuickGraph;
using System.Diagnostics;
namespace GraphSharp.Algorithms.Highlight
{
public abstract class HighlightAlgorithmBase<TVertex, TEdge, TGraph, TParameters> : IHighlightAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
where TParameters : class, IHighlightParameters
{
public IHighlightController<TVertex, TEdge, TGraph> Controller { get; private set; }
IHighlightParameters IHighlightAlgorithm<TVertex, TEdge, TGraph>.Parameters
{
get { return Parameters; }
}
public TParameters Parameters { get; private set; }
protected HighlightAlgorithmBase(
IHighlightController<TVertex, TEdge, TGraph> controller,
IHighlightParameters parameters )
{
Controller = controller;
TrySetParameters( parameters );
}
public abstract void ResetHighlight();
public abstract bool OnVertexHighlighting( TVertex vertex );
public abstract bool OnVertexHighlightRemoving( TVertex vertex );
public abstract bool OnEdgeHighlighting( TEdge edge );
public abstract bool OnEdgeHighlightRemoving( TEdge edge );
public bool IsParametersSettable( IHighlightParameters parameters )
{
return parameters != null && parameters is TParameters;
}
public bool TrySetParameters( IHighlightParameters parameters )
{
if ( IsParametersSettable( parameters ) )
{
if ( Parameters != null )
Parameters.PropertyChanged -= OnParameterPropertyChanged;
Parameters = (TParameters)parameters;
if ( Parameters != null )
Parameters.PropertyChanged += OnParameterPropertyChanged;
return true;
}
return false;
}
protected virtual void OnParametersChanged()
{
this.ResetHighlight();
}
private void OnParameterPropertyChanged( object sender, PropertyChangedEventArgs e )
{
OnParametersChanged();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de0a87e59efe95a44a7c95625f1584af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,20 @@
using QuickGraph;
namespace GraphSharp.Algorithms.Highlight
{
public class HighlightContext<TVertex, TEdge, TGraph> : IHighlightContext<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
public TGraph Graph
{
get; private set;
}
public HighlightContext(TGraph graph)
{
this.Graph = graph;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2480fc7369694ef4e9506685b8902650
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,28 @@
using System.ComponentModel;
namespace GraphSharp.Algorithms.Highlight
{
public class HighlightParameterBase : IHighlightParameters
{
#region ICloneable Members
public object Clone()
{
return MemberwiseClone();
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged( string propertyName )
{
if ( PropertyChanged != null )
PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 975eca90cc758be4886238e860c8edbc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,25 @@
using QuickGraph;
namespace GraphSharp.Algorithms.Highlight
{
public interface IHighlightAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
IHighlightParameters Parameters { get; }
/// <summary>
/// Reset the whole highlight.
/// </summary>
void ResetHighlight();
bool OnVertexHighlighting( TVertex vertex );
bool OnVertexHighlightRemoving( TVertex vertex );
bool OnEdgeHighlighting( TEdge edge );
bool OnEdgeHighlightRemoving( TEdge edge );
bool IsParametersSettable(IHighlightParameters parameters);
bool TrySetParameters(IHighlightParameters parameters);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c8c1786bae9007498205dc11952ffb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
using QuickGraph;
namespace GraphSharp.Algorithms.Highlight
{
public interface IHighlightAlgorithmFactory<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
IEnumerable<string> HighlightModes { get; }
bool IsValidMode( string mode );
IHighlightAlgorithm<TVertex, TEdge, TGraph> CreateAlgorithm(
string highlightMode,
IHighlightContext<TVertex, TEdge, TGraph> context,
IHighlightController<TVertex, TEdge, TGraph> controller,
IHighlightParameters parameters );
IHighlightParameters CreateParameters( string highlightMode, IHighlightParameters oldParameters );
string GetHighlightMode( IHighlightAlgorithm<TVertex, TEdge, TGraph> algorithm );
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7544860789ab4cd42aef36c403689688
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
using QuickGraph;
namespace GraphSharp.Algorithms.Highlight
{
public interface IHighlightContext<TVertex, TEdge, TGraph>
where TEdge : IEdge<TVertex>
where TGraph : IVertexAndEdgeListGraph<TVertex, TEdge>
{
TGraph Graph { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 79156d864172f444695ab27099ac9be9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,37 @@
using System.Collections.Generic;
using QuickGraph;
namespace GraphSharp.Algorithms.Highlight
{
public interface IHighlightController<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
TGraph Graph { get; }
IEnumerable<TVertex> HighlightedVertices { get; }
IEnumerable<TVertex> SemiHighlightedVertices { get; }
IEnumerable<TEdge> HighlightedEdges { get; }
IEnumerable<TEdge> SemiHighlightedEdges { get; }
bool IsHighlightedVertex( TVertex vertex );
bool IsHighlightedVertex( TVertex vertex, out object highlightInfo );
bool IsSemiHighlightedVertex( TVertex vertex );
bool IsSemiHighlightedVertex( TVertex vertex, out object semiHighlightInfo );
bool IsHighlightedEdge( TEdge edge );
bool IsHighlightedEdge( TEdge edge, out object highlightInfo );
bool IsSemiHighlightedEdge( TEdge edge );
bool IsSemiHighlightedEdge( TEdge edge, out object semiHighlightInfo );
void HighlightVertex( TVertex vertex, object highlightInfo );
void SemiHighlightVertex( TVertex vertex, object semiHighlightInfo );
void HighlightEdge( TEdge edge, object highlightInfo );
void SemiHighlightEdge( TEdge edge, object semiHighlightInfo );
void RemoveHighlightFromVertex( TVertex vertex );
void RemoveSemiHighlightFromVertex( TVertex vertex );
void RemoveHighlightFromEdge( TEdge edge );
void RemoveSemiHighlightFromEdge( TEdge edge );
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e0e4a052750ba434d9e7b47f41254ebc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,9 @@
using System;
using System.ComponentModel;
namespace GraphSharp.Algorithms.Highlight
{
public interface IHighlightParameters : ICloneable, INotifyPropertyChanged
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74d481da9efa96c4f835885ef71fb92f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,105 @@
using QuickGraph;
namespace GraphSharp.Algorithms.Highlight
{
public class SimpleHighlightAlgorithm<TVertex, TEdge, TGraph> : HighlightAlgorithmBase<TVertex, TEdge, TGraph, IHighlightParameters>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
public SimpleHighlightAlgorithm(
IHighlightController<TVertex, TEdge, TGraph> controller,
IHighlightParameters parameters )
: base( controller, parameters )
{
}
private void ClearSemiHighlights()
{
foreach ( var vertex in Controller.SemiHighlightedVertices )
Controller.RemoveSemiHighlightFromVertex( vertex );
foreach ( var edge in Controller.SemiHighlightedEdges )
Controller.RemoveSemiHighlightFromEdge( edge );
}
private void ClearAllHighlights()
{
ClearSemiHighlights();
foreach ( var vertex in Controller.HighlightedVertices )
Controller.RemoveHighlightFromVertex( vertex );
foreach ( var edge in Controller.HighlightedEdges )
Controller.RemoveHighlightFromEdge( edge );
}
/// <summary>
/// Resets the semi-highlights according to the actually
/// highlighted vertices/edges.
///
/// This method should be called if the graph changed,
/// or the highlights should be resetted.
/// </summary>
public override void ResetHighlight()
{
ClearAllHighlights();
}
public override bool OnVertexHighlighting( TVertex vertex )
{
ClearAllHighlights();
if ( vertex == null || !Controller.Graph.ContainsVertex( vertex ) )
return false;
//semi-highlight the in-edges, and the neighbours on their other side
foreach ( var edge in Controller.Graph.InEdges( vertex ) )
{
Controller.SemiHighlightEdge( edge, "InEdge" );
if ( edge.Source == vertex || Controller.IsHighlightedVertex( edge.Source ) )
continue;
Controller.SemiHighlightVertex( edge.Source, "Source" );
}
//semi-highlight the out-edges
foreach ( var edge in Controller.Graph.OutEdges( vertex ) )
{
Controller.SemiHighlightEdge( edge, "OutEdge" );
if ( edge.Target == vertex || Controller.IsHighlightedVertex( edge.Target ) )
continue;
Controller.SemiHighlightVertex( edge.Target, "Target" );
}
Controller.HighlightVertex( vertex, "None" );
return true;
}
public override bool OnVertexHighlightRemoving( TVertex vertex )
{
ClearAllHighlights();
return true;
}
public override bool OnEdgeHighlighting( TEdge edge )
{
ClearAllHighlights();
//highlight the source and the target
if ( Equals( edge, default( TEdge ) ) || !Controller.Graph.ContainsEdge( edge ) )
return false;
Controller.HighlightEdge( edge, null );
Controller.SemiHighlightVertex( edge.Source, "Source" );
Controller.SemiHighlightVertex( edge.Target, "Target" );
return true;
}
public override bool OnEdgeHighlightRemoving( TEdge edge )
{
ClearAllHighlights();
return true;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 707756178922bf343bb53c545a66f6d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,58 @@
using System.Collections.Generic;
using System.Linq;
using QuickGraph;
namespace GraphSharp.Algorithms.Highlight
{
public class StandardHighlightAlgorithmFactory<TVertex, TEdge, TGraph> : IHighlightAlgorithmFactory<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
private static readonly string[] highlightModes = { "Simple" };
public IEnumerable<string> HighlightModes
{
get { return highlightModes; }
}
public bool IsValidMode( string mode )
{
return string.IsNullOrEmpty( mode ) || highlightModes.Contains( mode );
}
public IHighlightAlgorithm<TVertex, TEdge, TGraph> CreateAlgorithm(
string highlightMode,
IHighlightContext<TVertex, TEdge, TGraph> context,
IHighlightController<TVertex, TEdge, TGraph> controller,
IHighlightParameters parameters )
{
switch (highlightMode)
{
case "Simple":
return new SimpleHighlightAlgorithm<TVertex, TEdge, TGraph>(controller, parameters);
default:
return null;
}
}
public IHighlightParameters CreateParameters( string highlightMode, IHighlightParameters oldParameters )
{
switch (highlightMode)
{
case "Simple":
return new HighlightParameterBase();
default:
return new HighlightParameterBase();
}
}
public string GetHighlightMode( IHighlightAlgorithm<TVertex, TEdge, TGraph> algorithm )
{
if ( algorithm is SimpleHighlightAlgorithm<TVertex, TEdge, TGraph> )
return "Simple";
return null;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad9f5a34732fe36489821652974bddb8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System;
using QuickGraph.Algorithms;
namespace GraphSharp.Algorithms
{
/// <summary>
/// Simple algorithm interface which is not connected to any graph.
/// </summary>
public interface IAlgorithm
{
object SyncRoot { get;}
ComputationState State { get;}
void Compute();
void Abort();
event EventHandler StateChanged;
event EventHandler Started;
event EventHandler Finished;
event EventHandler Aborted;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6fe4b9a345a86a244a6c195309a2aa59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,9 @@
using System;
using System.ComponentModel;
namespace GraphSharp.Algorithms
{
public interface IAlgorithmParameters : ICloneable, INotifyPropertyChanged
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 863e1d8f88a040944aa87054331199cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QuickGraph;
using QuickGraph.Algorithms;
namespace GraphSharp.Algorithms
{
public class LayeredTopologicalSortAlgorithm<TVertex, TEdge> : AlgorithmBase<IVertexAndEdgeListGraph<TVertex, TEdge>>
where TEdge : IEdge<TVertex>
{
#region Private values
private readonly IDictionary<TVertex, int> layerIndices = new Dictionary<TVertex, int>(); //the index of the layer where the vertex belongs to
private readonly List<IList<TVertex>> layers = new List<IList<TVertex>>(); //the list of the vertices in the layers
private int layer; //gives the index of the actual layer
private readonly IMutableBidirectionalGraph<TVertex, TEdge> tmpGraph;
#endregion
#region Properties
/// <summary>
/// This dictionary contains the layer-index for every vertices.
/// </summary>
public IDictionary<TVertex, int> LayerIndices
{
get { return layerIndices; }
}
/// <summary>
/// The count of the layers in the graph.
/// </summary>
public int LayerCount
{
get { return layer; }
}
/// <summary>
/// The vertices grouped by their LayerIndex.
/// </summary>
public IList<IList<TVertex>> Layers
{
get { return layers; }
}
#endregion
public delegate void LayerFinishedDelegate( object sender, LayeredTopologicalSortEventArgs e );
public event LayerFinishedDelegate LayerFinished;
public LayeredTopologicalSortAlgorithm( IVertexAndEdgeListGraph<TVertex, TEdge> g )
: base( g )
{
tmpGraph = new BidirectionalGraph<TVertex, TEdge>();
//create a copy from the graph
tmpGraph.AddVertexRange( g.Vertices );
foreach ( var e in g.Edges )
tmpGraph.AddEdge( e );
}
protected override void InternalCompute()
{
//initializing the sources
var sources = GetSources( tmpGraph.Vertices );
//initializing the candidates (candidate for 'source' of the next layer)
var newSources = new HashSet<TVertex>();
for ( layer = 0; sources.Count != 0; layer++ )
{
foreach ( var s in sources )
{
layerIndices[s] = layer;
//get the neighbours of this source
var outNeighbours = tmpGraph.GetOutNeighbours( s );
//remove this source
tmpGraph.RemoveVertex( s );
//check if any of the neighbours became a source
foreach ( var n in outNeighbours )
if ( tmpGraph.IsInEdgesEmpty( n ) )
newSources.Add( n );
}
//the actual layer have been finished
layers.Add( sources );
OnLayerFinished( new LayeredTopologicalSortEventArgs
{
LayerIndex = layer,
Vertices = sources
} );
//prepare for the next layer
sources = newSources.ToList();
newSources = new HashSet<TVertex>();
}
//if the graph is not empty, it's a problem
if ( !tmpGraph.IsVerticesEmpty )
throw new NonAcyclicGraphException();
}
protected IList<TVertex> GetSources( IEnumerable<TVertex> vertices )
{
return ( from v in vertices
where tmpGraph.IsInEdgesEmpty( v )
select v ).ToList();
}
protected void OnLayerFinished( LayeredTopologicalSortEventArgs args )
{
if ( LayerFinished != null )
LayerFinished( this, args );
}
public class LayeredTopologicalSortEventArgs : EventArgs
{
public int LayerIndex { get; internal set; }
public IEnumerable<TVertex> Vertices { get; internal set; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dd2e54ae549170842bbac94cfcd0194a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b346539380c38444aa42035501f20594
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 59b531dac7b0fc440b9946b386c0dda4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Windows;
using QuickGraph;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound
{
public class CompoundLayoutContext<TVertex, TEdge, TGraph>
: LayoutContext<TVertex, TEdge, TGraph>, ICompoundLayoutContext<TVertex, TEdge, TGraph>
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
public CompoundLayoutContext(
TGraph graph,
IDictionary<TVertex, float2> positions,
IDictionary<TVertex, float2> sizes,
LayoutMode mode,
// IDictionary<TVertex, Thickness> vertexBorders,
IDictionary<TVertex, CompoundVertexInnerLayoutType> layoutTypes)
: base( graph, positions, sizes, mode )
{
// VertexBorders = vertexBorders;
LayoutTypes = layoutTypes;
}
// public IDictionary<TVertex, Thickness> VertexBorders { get; private set; }
public IDictionary<TVertex, CompoundVertexInnerLayoutType> LayoutTypes { get; private set; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 01aaa31a669873342a18865ecea141e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,34 @@
using System.Collections.Generic;
using QuickGraph;
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound
{
public class CompoundLayoutIterationEventArgs<TVertex, TEdge>
: LayoutIterationEventArgs<TVertex, TEdge>, ICompoundLayoutIterationEventArgs<TVertex>
where TVertex : class
where TEdge : IEdge<TVertex>
{
public CompoundLayoutIterationEventArgs(
int iteration,
double statusInPercent,
string message,
IDictionary<TVertex, float2> vertexPositions,
IDictionary<TVertex, float2> innerCanvasSizes)
: base(iteration, statusInPercent, message, vertexPositions)
{
InnerCanvasSizes = innerCanvasSizes;
}
#region ICompoundLayoutIterationEventArgs<TVertex> Members
public IDictionary<TVertex, float2> InnerCanvasSizes
{
get; private set;
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f2dc57d0a594b9741b197804e5c3cf47
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,10 @@
namespace GraphSharp.Algorithms.Layout.Compound
{
public enum CompoundVertexInnerLayoutType
{
Automatic,
ContextFree,
Contextual,
Fixed
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4587271fd90cae24e84685cdb311dc7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 751b64aba9e41e34cbcc3f2f0832f02e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,475 @@
using System;
using System.Diagnostics.Contracts;
using System.Windows;
using System.Linq;
using QuickGraph;
using System.Collections.Generic;
using System.Collections;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound.FDP
{
public partial class CompoundFDPLayoutAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IBidirectionalGraph<TVertex, TEdge>
{
/// <summary>
/// Informations for compound vertices.
/// </summary>
private readonly IDictionary<TVertex, CompoundVertexData> _compoundVertexDatas =
new Dictionary<TVertex, CompoundVertexData>();
/// <summary>
/// Informations for the simple vertices.
/// </summary>
private readonly IDictionary<TVertex, SimpleVertexData> _simpleVertexDatas =
new Dictionary<TVertex, SimpleVertexData>();
/// <summary>
/// Informations for all kind of vertices.
/// </summary>
private readonly IDictionary<TVertex, VertexData> _vertexDatas =
new Dictionary<TVertex, VertexData>();
/// <summary>
/// The levels of the graph (generated by the containment associations).
/// </summary>
private readonly IList<HashSet<TVertex>> _levels =
new List<HashSet<TVertex>>();
public IList<HashSet<TVertex>> Levels
{
get { return _levels; }
}
private class RemovedTreeNodeData<TVertex1, TEdge1>
{
public readonly TVertex1 Vertex;
public readonly TEdge1 Edge;
public RemovedTreeNodeData(TVertex1 vertex, TEdge1 edge)
{
Vertex = vertex;
Edge = edge;
}
}
/// <summary>
/// The list of the removed root-tree-nodes and edges by it's level
/// (level = distance from the closest not removed node).
/// </summary>
private readonly Stack<IList<RemovedTreeNodeData<TVertex,TEdge>>> _removedRootTreeNodeLevels =
new Stack<IList<RemovedTreeNodeData<TVertex,TEdge>>>();
private readonly HashSet<TVertex> _removedRootTreeNodes =
new HashSet<TVertex>();
private readonly HashSet<TEdge> _removedRootTreeEdges =
new HashSet<TEdge>();
/// <summary>
/// Temporary dictionary for the inner canvas sizes (do not depend on this!!! inside
/// the algorithm, use the vertexData objects instead).
/// </summary>
private IDictionary<TVertex, float2> _innerCanvasSizes;
/// <summary>
/// The dictionary of the initial vertex sizes.
/// DO NOT USE IT AFTER THE INITIALIZATION.
/// </summary>
private readonly IDictionary<TVertex, float2> _vertexSizes;
/// <summary>
/// The dictionary of the vertex bordex.
/// DO NOT USE IT AFTER THE INITIALIZATION.
/// </summary>
// private readonly IDictionary<TVertex, Thickness> _vertexBorders;
/// <summary>
/// The dictionary of the layout types of the compound vertices.
/// DO NOT USE IT AFTER THE INITIALIZATION.
/// </summary>
private readonly IDictionary<TVertex, CompoundVertexInnerLayoutType> _layoutTypes;
private readonly IMutableCompoundGraph<TVertex, TEdge> _compoundGraph;
/// <summary>
/// Represents the root vertex.
/// </summary>
private readonly CompoundVertexData _rootCompoundVertex =
new CompoundVertexData(
null, null, false, new float2(),
new float2(), //new Thickness(),
CompoundVertexInnerLayoutType.Automatic);
#region Constructors
public CompoundFDPLayoutAlgorithm(
TGraph visitedGraph,
IDictionary<TVertex, float2> vertexSizes,
// IDictionary<TVertex, Thickness> vertexBorders,
IDictionary<TVertex, CompoundVertexInnerLayoutType> layoutTypes)
: this(visitedGraph, vertexSizes, /*vertexBorders,*/ layoutTypes, null, null)
{
}
public CompoundFDPLayoutAlgorithm(
TGraph visitedGraph,
IDictionary<TVertex, float2> vertexSizes,
// IDictionary<TVertex, Thickness> vertexBorders,
IDictionary<TVertex, CompoundVertexInnerLayoutType> layoutTypes,
IDictionary<TVertex, float2> vertexPositions,
CompoundFDPLayoutParameters oldParameters)
: base(visitedGraph, vertexPositions, oldParameters)
{
_vertexSizes = vertexSizes;
//_vertexBorders = vertexBorders;
_layoutTypes = layoutTypes;
if (VisitedGraph is ICompoundGraph<TVertex, TEdge>)
_compoundGraph = new CompoundGraph<TVertex, TEdge>(VisitedGraph as ICompoundGraph<TVertex, TEdge>);
else
_compoundGraph = new CompoundGraph<TVertex, TEdge>(VisitedGraph);
}
#endregion
public int LevelOfVertex(TVertex vertex)
{
return _vertexDatas[vertex].Level;
}
#region ICompoundLayoutAlgorithm<TVertex,TEdge,TGraph> Members
public IDictionary<TVertex, float2> InnerCanvasSizes
{
get
{
return _compoundVertexDatas.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.InnerCanvasSize);
}
}
#endregion
#region Nested type: CompoundVertexData
/// <summary>
/// Data for the compound vertices.
/// </summary>
private class CompoundVertexData : VertexData
{
/// <summary>
/// The thickness of the borders of the compound vertex.
/// </summary>
// public readonly Thickness Borders;
/// <summary>
/// Gets the layout type of the compound vertex.
/// </summary>
public readonly CompoundVertexInnerLayoutType InnerVertexLayoutType;
private float2 _innerCanvasSize;
private float2 _size;
private ICollection<VertexData> _children;
public CompoundVertexData(TVertex vertex,
VertexData movableParent,
bool isFixedToParent,
float2 position,
float2 size,
// Thickness borders,
CompoundVertexInnerLayoutType innerVertexLayoutType)
: base(vertex, movableParent, isFixedToParent, position)
{
//Borders = borders;
//calculate the size of the inner canvas
InnerCanvasSize = new float2(max(0.0f, size.x),// - Borders.Left - Borders.Right
max(0.0f, size.y));// - Borders.Top - Borders.Bottom
InnerVertexLayoutType = innerVertexLayoutType;
}
/// <summary>
/// The size of the inner canvas of the compound vertex.
/// </summary>
public float2 InnerCanvasSize
{
get { return _innerCanvasSize; }
set
{
_innerCanvasSize = value;
//set the size of the canvas
_size = new float2(_innerCanvasSize.x,// + Borders.Left + Borders.Right,
_innerCanvasSize.y); //+ Borders.Top + Borders.Bottom
}
}
/// <summary>
/// The overall size of the vertex (inner canvas size + borders + ...).
/// </summary>
public override float2 Size
{
get { return _size; }
}
/// <summary>
/// Modifies the position of the children with the given
/// vector.
/// </summary>
/// <param name="force">The vector of the position modification.</param>
private void PropogateToChildren(float2 force)
{
foreach (var child in _children)
{
child.ApplyForce(force);
}
}
public ICollection<VertexData> Children
{
get { return _children; }
set
{
_children = value;
}
}
internal override void ApplyForce(float2 force)
{
Position += force;
PropogateToChildren(force);
RecalculateBounds();
}
public float2 InnerCanvasCenter
{
get
{
return new float2(
Position.x - Size.x / 2 + /*Borders.Left +*/ InnerCanvasSize.x / 2,
Position.y - Size.y / 2 + /*Borders.Top +*/ InnerCanvasSize.y / 2
);
}
set
{
Position = new float2(
value.x - InnerCanvasSize.x / 2 /*- Borders.Left*/ + Size.x / 2,
value.y - InnerCanvasSize.y / 2 /*- Borders.Top*/ + Size.y / 2
);
}
}
public void RecalculateBounds()
{
if (_children == null)
{
InnerCanvasSize = new float2(); //TODO padding
return;
}
float2 topLeft = new float2(float.PositiveInfinity, float.PositiveInfinity);
float2 bottomRight = new float2(float.NegativeInfinity, float.NegativeInfinity);
foreach (var child in _children)
{
topLeft.x = Math.Min(topLeft.x, child.Position.x - child.Size.x / 2);
topLeft.y = Math.Min(topLeft.y, child.Position.y - child.Size.y / 2);
bottomRight.x = Math.Max(bottomRight.x, child.Position.x + child.Size.x / 2);
bottomRight.y = Math.Max(bottomRight.y, child.Position.y + child.Size.y / 2);
}
InnerCanvasSize = new float2(bottomRight.y - topLeft.y, bottomRight.y - topLeft.y);
InnerCanvasCenter = new float2((topLeft.x + bottomRight.x) / 2.0f, (topLeft.y + bottomRight.y) / 2.0f);
}
}
#endregion
#region Nested type: SimpleVertexData
private class SimpleVertexData : VertexData
{
/// <summary>
/// The size of the vertex.
/// </summary>
private readonly float2 _size;
public SimpleVertexData(TVertex vertex, VertexData movableParent, bool isFixed, float2 position, float2 size)
: base(vertex, movableParent, isFixed, position)
{
_size = size;
}
/// <summary>
/// Gets the actual size of the vertex (inner size + border + anything else...).
/// </summary>
public override float2 Size
{
get { return _size; }
}
internal override void ApplyForce(float2 force)
{
Position += force;
}
}
#endregion
#region Nested type: VertexData
/// <summary>
/// Data for the simple vertices.
/// </summary>
private abstract class VertexData
{
/// <summary>
/// Gets the vertex which is wrapped by this object.
/// </summary>
public readonly TVertex Vertex;
public CompoundVertexData Parent;
private float2 _springForce;
private float2 _repulsionForce;
private float2 _gravitationForce;
private float2 _applicationForce;
private float2 _previousForce;
private float2 _childrenForce;
protected VertexData _movableParent;
protected VertexData(TVertex vertex, VertexData movableParent, bool isFixedToParent, float2 position)
{
Vertex = vertex;
MovableParent = movableParent;
IsFixedToParent = isFixedToParent;
Parent = null;
Position = position;
}
/// <summary>
/// If the vertex is fixed (cannot be moved), that's it's parent
/// that could be moved (if there's any).
///
/// This property can only be set once.
/// </summary>
public VertexData MovableParent
{
get { return _movableParent; }
set
{
_movableParent = value;
}
}
/// <summary>
/// Gets or sets that the position of the vertex is fixed to
/// it's parent vertex or not.
/// </summary>
public bool IsFixedToParent { get; set; }
/// <summary>
/// Gets the actual size of the vertex (inner size + border + anything else...).
/// </summary>
public abstract float2 Size { get; }
/// <summary>
/// The level of the vertex inside the graph.
/// </summary>
public int Level;
/// <summary>
/// The position of the vertex.
/// </summary>
public float2 Position;
/// <summary>
/// Gets or sets the spring force.
/// </summary>
public float2 SpringForce
{
get { return IsFixedToParent ? new float2() : _springForce; }
set
{
if (IsFixedToParent)
_springForce = new float2();
else _springForce = value;
}
}
/// <summary>
/// Gets or sets the spring force.
/// </summary>
public float2 RepulsionForce
{
get { return IsFixedToParent ? new float2() : _repulsionForce; }
set
{
if (IsFixedToParent)
_repulsionForce = new float2();
else _repulsionForce = value;
}
}
/// <summary>
/// Gets or sets the spring force.
/// </summary>
public float2 GravitationForce
{
get { return IsFixedToParent ? new float2() : _gravitationForce; }
set
{
if (IsFixedToParent)
_gravitationForce = new float2();
else _gravitationForce = value;
}
}
/// <summary>
/// Gets or sets the spring force.
/// </summary>
public float2 ApplicationForce
{
get { return IsFixedToParent ? new float2() : _applicationForce; }
set
{
if (IsFixedToParent)
_applicationForce = new float2();
else _applicationForce = value;
}
}
internal abstract void ApplyForce(float2 force);
public float2 ApplyForce(float limit)
{
var force = _springForce
+ _repulsionForce
+ _gravitationForce
+ _applicationForce
+ 0.5f * _childrenForce;
Parent._childrenForce += force;
if (length(force) > limit)
force *= limit / length(force);
force += 0.7f * _previousForce;
if (length(force) > limit)
force *= limit / length(force);
ApplyForce(force);
_springForce = new float2();
_repulsionForce = new float2();
_gravitationForce = new float2();
_applicationForce = new float2();
_childrenForce = new float2();
_previousForce = force;
return force;
}
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04f6319aebf16be48b7d36d70101d150
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,278 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using QuickGraph;
using System;
using System.Diagnostics.Contracts;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound.FDP
{
public partial class CompoundFDPLayoutAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IBidirectionalGraph<TVertex, TEdge>
{
private static void RemoveAll<T>(ICollection<T> set, IEnumerable<T> elements)
{
foreach (var e in elements)
{
set.Remove(e);
}
}
/// <summary>
/// <list type="ul">
/// <listheader>
/// Initializes the algorithm, and the following things:
/// </listheader>
/// <item>the nodes sizes (of the compound vertices)</item>
/// <item>the thresholds for the convergence</item>
/// <item>random initial positions (if the position is not null)</item>
/// <item>remove the 'tree-nodes' from the root graph (level 0)</item>
/// </list>
/// </summary>
/// <param name="vertexSizes">The dictionary of the inner canvas sizes
/// of the compound vertices.</param>
/// <param name="vertexBorders">The dictionary of the border thickness of
/// the compound vertices.</param>
/// <param name="layoutTypes">The dictionary of the layout types of
/// the compound vertices.</param>
private void Init(IDictionary<TVertex, float2> vertexSizes, /*IDictionary<TVertex, Thickness> vertexBorders, */IDictionary<TVertex, CompoundVertexInnerLayoutType> layoutTypes)
{
InitializeWithRandomPositions(100, 100);
var movableParentUpdateQueue = new Queue<TVertex>();
_rootCompoundVertex.Children = new HashSet<VertexData>();
InitialLevels();
InitSimpleVertices(vertexSizes);
InitCompoundVertices(/*vertexBorders, */vertexSizes, layoutTypes, /*out*/ movableParentUpdateQueue);
SetLevelIndices();
//TODO do we need this?
InitMovableParentOfFixedVertices(movableParentUpdateQueue);
RemoveTreeNodesFromRootGraph();
InitGravitationMagnitude();
}
private void InitGravitationMagnitude()
{
//get the average width and height
float sumWidth = 0, sumHeight = 0;
foreach (var vertex in _levels[0])
{
var v = _vertexDatas[vertex];
sumWidth += v.Size.x;
sumHeight += v.Size.y;
}
if (_levels[0].Count > 0)
_gravityForceMagnitude = min(sumWidth, sumHeight) / _levels[0].Count;
}
private void RemoveTreeNodesFromRootGraph()
{
bool removed = true;
for (int i = 0; removed; i++)
{
removed = false;
foreach (var vertex in _levels[0])
{
if (_compoundGraph.Degree(vertex) != 1 || _compoundGraph.IsCompoundVertex(vertex))
continue;
TEdge edge = default(TEdge);
if (_compoundGraph.InDegree(vertex) > 0)
edge = _compoundGraph.InEdge(vertex, 0);
else
edge = _compoundGraph.OutEdge(vertex, 0);
if (_removedRootTreeEdges.Contains(edge))
continue;
//the vertex is a leaf tree node
removed = true;
while (_removedRootTreeNodeLevels.Count <= i)
_removedRootTreeNodeLevels.Push(new List<RemovedTreeNodeData<TVertex,TEdge>>());
//add to the removed vertices
_removedRootTreeNodeLevels.Peek().Add(new RemovedTreeNodeData<TVertex,TEdge>(vertex, edge));
_removedRootTreeNodes.Add(vertex);
_removedRootTreeEdges.Add(edge);
}
if (removed && _removedRootTreeNodeLevels.Count > 0)
//remove from the level
foreach (var tnd in _removedRootTreeNodeLevels.Peek())
{
_levels[0].Remove(tnd.Vertex);
//remove the vertex from the graph
_compoundGraph.RemoveEdge(tnd.Edge);
_compoundGraph.RemoveVertex(tnd.Vertex);
}
}
}
private void InitMovableParentOfFixedVertices(Queue<TVertex> movableParentUpdateQueue)
{
while (movableParentUpdateQueue.Count > 0)
{
//geth the compound vertex with the fixed layout
var fixedLayoutedCompoundVertex = movableParentUpdateQueue.Dequeue();
//find the not fixed predecessor
TVertex movableVertex = fixedLayoutedCompoundVertex;
for (; ; )
{
//if the vertex hasn't parent
if (movableVertex == null)
break;
TVertex parent = _compoundGraph.GetParent(movableVertex);
if (parent == null)
break;
//if the parent's layout type is fixed
if (_compoundVertexDatas[parent].InnerVertexLayoutType != CompoundVertexInnerLayoutType.Fixed)
break;
movableVertex = parent;
}
//the movable vertex is the ancestor of the children of the vertex
//that could be moved
//fix the child vertices and set the movable parent
foreach (var childVertex in _compoundGraph.GetChildrenVertices(fixedLayoutedCompoundVertex))
{
var data = _vertexDatas[childVertex];
data.IsFixedToParent = true;
data.MovableParent = _vertexDatas[movableVertex];
}
}
}
/// <summary>
/// Initializes the data of the simple vertices.
/// </summary>
/// <param name="vertexSizes">Dictionary of the vertex sizes.</param>
private void InitSimpleVertices(IDictionary<TVertex, float2> vertexSizes)
{
foreach (var vertex in _compoundGraph.SimpleVertices)
{
float2 vertexSize;
vertexSizes.TryGetValue(vertex, out vertexSize);
var position = new float2();
VertexPositions.TryGetValue(vertex, out position);
//create the information container for this simple vertex
var dataContainer = new SimpleVertexData(vertex, _rootCompoundVertex, false, position, vertexSize);
dataContainer.Parent = _rootCompoundVertex;
_simpleVertexDatas[vertex] = dataContainer;
_vertexDatas[vertex] = dataContainer;
_rootCompoundVertex.Children.Add(dataContainer);
}
}
/// <summary>
/// Initializes the data of the compound vertices.
/// </summary>
/// <param name="vertexBorders">Dictionary of the border thicknesses.</param>
/// <param name="vertexSizes">Dictionary of the vertex sizes.</param>
/// <param name="layoutTypes">Dictionary of the layout types.</param>
/// <param name="movableParentUpdateQueue">The compound vertices with fixed layout
/// should be added to this queue.</param>
private void InitCompoundVertices(
//IDictionary<TVertex, Thickness> vertexBorders,
IDictionary<TVertex, float2> vertexSizes,
IDictionary<TVertex, CompoundVertexInnerLayoutType> layoutTypes,
Queue<TVertex> movableParentUpdateQueue)
{
for (int i = _levels.Count - 1; i >= 0; i--)
{
foreach (var vertex in _levels[i])
{
if (!_compoundGraph.IsCompoundVertex(vertex))
continue;
//get the data of the vertex
// Thickness border;
// vertexBorders.TryGetValue(vertex, out border);
float2 vertexSize;
vertexSizes.TryGetValue(vertex, out vertexSize);
var layoutType = CompoundVertexInnerLayoutType.Automatic;
layoutTypes.TryGetValue(vertex, out layoutType);
if (layoutType == CompoundVertexInnerLayoutType.Fixed)
{
movableParentUpdateQueue.Enqueue(vertex);
}
var position = new float2();
VertexPositions.TryGetValue(vertex, out position);
//create the information container for this compound vertex
var dataContainer = new CompoundVertexData(vertex, _rootCompoundVertex, false, position, vertexSize, /*border, */layoutType);
if (i == 0)
{
dataContainer.Parent = _rootCompoundVertex;
_rootCompoundVertex.Children.Add(dataContainer);
}
_compoundVertexDatas[vertex] = dataContainer;
_vertexDatas[vertex] = dataContainer;
//add the datas of the childrens
var children = _compoundGraph.GetChildrenVertices(vertex);
var childrenData = children.Select(v => _vertexDatas[v]).ToList();
dataContainer.Children = childrenData;
foreach (var child in dataContainer.Children)
{
_rootCompoundVertex.Children.Remove(child);
child.Parent = dataContainer;
}
}
}
}
private void InitialLevels()
{
var verticesLeft = new HashSet<TVertex>(VisitedGraph.Vertices);
//initial 0th level
_levels.Add(new HashSet<TVertex>(VisitedGraph.Vertices.Where(v => _compoundGraph.GetParent(v) == default(TVertex))));
RemoveAll(verticesLeft, _levels[0]);
//other layers
for (int i = 1; verticesLeft.Count > 0; i++)
{
var nextLevel = new HashSet<TVertex>();
foreach (var parent in _levels[i - 1])
{
if (_compoundGraph.GetChildrenCount(parent) <= 0)
continue;
foreach (var children in _compoundGraph.GetChildrenVertices(parent))
nextLevel.Add(children);
}
_levels.Add(nextLevel);
RemoveAll(verticesLeft, nextLevel);
}
}
private void SetLevelIndices()
{
//set the level indexes in the vertex datas
for (int i = 0; i < _levels.Count; i++)
{
foreach (var v in _levels[i])
_vertexDatas[v].Level = i;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfb500bde641d9b42a21f471a6359c29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,399 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using QuickGraph;
using System.Diagnostics.Contracts;
using System.Diagnostics;
using Unity.Mathematics;
using static Unity.Mathematics.math;
using Random = System.Random;
namespace GraphSharp.Algorithms.Layout.Compound.FDP
{
/// <typeparam name="TVertex">The type of the vertices.</typeparam>
/// <typeparam name="TEdge">The type of the edges.</typeparam>
/// <typeparam name="TGraph">The type of the graph.</typeparam>
public partial class CompoundFDPLayoutAlgorithm<TVertex, TEdge, TGraph> :
DefaultParameterizedLayoutAlgorithmBase<TVertex, TEdge, TGraph, CompoundFDPLayoutParameters>,
ICompoundLayoutAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IBidirectionalGraph<TVertex, TEdge>
{
/*[ContractInvariantMethod]
private void InvariantContracts()
{
Contract.Invariant(1 <= _phase && _phase <= 3);
Contract.Invariant(_treeGrowingStep > 0);
}*/
private float _temperature = 0;
private float _temperatureDelta; //need to be initialized
private readonly float _temperatureLambda = 0.99f;
private readonly Random rnd = new Random(DateTime.Now.Millisecond);
/// <summary>
/// <para>Phase of the layout process.</para>
/// <para>Values: 1,2,3</para>
/// </summary>
private int _phase = 1;
/// <summary>
/// The steps in the actual phase.
/// </summary>
private int _step;
/// <summary>
/// The maximal iteration count in the phases.
/// </summary>
private /*readonly*/ int[] _maxIterationCounts = new int[3] { 30, 70, 50 };
/// <summary>
/// The error thresholds for the phases (calculated inside the Init method).
/// </summary>
private readonly float[] _errorThresholds = new float[3];
/// <summary>
/// Indicates whether the removed tree-node
/// has been grown back or not.
/// </summary>
private bool _allTreesGrown
{
get { return _removedRootTreeNodeLevels.Count == 0; }
}
/// <summary>
/// Grows back a tree-node level in every 'treeGrowingStep'th step.
/// </summary>
private int _treeGrowingStep = 5;
/// <summary>
/// The magnitude of the gravity force calculated in the init phased.
/// </summary>
private float _gravityForceMagnitude;
/// <summary>
/// Has been the gravity center initiated or not.
/// </summary>
private bool _gravityCenterCalculated;
private float _phaseDependentRepulsionMultiplier = 1.0f;
/// <summary>
/// This method is the skeleton of the layout algorithm.
/// </summary>
protected override void InternalCompute()
{
//call initialize
Init(_vertexSizes, /*_vertexBorders,*/ _layoutTypes);
//Phases:
//1: layout the skeleton graph without app. specific and gravitation forces.
//2: add the removed tree nodes and apply app. specific and gravitation forces.
//3: stabilization
/* ********* FOR OPTIMIZATION PURPOSES ********** */
_maxIterationCounts = new int[3];
_maxIterationCounts[0] = Parameters.Phase1Iterations;
_maxIterationCounts[1] = Parameters.Phase2Iterations;
_maxIterationCounts[2] = Parameters.Phase3Iterations;
var _temperatureMultipliers = new float[3]
{
1.0f,
Parameters.Phase2TemperatureInitialMultiplier,
Parameters.Phase3TemperatureInitialMultiplier
};
float initialTemperature = sqrt(_compoundGraph.VertexCount) * Parameters.IdealEdgeLength;
float minimalTemperature = initialTemperature * 0.1f;
_temperature = initialTemperature;
_gravityCenterCalculated = false;
for (_phase = 1; _phase <= 3; _phase++)
{
_temperature = initialTemperature * _temperatureMultipliers[_phase - 1];
_phaseDependentRepulsionMultiplier = _phase < 2 ? 0.5f : 1.0f;
//TODO put back the error and its threshold
/*float error = _errorThresholds[_phase] + 1;*/
for (_step = _maxIterationCounts[_phase - 1];
(_step > 0 && true/*error > _errorThresholds[_phase - 1] */) || (_phase == 2 && !_allTreesGrown);
_step--)
{
/*error = 0;*/
ApplySpringForces();
ApplyRepulsionForces();
if (_phase > 1)
{
ApplyGravitationForces();
ApplyApplicationSpecificForces();
}
if (ReportOnIterationEndNeeded)
SavePositions();
CalcNodePositionsAndSizes();
if (_phase == 2 && !_allTreesGrown && _step % _treeGrowingStep == 0)
GrowTreesOneLevel();
_temperature *= _temperatureLambda;
_temperature = Math.Max(_temperature, minimalTemperature);
}
if (!_gravityCenterCalculated)
{
_rootCompoundVertex.RecalculateBounds();
_gravityCenterCalculated = true;
}
//if (_phase == 1)
_temperature *= Parameters.TemperatureDecreasing;
}
SavePositions();
}
private void SavePositions()
{
foreach (var vertex in _vertexDatas.Keys)
{
var v = _vertexDatas[vertex];
VertexPositions[vertex] = v.Position;
}
/*var iterationEndedArgs =
new CompoundLayoutIterationEventArgs<TVertex, TEdge>(
0, 0, string.Empty,
VertexPositions,
InnerCanvasSizes);*/
//build the test vertex infos
var vertexInfos = _vertexDatas.ToDictionary(
kvp => kvp.Key,
kvp => new TestingCompoundVertexInfo(
kvp.Value.SpringForce,
kvp.Value.RepulsionForce,
kvp.Value.GravitationForce,
kvp.Value.ApplicationForce));
var iterationEndedArgs =
new TestingCompoundLayoutIterationEventArgs<TVertex, TEdge, TestingCompoundVertexInfo, object>(
0, 0, string.Format("Phase: {0}, Steps: {1}", _phase, _step),
VertexPositions,
InnerCanvasSizes,
vertexInfos,
_rootCompoundVertex.InnerCanvasCenter);
//raise the event
OnIterationEnded(iterationEndedArgs);
}
private void GrowTreesOneLevel()
{
if (_removedRootTreeNodeLevels.Count <= 0)
return;
var treeNodeDatas = _removedRootTreeNodeLevels.Pop();
foreach (var tnd in treeNodeDatas)
{
_removedRootTreeNodes.Remove(tnd.Vertex);
_removedRootTreeEdges.Remove(tnd.Edge);
_levels[0].Add(tnd.Vertex);
_compoundGraph.AddVertex(tnd.Vertex);
_compoundGraph.AddEdge(tnd.Edge);
var otherVertex = tnd.Edge.GetOtherVertex(tnd.Vertex);
_vertexDatas[tnd.Vertex].Position = _vertexDatas[otherVertex].Position;
}
}
private float2 GetSpringForce(float idealLength, float2 uPos, float2 vPos, float2 uSize, float2 vSize)
{
var positionVector = (uPos - vPos);
if (abs(math.length(positionVector)) < .001f)
{
var compensationVector = new float2((float) rnd.NextDouble(), (float) rnd.NextDouble());
positionVector = compensationVector * 2;
uPos += compensationVector;
vPos -= compensationVector;
}
positionVector = normalize(positionVector);
//get the clipping points
var c_u = LayoutUtil.GetClippingPoint(uSize, uPos, vPos);
var c_v = LayoutUtil.GetClippingPoint(vSize, vPos, uPos);
float2 F = (c_u - c_v);
bool isSameDirection = LayoutUtil.IsSameDirection(positionVector, F);
float length = 0;
if (isSameDirection)
length = math.length(F) - idealLength;
else
length = math.length(F) + idealLength;
if (abs(math.length(F)) < .001f)
F = -positionVector;
F = normalize(F);
if (length > 0)
F *= -1;
var Fs = pow(length / (idealLength), 2) / Parameters.ElasticConstant * F;
return Fs;
}
private float2 GetRepulsionForce(float2 uPos, float2 vPos, float2 uSize, float2 vSize, float repulsionRange)
{
var positionVector = (uPos - vPos);
if (math.length(positionVector) == 0)
{
var compensationVector = new float2((float) rnd.NextDouble(), (float) rnd.NextDouble());
positionVector = compensationVector * 2;
uPos += compensationVector;
vPos -= compensationVector;
}
positionVector = normalize(positionVector);
var c_u = LayoutUtil.GetClippingPoint(uSize, uPos, vPos);
var c_v = LayoutUtil.GetClippingPoint(vSize, vPos, uPos);
var F = c_u - c_v;
var isSameDirection = LayoutUtil.IsSameDirection(positionVector, F);
var Fr = new float2();
if (isSameDirection && math.length(F) > repulsionRange)
return new float2();
float length = Math.Max(1, math.length(F));
//float length = F.LengthSquared;
length = pow(isSameDirection ? length / (Parameters.IdealEdgeLength * 2.0f) : 1 / length, 2);
Fr = Parameters.RepulsionConstant / length * positionVector * _phaseDependentRepulsionMultiplier;
return Fr;
}
/// <summary>
/// Applies the attraction forces (between the end nodes
/// of the edges).
/// </summary>
private void ApplySpringForces()
{
foreach (var edge in VisitedGraph.Edges)
{
if (!_allTreesGrown && (_removedRootTreeNodes.Contains(edge.Source) || _removedRootTreeNodes.Contains(edge.Target)))
continue;
//get the ideal edge length
float idealLength = Parameters.IdealEdgeLength;
var u = _vertexDatas[edge.Source];
var v = _vertexDatas[edge.Target];
var multiplier = (u.Level + v.Level) / 2.0f + 1;
if (IsInterGraphEdge(edge))
{
//idealLength *= (u.Level + v.Level + 1) * Parameters.NestingFactor;
idealLength *= 1 + (u.Level + v.Level + 1) * Parameters.NestingFactor;
//multiplier = 1;
}
var Fs = GetSpringForce(idealLength, u.Position, v.Position, u.Size, v.Size) * multiplier;
//aggregate the forces
if ((u.IsFixedToParent && u.MovableParent == null) ^ (v.IsFixedToParent && v.MovableParent == null))
Fs *= 2;
if (!u.IsFixedToParent)
u.SpringForce += Fs /* * u.Mass / (u.Mass + v.Mass)*/;
else if (u.MovableParent != null)
{
u.MovableParent.SpringForce += Fs;
}
if (!v.IsFixedToParent)
v.SpringForce -= Fs /* * v.Mass / (u.Mass + v.Mass)*/;
else if (v.MovableParent != null)
{
v.MovableParent.SpringForce -= Fs;
}
}
}
/// <summary>
/// Applies the repulsion forces between every node-pair.
/// </summary>
private void ApplyRepulsionForces()
{
var repulsionRange = Parameters.IdealEdgeLength * Parameters.SeparationMultiplier;
for (int i = _levels.Count - 1; i >= 0; i--)
{
var checkedVertices = new HashSet<TVertex>();
foreach (var uVertex in _levels[i])
{
checkedVertices.Add(uVertex);
var u = _vertexDatas[uVertex];
foreach (var vVertex in _levels[i])
{
if (checkedVertices.Contains(vVertex))
continue;
var v = _vertexDatas[vVertex];
if (u.Parent != v.Parent)
continue; //the two vertex not in the same graph
var Fr = GetRepulsionForce(u.Position, v.Position, u.Size, v.Size, repulsionRange) * pow(u.Level + 1,2);
if (u.IsFixedToParent ^ v.IsFixedToParent)
Fr *= 2;
if (!u.IsFixedToParent)
u.RepulsionForce += Fr /** u.Mass / (u.Mass + v.Mass)*/;
if (!v.IsFixedToParent)
v.RepulsionForce -= Fr /** v.Mass / (u.Mass + v.Mass)*/;
}
}
}
}
/// <summary>
/// Applies the gravitation forces.
/// </summary>
private void ApplyGravitationForces()
{
for (int i = _levels.Count - 1; i >= 0; i--)
{
foreach (var uVertex in _levels[i])
{
var u = _vertexDatas[uVertex];
var center = u.Parent.InnerCanvasCenter;
var Fg = center - u.Position;
if (math.length(Fg) < .001f)
continue;
float length = Math.Max(1, math.length(Fg) / (Parameters.IdealEdgeLength * 2.0f));
Fg = normalize(Fg);
Fg *= Parameters.GravitationFactor * _gravityForceMagnitude * pow(u.Level + 1,2) / pow(length, 0.25f);
u.GravitationForce += Fg;
}
}
}
/// <summary>
/// Applies the application specific forces to the vertices.
/// </summary>
protected virtual void ApplyApplicationSpecificForces()
{
}
private void CalcNodePositionsAndSizes()
{
for (int i = _levels.Count - 1; i >= 0; i--)
{
foreach (var uVertex in _levels[i])
{
var u = _vertexDatas[uVertex];
var force = u.ApplyForce(_temperature * max(1, _step) / 100.0f * Parameters.DisplacementLimitMultiplier);
}
}
}
private bool IsInterGraphEdge(TEdge e)
{
return _vertexDatas[e.Source].Parent != _vertexDatas[e.Target].Parent;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18b1a2cf0e101ee4cb799f53aebfff4c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,222 @@
namespace GraphSharp.Algorithms.Layout.Compound.FDP
{
public class CompoundFDPLayoutParameters : LayoutParametersBase
{
private float _idealEdgeLength = 25;
private float _elasticConstant = 0.005f;
private float _repulsionConstant = 150;
private float _nestingFactor = 0.2f;
private float _gravitationFactor = 8;
private int _phase1Iterations = 50;
private int _phase2Iterations = 70;
private int _phase3Iterations = 30;
private float _phase2TemperatureInitialMultiplier = 0.5f;
private float _phase3TemperatureInitialMultiplier = 0.2f;
private float _temperatureDecreasing = 0.5f;
private float _temperatureFactor = 0.95f;
private float _displacementLimitMultiplier = 0.5f;
private float _separationMultiplier = 15;
/// <summary>
/// Gets or sets the ideal edge length.
/// </summary>
public float IdealEdgeLength
{
get { return _idealEdgeLength; }
set
{
if (value == _idealEdgeLength)
return;
_idealEdgeLength = value;
NotifyPropertyChanged("IdealEdgeLength");
}
}
/// <summary>
/// Gets or sets the elastic constant for the edges.
/// </summary>
public float ElasticConstant
{
get { return _elasticConstant; }
set
{
if (value == _elasticConstant)
return;
_elasticConstant = value;
NotifyPropertyChanged("ElasticConstant");
}
}
/// <summary>
/// Gets or sets the repulsion constant for the node-node
/// repulsion.
/// </summary>
public float RepulsionConstant
{
get { return _repulsionConstant; }
set
{
if (value == _repulsionConstant)
return;
_repulsionConstant = value;
NotifyPropertyChanged("RepulsionConstant");
}
}
/// <summary>
/// Gets or sets the factor of the ideal edge length for the
/// inter-graph edges.
/// </summary>
public float NestingFactor
{
get { return _nestingFactor; }
set
{
if (value == _nestingFactor)
return;
_nestingFactor = value;
NotifyPropertyChanged("NestingFactor");
}
}
/// <summary>
/// Gets or sets the factor of the gravitation.
/// </summary>
public float GravitationFactor
{
get { return _gravitationFactor; }
set
{
if (value == _gravitationFactor)
return;
_gravitationFactor = value;
NotifyPropertyChanged("GravitationFactor");
}
}
public int Phase1Iterations
{
get { return _phase1Iterations; }
set
{
if (value == _phase1Iterations)
return;
_phase1Iterations = value;
NotifyPropertyChanged("Phase1Iterations");
}
}
public int Phase2Iterations
{
get { return _phase2Iterations; }
set
{
if (value == _phase2Iterations)
return;
_phase2Iterations = value;
NotifyPropertyChanged("Phase2Iterations");
}
}
public int Phase3Iterations
{
get { return _phase3Iterations; }
set
{
if (value == _phase3Iterations)
return;
_phase3Iterations = value;
NotifyPropertyChanged("Phase3Iterations");
}
}
public float Phase2TemperatureInitialMultiplier
{
get { return _phase2TemperatureInitialMultiplier; }
set
{
if (value == _phase2TemperatureInitialMultiplier)
return;
_phase2TemperatureInitialMultiplier = value;
NotifyPropertyChanged("Phase2TemperatureInitialMultiplier");
}
}
public float Phase3TemperatureInitialMultiplier
{
get { return _phase3TemperatureInitialMultiplier; }
set
{
if (value == _phase3TemperatureInitialMultiplier)
return;
_phase3TemperatureInitialMultiplier = value;
NotifyPropertyChanged("Phase3TemperatureInitialMultiplier");
}
}
public float TemperatureDecreasing
{
get { return _temperatureDecreasing; }
set
{
if (value == _temperatureDecreasing)
return;
_temperatureDecreasing = value;
NotifyPropertyChanged("TemperatureDecreasing");
}
}
public float TemperatureFactor
{
get { return _temperatureFactor; }
set
{
if (value == _temperatureFactor)
return;
_temperatureFactor = value;
NotifyPropertyChanged("TemperatureFactor");
}
}
public float DisplacementLimitMultiplier
{
get { return _displacementLimitMultiplier; }
set
{
if (value == _displacementLimitMultiplier)
return;
_displacementLimitMultiplier = value;
NotifyPropertyChanged("DisplacementLimitMultiplier");
}
}
public float SeparationMultiplier
{
get { return _separationMultiplier; }
set
{
if (value == _separationMultiplier)
return;
_separationMultiplier = value;
NotifyPropertyChanged("SeparationMultiplier");
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb985b217904cfb40a64fc91d7846140
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Windows;
using QuickGraph;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound
{
public interface ICompoundLayoutAlgorithm<TVertex, TEdge, TGraph> : ILayoutAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IBidirectionalGraph<TVertex, TEdge>
{
IDictionary<TVertex, float2> InnerCanvasSizes { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e4cf28522a9e174e88fbe8ba7aa302b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,14 @@
using System.Collections.Generic;
using QuickGraph;
using System.Windows;
namespace GraphSharp.Algorithms.Layout.Compound
{
public interface ICompoundLayoutContext<TVertex, TEdge, TGraph> : ILayoutContext<TVertex, TEdge, TGraph>
where TEdge : IEdge<TVertex>
where TGraph : IBidirectionalGraph<TVertex, TEdge>
{
// IDictionary<TVertex, Thickness> VertexBorders { get; }
IDictionary<TVertex, CompoundVertexInnerLayoutType> LayoutTypes { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 05b8cb2e16ce46b40935e68b560a7547
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound
{
public interface ICompoundLayoutIterationEventArgs<TVertex>
: ILayoutIterationEventArgs<TVertex>
where TVertex : class
{
IDictionary<TVertex, float2> InnerCanvasSizes { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0f86aed8aefca354f88d2d60172c1b3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using QuickGraph;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound
{
public class TestingCompoundLayoutIterationEventArgs<TVertex, TEdge, TVertexInfo, TEdgeInfo>
: CompoundLayoutIterationEventArgs<TVertex, TEdge>, ILayoutInfoIterationEventArgs<TVertex, TEdge, TVertexInfo, TEdgeInfo>
where TVertex : class
where TEdge : IEdge<TVertex>
{
private IDictionary<TVertex, TVertexInfo> vertexInfos;
public float2 GravitationCenter { get; private set; }
public TestingCompoundLayoutIterationEventArgs(
int iteration,
double statusInPercent,
string message,
IDictionary<TVertex, float2> vertexPositions,
IDictionary<TVertex, float2> innerCanvasSizes,
IDictionary<TVertex, TVertexInfo> vertexInfos,
float2 gravitationCenter)
: base(iteration, statusInPercent, message, vertexPositions, innerCanvasSizes)
{
this.vertexInfos = vertexInfos;
this.GravitationCenter = gravitationCenter;
}
public override object GetVertexInfo(TVertex vertex)
{
TVertexInfo info = default(TVertexInfo);
if (vertexInfos.TryGetValue(vertex, out info))
return info;
return null;
}
public IDictionary<TVertex, TVertexInfo> VertexInfos
{
get { return this.vertexInfos; }
}
public IDictionary<TEdge, TEdgeInfo> EdgeInfos
{
get { return null; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2749eb7cc688780428b6826a1bb9f799
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Compound
{
public class TestingCompoundVertexInfo
{
public TestingCompoundVertexInfo(float2 springForce, float2 repulsionForce, float2 gravityForce, float2 applicationForce)
{
SpringForce = springForce;
RepulsionForce = repulsionForce;
GravityForce = gravityForce;
ApplicationForce = applicationForce;
}
public float2 SpringForce { get; set; }
public float2 RepulsionForce { get; set; }
public float2 GravityForce { get; set; }
public float2 ApplicationForce { get; set; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f49438cc322bc5840aecb2cd2f78dabe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 91bee5591d233f24db1aa32e4f3a0243
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,74 @@
using System.Collections.Generic;
using System.Linq;
using QuickGraph;
using GraphSharp.Algorithms.Layout.Simple.Tree;
namespace GraphSharp.Algorithms.Layout.Contextual
{
public class ContextualLayoutAlgorithmFactory<TVertex, TEdge, TGraph> : IContextualLayoutAlgorithmFactory<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
private readonly string[] algorithmTypes = new[] { "DoubleTree", "BalloonTree" };
public IEnumerable<string> AlgorithmTypes
{
get { return algorithmTypes; }
}
public ILayoutAlgorithm<TVertex, TEdge, TGraph> CreateAlgorithm( string newAlgorithmType, ILayoutContext<TVertex, TEdge, TGraph> context, ILayoutParameters parameters )
{
var layoutContext = context as ContextualLayoutContext<TVertex, TEdge, TGraph>;
switch ( newAlgorithmType )
{
case "DoubleTree":
return new DoubleTreeLayoutAlgorithm<TVertex, TEdge, TGraph>( layoutContext.Graph, layoutContext.Positions, layoutContext.Sizes, parameters as DoubleTreeLayoutParameters, layoutContext.SelectedVertex );
case "BalloonTree":
return new BalloonTreeLayoutAlgorithm<TVertex, TEdge, TGraph>( layoutContext.Graph, layoutContext.Positions, layoutContext.Sizes, parameters as BalloonTreeLayoutParameters, layoutContext.SelectedVertex );
default:
return null;
}
}
public ILayoutParameters CreateParameters( string algorithmType, ILayoutParameters oldParameters )
{
switch ( algorithmType )
{
case "DoubleTree":
return !( oldParameters is DoubleTreeLayoutParameters ) ? new DoubleTreeLayoutParameters() : (DoubleTreeLayoutParameters)( oldParameters as DoubleTreeLayoutParameters ).Clone();
case "BaloonTree":
return !( oldParameters is BalloonTreeLayoutParameters ) ? new BalloonTreeLayoutParameters() : (BalloonTreeLayoutParameters)( oldParameters as BalloonTreeLayoutParameters ).Clone();
default:
return null;
}
}
public string GetAlgorithmType( ILayoutAlgorithm<TVertex, TEdge, TGraph> algorithm )
{
if ( algorithm is DoubleTreeLayoutAlgorithm<TVertex, TEdge, TGraph> )
return "DoubleTree";
if ( algorithm is BalloonTreeLayoutAlgorithm<TVertex, TEdge, TGraph> )
return "BalloonTree";
return string.Empty;
}
public bool IsValidAlgorithm( string algorithmType )
{
return ( AlgorithmTypes.Contains( algorithmType ) );
}
public bool NeedEdgeRouting( string algorithmType )
{
return true;
}
public bool NeedOverlapRemoval( string algorithmType )
{
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b08537ed969a3b489a3544360dbc2bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
using QuickGraph;
using System.Windows;
using System.Diagnostics.Contracts;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Contextual
{
public class ContextualLayoutContext<TVertex, TEdge, TGraph> : LayoutContext<TVertex, TEdge, TGraph>
where TEdge : IEdge<TVertex>
where TGraph : IVertexAndEdgeListGraph<TVertex, TEdge>
{
public TVertex SelectedVertex { get; private set; }
public ContextualLayoutContext( TGraph graph, TVertex selectedVertex, IDictionary<TVertex, float2> positions, IDictionary<TVertex, float2> sizes )
: base( graph, positions, sizes, LayoutMode.Simple )
{
SelectedVertex = selectedVertex;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b79468344f5b45c4399f30f6812459f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,198 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using QuickGraph;
using System.Diagnostics.Contracts;
using GraphSharp.Algorithms.Layout.Simple.Tree;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Contextual
{
public enum DoubleTreeVertexType
{
Backward,
Forward,
Center
}
public class DoubleTreeLayoutAlgorithm<TVertex, TEdge, TGraph> : ParameterizedLayoutAlgorithmBase<TVertex, TEdge, TGraph, DoubleTreeVertexType, object, DoubleTreeLayoutParameters>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IBidirectionalGraph<TVertex, TEdge>
{
readonly TVertex root;
readonly IDictionary<TVertex, float2> vertexSizes;
protected override DoubleTreeLayoutParameters DefaultParameters
{
get { return new DoubleTreeLayoutParameters(); }
}
public DoubleTreeLayoutAlgorithm( TGraph visitedGraph, IDictionary<TVertex, float2> vertexPositions, IDictionary<TVertex, float2> vertexSizes, DoubleTreeLayoutParameters oldParameters, TVertex selectedVertex )
: base( visitedGraph, vertexPositions, oldParameters )
{
root = selectedVertex;
this.vertexSizes = ( vertexSizes ?? new Dictionary<TVertex, float2>() );
}
protected override void InternalCompute()
{
//
// Separate the two sides
//
HashSet<TVertex> side1, side2;
SeparateSides( VisitedGraph, root, out side1, out side2 );
#region Build the temporary graph for the two sides
//
// The IN side
//
//on the IN side we should reverse the edges
var graph1 = new BidirectionalGraph<TVertex, Edge<TVertex>>();
graph1.AddVertexRange( side1 );
foreach ( var v in side1 )
{
vertexInfos[v] = DoubleTreeVertexType.Backward;
foreach ( var e in VisitedGraph.InEdges( v ) )
{
if ( !side1.Contains( e.Source ) || e.Source.Equals( e.Target ) )
continue;
//reverse the edge
graph1.AddEdge( new Edge<TVertex>( e.Target, e.Source ) );
}
}
//
// The OUT side
//
var graph2 = new BidirectionalGraph<TVertex, TEdge>();
graph2.AddVertexRange( side2 );
foreach ( var v in side2 )
{
vertexInfos[v] = DoubleTreeVertexType.Forward;
foreach ( var e in VisitedGraph.OutEdges( v ) )
{
if ( !side2.Contains( e.Target ) || e.Source.Equals( e.Target ) )
continue;
//simply add the edge
graph2.AddEdge( e );
}
}
vertexInfos[root] = DoubleTreeVertexType.Center;
#endregion
LayoutDirection side2Direction = Parameters.Direction;
LayoutDirection side1Direction = Parameters.Direction;
switch ( side2Direction )
{
case LayoutDirection.BottomToTop:
side1Direction = LayoutDirection.TopToBottom;
break;
case LayoutDirection.LeftToRight:
side1Direction = LayoutDirection.RightToLeft;
break;
case LayoutDirection.RightToLeft:
side1Direction = LayoutDirection.LeftToRight;
break;
case LayoutDirection.TopToBottom:
side1Direction = LayoutDirection.BottomToTop;
break;
}
//
// SimpleTree layout on the two side
//
var side1LayoutAlg = new SimpleTreeLayoutAlgorithm<TVertex, Edge<TVertex>, BidirectionalGraph<TVertex, Edge<TVertex>>>(
graph1, VertexPositions, vertexSizes,
new SimpleTreeLayoutParameters
{
LayerGap = Parameters.LayerGap,
VertexGap = Parameters.VertexGap,
Direction = side1Direction,
SpanningTreeGeneration = SpanningTreeGeneration.BFS
} );
var side2LayoutAlg = new SimpleTreeLayoutAlgorithm<TVertex, TEdge, BidirectionalGraph<TVertex, TEdge>>(
graph2, VertexPositions, vertexSizes,
new SimpleTreeLayoutParameters
{
LayerGap = Parameters.LayerGap,
VertexGap = Parameters.VertexGap,
Direction = side2Direction,
SpanningTreeGeneration = SpanningTreeGeneration.BFS
} );
side1LayoutAlg.Compute();
side2LayoutAlg.Compute();
//
// Merge the layouts
//
var side2Translate = side1LayoutAlg.VertexPositions[root] - side2LayoutAlg.VertexPositions[root];
foreach ( var v in side1 )
VertexPositions[v] = side1LayoutAlg.VertexPositions[v];
foreach ( var v in side2 )
VertexPositions[v] = side2LayoutAlg.VertexPositions[v] + side2Translate;
NormalizePositions();
}
/// <summary>
/// Separates the points of the graph according to the given <paramref name="selectedVertex"/>.
/// </summary>
/// <param name="graph"></param>
/// <param name="selectedVertex"></param>
/// <param name="side1"></param>
/// <param name="side2"></param>
public static void SeparateSides( TGraph graph, TVertex selectedVertex, out HashSet<TVertex> side1, out HashSet<TVertex> side2 )
{
var visitedVertices = new HashSet<TVertex> { selectedVertex };
//create the set of the side 1 and 2
side1 = new HashSet<TVertex> { selectedVertex };
side2 = new HashSet<TVertex> { selectedVertex };
var queue1 = new Queue<TVertex>();
var queue2 = new Queue<TVertex>();
queue1.Enqueue( selectedVertex );
queue2.Enqueue( selectedVertex );
do
{
//get the next layer of vertices on the IN side
for ( int i = 0, n = queue1.Count; i < n; i++ )
{
var vertex = queue1.Dequeue();
foreach ( var edge in graph.InEdges( vertex ) )
{
if ( ( graph.ContainsVertex( edge.Source ) && visitedVertices.Add( edge.Source ) ) || vertex.Equals( selectedVertex ) )
{
queue1.Enqueue( edge.Source );
side1.Add( edge.Source );
}
}
}
//get the next layer of vertices on the OUT side
for ( int i = 0, n = queue2.Count; i < n; i++ )
{
var vertex = queue2.Dequeue();
foreach ( var edge in graph.OutEdges( vertex ) )
{
if ( ( graph.ContainsVertex( edge.Target ) && visitedVertices.Add( edge.Target ) ) || vertex.Equals( selectedVertex ) )
{
queue2.Enqueue( edge.Target );
side2.Add( edge.Target );
}
}
}
} while ( queue1.Count > 0 || queue2.Count > 0 );
//we got the 2 sides
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca869432dda75b0488e5e13d6b853059
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,80 @@
namespace GraphSharp.Algorithms.Layout.Contextual
{
public enum DoubleTreeSides
{
Side1,
Side2
}
public class DoubleTreeLayoutParameters : LayoutParametersBase
{
private LayoutDirection direction = LayoutDirection.LeftToRight;
/// <summary>
/// Gets or sets the layout direction.
/// </summary>
public LayoutDirection Direction
{
get { return direction; }
set
{
if ( direction != value )
{
direction = value;
NotifyPropertyChanged( "Direction" );
}
}
}
private float layerGap = 10;
/// <summary>
/// Gets or sets the gap between the layers.
/// </summary>
public float LayerGap
{
get { return layerGap; }
set
{
if ( layerGap != value )
{
layerGap = value;
NotifyPropertyChanged( "LayerGap" );
}
}
}
private float vertexGap = 10;
/// <summary>
/// Gets or sets the gap between the neighbor vertices in a layer.
/// </summary>
public float VertexGap
{
get { return vertexGap; }
set
{
if ( vertexGap != value )
{
vertexGap = value;
NotifyPropertyChanged( "VertexGap" );
}
}
}
private DoubleTreeSides prioritizedTreeSide = DoubleTreeSides.Side1;
/// <summary>
/// Gets or sets the the prioritized tree side (the one with the bigger priority: where a vertex
/// goes if it should go on both side).
/// </summary>
public DoubleTreeSides PrioritizedTreeSide
{
get { return prioritizedTreeSide; }
set
{
if ( prioritizedTreeSide != value )
{
prioritizedTreeSide = value;
NotifyPropertyChanged( "PrioritizedTreeSide" );
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b7810d4c9a602945b703c39de543302
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,12 @@
using QuickGraph;
using System.Diagnostics.Contracts;
namespace GraphSharp.Algorithms.Layout.Contextual
{
public interface IContextualLayoutAlgorithmFactory<TVertex, TEdge, TGraph> : ILayoutAlgorithmFactory<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b771698c04360d54786bcda1fcc06c22
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Windows;
using QuickGraph;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout.Contextual
{
public class RadialTreeLayoutAlgorithm<TVertex, TEdge, TGraph> : DefaultParameterizedLayoutAlgorithmBase<TVertex, TEdge, TGraph, RadialTreeLayoutParameters>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IBidirectionalGraph<TVertex, TEdge>
{
private readonly TVertex root;
public RadialTreeLayoutAlgorithm(
TGraph visitedGraph,
IDictionary<TVertex, float2> vertexPositions,
RadialTreeLayoutParameters oldParameters,
TVertex selectedVertex )
: base( visitedGraph, vertexPositions, oldParameters )
{
this.root = selectedVertex;
}
protected override void InternalCompute()
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 87c52b55f6c18524db96158ea5b9bb21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
namespace GraphSharp.Algorithms.Layout.Contextual
{
public class RadialTreeLayoutParameters : LayoutParametersBase
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea6f658fd5b673c47bc2d527b7e55abf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,64 @@
using System.Collections.Generic;
using QuickGraph.Algorithms;
using QuickGraph;
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout
{
public delegate void LayoutIterationEndedEventHandler<TVertex, TEdge>( object sender, ILayoutIterationEventArgs<TVertex> e )
where TVertex : class
where TEdge : IEdge<TVertex>;
public delegate void LayoutIterationEndedEventHandler<TVertex, TEdge, TVertexInfo, TEdgeInfo>( object sender, ILayoutInfoIterationEventArgs<TVertex, TEdge, TVertexInfo, TEdgeInfo> e )
where TVertex : class
where TEdge : IEdge<TVertex>;
/// <summary>
/// Reports the progress of the layout.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="percent">The status of the progress in percent.</param>
public delegate void ProgressChangedEventHandler(object sender, double percent);
public interface ILayoutAlgorithm<TVertex, TEdge, TGraph, TVertexInfo, TEdgeInfo> : ILayoutAlgorithm<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IVertexAndEdgeListGraph<TVertex, TEdge>
{
/// <summary>
/// Extra informations, calculated by the layout
/// </summary>
IDictionary<TVertex, TVertexInfo> VertexInfos { get; }
/// <summary>
/// Extra informations, calculated by the layout
/// </summary>
IDictionary<TEdge, TEdgeInfo> EdgeInfos { get; }
new event LayoutIterationEndedEventHandler<TVertex, TEdge, TVertexInfo, TEdgeInfo> IterationEnded;
}
public interface ILayoutAlgorithm<TVertex, TEdge, TGraph> : IAlgorithm<TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : IVertexAndEdgeListGraph<TVertex, TEdge>
{
IDictionary<TVertex, float2> VertexPositions { get; }
/// <summary>
/// Returns with the extra layout information of the vertex (or null).
/// </summary>
object GetVertexInfo( TVertex vertex );
/// <summary>
/// Returns with the extra layout information of the edge (or null).
/// </summary>
object GetEdgeInfo( TEdge edge );
event LayoutIterationEndedEventHandler<TVertex, TEdge> IterationEnded;
event ProgressChangedEventHandler ProgressChanged;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0f1afdff86cccf8498709efbd37366cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,38 @@
using System.Collections.Generic;
using QuickGraph;
using System.Diagnostics.Contracts;
namespace GraphSharp.Algorithms.Layout
{
public interface ILayoutAlgorithmFactory<TVertex, TEdge, TGraph>
where TVertex : class
where TEdge : IEdge<TVertex>
where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
{
IEnumerable<string> AlgorithmTypes { get; }
/// <summary>
/// Creates a new algorithm specified by the newAlgorithmType parameter.
/// </summary>
/// <param name="newAlgorithmType">The identifier of the new layout algorithm.</param>
/// <param name="context"></param>
/// <param name="parameters"></param>
/// <returns>The new layout algorithm object.</returns>
ILayoutAlgorithm<TVertex, TEdge, TGraph> CreateAlgorithm( string newAlgorithmType, ILayoutContext<TVertex, TEdge, TGraph> context, ILayoutParameters parameters );
ILayoutParameters CreateParameters( string algorithmType, ILayoutParameters oldParameters );
bool IsValidAlgorithm( string algorithmType );
/// <summary>
/// Gets the type of the algorithm (usually the name of the algorithm which identifies the algorithm).
/// </summary>
/// <param name="algorithm">The layout algorithm object.</param>
/// <returns>The identified of the algorithm.</returns>
string GetAlgorithmType( ILayoutAlgorithm<TVertex, TEdge, TGraph> algorithm );
bool NeedEdgeRouting( string algorithmType );
bool NeedOverlapRemoval( string algorithmType );
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 25df130b4dde3bc409d99a7e0e250b08
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using QuickGraph;
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout
{
public interface ILayoutContext<TVertex, TEdge, TGraph>
where TEdge : IEdge<TVertex>
where TGraph : IVertexAndEdgeListGraph<TVertex, TEdge>
{
IDictionary<TVertex, float2> Positions { get; }
IDictionary<TVertex, float2> Sizes { get; }
TGraph Graph { get; }
LayoutMode Mode { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a53021c32b555184291d2b55424ba6bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using QuickGraph;
namespace GraphSharp.Algorithms.Layout
{
public interface ILayoutInfoIterationEventArgs<TVertex, TEdge>
: ILayoutIterationEventArgs<TVertex>
where TVertex : class
where TEdge : IEdge<TVertex>
{
object GetVertexInfo(TVertex vertex);
object GetEdgeInfo(TEdge edge);
}
public interface ILayoutInfoIterationEventArgs<TVertex, TEdge, TVertexInfo, TEdgeInfo>
: ILayoutInfoIterationEventArgs<TVertex, TEdge>
where TVertex : class
where TEdge : IEdge<TVertex>
{
IDictionary<TVertex, TVertexInfo> VertexInfos { get; }
IDictionary<TEdge, TEdgeInfo> EdgeInfos { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 544c5b7b388ed714ab69f066f2cfdde8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Unity.Mathematics;
using static Unity.Mathematics.math;
namespace GraphSharp.Algorithms.Layout
{
public interface ILayoutIterationEventArgs<TVertex>
where TVertex : class
{
/// <summary>
/// Represent the status of the layout algorithm in percent.
/// </summary>
double StatusInPercent { get; }
/// <summary>
/// If the user sets this value to <code>true</code>, the algorithm aborts ASAP.
/// </summary>
bool Abort { get; set; }
/// <summary>
/// Number of the actual iteration.
/// </summary>
int Iteration { get; }
/// <summary>
/// Message, textual representation of the status of the algorithm.
/// </summary>
string Message { get; }
IDictionary<TVertex, float2> VertexPositions { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ebb2337ea7f8b45409f5cad9c28e8411
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show more