diff --git a/AIStudio.Wpf.DiagramDesigner/Layout/Configuration.cs b/AIStudio.Wpf.DiagramDesigner/Layout/Configuration.cs
index c49336c..f27cdec 100644
--- a/AIStudio.Wpf.DiagramDesigner/Layout/Configuration.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Layout/Configuration.cs
@@ -1,69 +1,72 @@
-//using System;
+using System;
-//namespace AIStudio.Wpf.DiagramDesigner.Layout
-//{
-// public class Configuration
-// {
-// ///
-// /// The network whose nodes are to be repositioned.
-// ///
-// public DiagramViewModel Network { get; set; }
+namespace AIStudio.Wpf.DiagramDesigner.Layout
+{
+ public class Configuration
+ {
+ ///
+ /// The network whose nodes are to be repositioned.
+ ///
+ public DiagramViewModel Network
+ {
+ get; set;
+ }
-// ///
-// /// A time modifier that is used to speed up, or slow down, time during the simulation.
-// /// A greater time modifier speeds up the physics simulation, at the cost of accuracy and stability.
-// ///
-// public float TimeModifier { get; set; } = 3.5f;
-
-// ///
-// /// Number of updates per iteration.
-// /// Increasing this number increases the accuracy of the physics simulation at the cost of performance.
-// ///
-// public int UpdatesPerIteration { get; set; } = 1;
+ ///
+ /// A time modifier that is used to speed up, or slow down, time during the simulation.
+ /// A greater time modifier speeds up the physics simulation, at the cost of accuracy and stability.
+ ///
+ public float TimeModifier { get; set; } = 3.5f;
-// ///
-// /// How strongly should nodes push eachother away?
-// /// A greater NodeRepulsionForce increases the distance between nodes.
-// ///
-// public float NodeRepulsionForce { get; set; } = 100;
+ ///
+ /// Number of updates per iteration.
+ /// Increasing this number increases the accuracy of the physics simulation at the cost of performance.
+ ///
+ public int UpdatesPerIteration { get; set; } = 1;
-// ///
-// /// A function that maps each connection onto the equilibrium distance of its corresponding spring.
-// /// A greater equilibrium distance increases the distance between the two connected endpoints.
-// ///
-// public Func EquilibriumDistance { get; set; } = conn => 100;
+ ///
+ /// How strongly should nodes push eachother away?
+ /// A greater NodeRepulsionForce increases the distance between nodes.
+ ///
+ public float NodeRepulsionForce { get; set; } = 100;
-// ///
-// /// A function that maps each connection onto the springiness/stiffness constant of its corresponding spring.
-// /// (c.f. Hooke's law)
-// ///
-// public Func SpringConstant { get; set; } = conn => 1;
+ ///
+ /// A function that maps each connection onto the equilibrium distance of its corresponding spring.
+ /// A greater equilibrium distance increases the distance between the two connected endpoints.
+ ///
+ public Func EquilibriumDistance { get; set; } = conn => 100;
-// ///
-// /// A function that maps each connection onto the strength of its row force.
-// /// Since inputs/outputs are on the left/right of a node, networks tend to be layed out horizontally.
-// /// The row force is added onto the endpoints of the connection to make the nodes end up in a more horizontal layout.
-// ///
-// public Func RowForce { get; set; } = conn => 100;
+ ///
+ /// A function that maps each connection onto the springiness/stiffness constant of its corresponding spring.
+ /// (c.f. Hooke's law)
+ ///
+ public Func SpringConstant { get; set; } = conn => 1;
-// ///
-// /// A function that maps each node onto its mass in the physics simulation.
-// /// Greater mass makes the node harder to move.
-// ///
-// public Func NodeMass { get; set; } = node => 10;
+ ///
+ /// A function that maps each connection onto the strength of its row force.
+ /// Since inputs/outputs are on the left/right of a node, networks tend to be layed out horizontally.
+ /// The row force is added onto the endpoints of the connection to make the nodes end up in a more horizontal layout.
+ ///
+ public Func RowForce { get; set; } = conn => 100;
-// ///
-// /// The friction coefficient is used to control friction forces in the simulation.
-// /// Greater friction makes the simulation converge faster, as it slows nodes down when
-// /// they are swinging around. If the friction is too high, the nodes will stop moving before
-// /// they reach their optimal position or might not even move at all.
-// ///
-// public Func FrictionCoefficient { get; set; } = node => 2.5f;
+ ///
+ /// A function that maps each node onto its mass in the physics simulation.
+ /// Greater mass makes the node harder to move.
+ ///
+ public Func NodeMass { get; set; } = node => 10;
-// ///
-// /// A predicate function that specifies whether or not a node is fixed.
-// /// Fixed nodes do not get moved in the simulation.
-// ///
-// public Func IsFixedNode { get; set; } = node => false;
-// }
-//}
+ ///
+ /// The friction coefficient is used to control friction forces in the simulation.
+ /// Greater friction makes the simulation converge faster, as it slows nodes down when
+ /// they are swinging around. If the friction is too high, the nodes will stop moving before
+ /// they reach their optimal position or might not even move at all.
+ ///
+ public Func FrictionCoefficient { get; set; } = node => 2.5f;
+
+ ///
+ /// A predicate function that specifies whether or not a node is fixed.
+ /// Fixed nodes do not get moved in the simulation.
+ ///
+ public Func IsFixedNode { get; set; } = node => false;
+ }
+}
diff --git a/AIStudio.Wpf.DiagramDesigner/Layout/Engine.cs b/AIStudio.Wpf.DiagramDesigner/Layout/Engine.cs
index 9c0482a..c5b7c46 100644
--- a/AIStudio.Wpf.DiagramDesigner/Layout/Engine.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Layout/Engine.cs
@@ -1,123 +1,123 @@
-//using System;
-//using System.Collections.Generic;
-//using System.Linq;
-//using System.Windows;
-//using AIStudio.Wpf.DiagramDesigner.Geometrys;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using AIStudio.Wpf.DiagramDesigner.Geometrys;
-//namespace AIStudio.Wpf.DiagramDesigner.Layout
-//{
-// internal class Engine
-// {
-// internal void ApplyRandomShift(DiagramViewModel network)
-// {
-// Random random = new Random();
-// foreach (var node in network.Items.OfType())
-// {
-// node.Position = node.Position + new VectorBase(random.NextDouble(), random.NextDouble());
-// }
-// }
+namespace AIStudio.Wpf.DiagramDesigner.Layout
+{
+ internal class Engine
+ {
+ internal void ApplyRandomShift(DiagramViewModel network)
+ {
+ Random random = new Random();
+ foreach (var node in network.Items.OfType())
+ {
+ node.Position = node.Position + new VectorBase(random.NextDouble(), random.NextDouble());
+ }
+ }
-// internal void Update(int deltaTMillis, IState state, Configuration config)
-// {
-// // Calculate forces
-// int nodeCount = config.Network.Items.Count;
-// IList<(DesignerItemViewModelBase, VectorBase)> nodeForces = new List<(DesignerItemViewModelBase, VectorBase)>(nodeCount);
+ internal void Update(int deltaTMillis, IState state, Configuration config)
+ {
+ // Calculate forces
+ int nodeCount = config.Network.Items.Count;
+ IList<(DesignerItemViewModelBase, VectorBase)> nodeForces = new List<(DesignerItemViewModelBase, VectorBase)>(nodeCount);
-// foreach (var node in config.Network.Items.OfType())
-// {
-// if (!config.IsFixedNode(node))
-// {
-// nodeForces.Add((node, CalculateNodeForce(node, state, config)));
-// }
-// }
+ foreach (var node in config.Network.Items.OfType())
+ {
+ if (!config.IsFixedNode(node))
+ {
+ nodeForces.Add((node, CalculateNodeForce(node, state, config)));
+ }
+ }
-// // Apply forces
-// foreach (var (node, force) in nodeForces)
-// {
-// VectorBase speed = state.GetNodeSpeed(node);
-// VectorBase pos = state.GetNodePosition(node);
-// double deltaT = deltaTMillis / 1000.0;
-// state.SetNodePosition(node, pos + ((speed * deltaT) + (force * deltaT * deltaT / 2)));
-// state.SetNodeSpeed(node, speed + ((force / config.NodeMass(node)) * deltaT));
-// }
-// }
+ // Apply forces
+ foreach (var (node, force) in nodeForces)
+ {
+ VectorBase speed = state.GetNodeSpeed(node);
+ VectorBase pos = state.GetNodePosition(node);
+ double deltaT = deltaTMillis / 1000.0;
+ state.SetNodePosition(node, pos + ((speed * deltaT) + (force * deltaT * deltaT / 2)));
+ state.SetNodeSpeed(node, speed + ((force / config.NodeMass(node)) * deltaT));
+ }
+ }
-// private VectorBase CalculateNodeForce(DesignerItemViewModelBase node, IState state, Configuration config)
-// {
-// VectorBase force = new VectorBase();
+ private VectorBase CalculateNodeForce(DesignerItemViewModelBase node, IState state, Configuration config)
+ {
+ VectorBase force = new VectorBase();
-// // Calculate total force on node from endpoints
-// if (node.InputConnectors.Count > 0 || node.OutputConnectors.Count > 0)
-// {
-// force += node.InputConnectors.Concat(node.OutputConnectors)
-// .Select(e => CalculateEndpointForce(e, state, config))
-// .Aggregate((v1, v2) => v1 + v2);
-// }
+ // Calculate total force on node from endpoints
+ if (node.InputConnectors.Count > 0 || node.OutputConnectors.Count > 0)
+ {
+ force += node.InputConnectors.Concat(node.OutputConnectors)
+ .Select(e => CalculateEndpointForce(e, state, config))
+ .Aggregate((v1, v2) => v1 + v2);
+ }
-// // Apply node repulsion force so nodes don't overlap
-// var nodeCenter = state.GetNodePosition(node) + (new VectorBase(node.Size.Width, node.Size.Height) / 2.0);
-// foreach (var otherNode in config.Network.Items.OfType())
-// {
-// if (node == otherNode)
-// {
-// continue;
-// }
+ // Apply node repulsion force so nodes don't overlap
+ var nodeCenter = state.GetNodePosition(node) + (new VectorBase(node.Size.Width, node.Size.Height) / 2.0);
+ foreach (var otherNode in config.Network.Items.OfType())
+ {
+ if (node == otherNode)
+ {
+ continue;
+ }
-// var otherNodeCenter = state.GetNodePosition(otherNode) + (new VectorBase(otherNode.Size.Width, otherNode.Size.Height) / 2.0);
-// var thisToOther = otherNodeCenter - nodeCenter;
-// var dist = thisToOther.Length;
-// thisToOther.Normalize();
+ var otherNodeCenter = state.GetNodePosition(otherNode) + (new VectorBase(otherNode.Size.Width, otherNode.Size.Height) / 2.0);
+ var thisToOther = otherNodeCenter - nodeCenter;
+ var dist = thisToOther.Length;
+ thisToOther.Normalize();
-// var repulsionX = thisToOther.X * (-1 * ((node.Size.Width + otherNode.Size.Width) / 2) / dist);
-// var repulsionY = thisToOther.Y * (-1 * ((node.Size.Height + otherNode.Size.Height) / 2) / dist);
-// force += new VectorBase(repulsionX, repulsionY) * config.NodeRepulsionForce;
-// }
+ var repulsionX = thisToOther.X * (-1 * ((node.Size.Width + otherNode.Size.Width) / 2) / dist);
+ var repulsionY = thisToOther.Y * (-1 * ((node.Size.Height + otherNode.Size.Height) / 2) / dist);
+ force += new VectorBase(repulsionX, repulsionY) * config.NodeRepulsionForce;
+ }
-// // Apply friction to make the movement converge to a stable state.
-// float gravity = 9.8f;
-// float normalForce = gravity * config.NodeMass(node);
-// float kineticFriction = normalForce * config.FrictionCoefficient(node);
-// VectorBase frictionVector = new VectorBase();
-// var nodeSpeed = state.GetNodeSpeed(node);
-// if (nodeSpeed.Length > 0)
-// {
-// frictionVector = new VectorBase(nodeSpeed.X, nodeSpeed.Y);
-// frictionVector.Normalize();
-// frictionVector *= -1.0 * kineticFriction;
-// }
-// force += frictionVector;
+ // Apply friction to make the movement converge to a stable state.
+ float gravity = 9.8f;
+ float normalForce = gravity * config.NodeMass(node);
+ float kineticFriction = normalForce * config.FrictionCoefficient(node);
+ VectorBase frictionVector = new VectorBase();
+ var nodeSpeed = state.GetNodeSpeed(node);
+ if (nodeSpeed.Length > 0)
+ {
+ frictionVector = new VectorBase(nodeSpeed.X, nodeSpeed.Y);
+ frictionVector.Normalize();
+ frictionVector *= -1.0 * kineticFriction;
+ }
+ force += frictionVector;
-// return force;
-// }
+ return force;
+ }
-// private VectorBase CalculateEndpointForce(ConnectorInfoBase endpoint, IState state, Configuration config)
-// {
-// var pos = state.GetEndpointPosition(endpoint);
+ private VectorBase CalculateEndpointForce(ConnectorInfoBase endpoint, IState state, Configuration config)
+ {
+ var pos = state.GetEndpointPosition(endpoint);
-// VectorBase force = new VectorBase();
+ VectorBase force = new VectorBase();
-// foreach (var conn in endpoint.Connections.Items)
-// {
-// var otherSide = conn.Input == endpoint ? (ConnectorInfoBase)conn.Output : conn.Input;
-// var otherSidePos = state.GetEndpointPosition(otherSide);
-// var dist = (otherSidePos - pos).Length;
-// var angle = Math.Acos((otherSidePos.X - pos.X) / dist);
-// if (otherSidePos.Y < pos.Y)
-// {
-// angle *= -1.0;
-// }
+ foreach (var conn in config.Network.Items.OfType().Where(p => p.SinkConnectorInfo == endpoint || p.SourceConnectorInfo == endpoint).ToList())
+ {
+ var otherSide = conn.SourceConnectorInfo == endpoint ? conn.SinkConnectorInfo : conn.SourceConnectorInfo;
+ var otherSidePos = state.GetEndpointPosition(otherSide);
+ var dist = (otherSidePos - pos).Length;
+ var angle = Math.Acos((otherSidePos.X - pos.X) / dist);
+ if (otherSidePos.Y < pos.Y)
+ {
+ angle *= -1.0;
+ }
-// // Put a spring between connected endpoints.
-// var hookForce = (dist - config.EquilibriumDistance(conn)) * config.SpringConstant(conn);
-// force += new VectorBase(Math.Cos(angle), Math.Sin(angle)) * hookForce;
+ // Put a spring between connected endpoints.
+ var hookForce = (dist - config.EquilibriumDistance(conn)) * config.SpringConstant(conn);
+ force += new VectorBase(Math.Cos(angle), Math.Sin(angle)) * hookForce;
-// // Try to 'straighten' out the graph horizontally.
-// var isLeftSide = endpoint.Orientation == ConnectorOrientation.Left;
-// var rowForce = (isLeftSide ? 1 : -1) * config.RowForce(conn);
-// force.X += rowForce;
-// }
+ // Try to 'straighten' out the graph horizontally.
+ var isLeftSide = endpoint.Orientation == ConnectorOrientation.Left;
+ var rowForce = (isLeftSide ? 1 : -1) * config.RowForce(conn);
+ force.X += rowForce;
+ }
-// return force;
-// }
-// }
-//}
+ return force;
+ }
+ }
+}
diff --git a/AIStudio.Wpf.DiagramDesigner/Layout/ForceDirectedLayouter.cs b/AIStudio.Wpf.DiagramDesigner/Layout/ForceDirectedLayouter.cs
index cf23015..5e47dda 100644
--- a/AIStudio.Wpf.DiagramDesigner/Layout/ForceDirectedLayouter.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Layout/ForceDirectedLayouter.cs
@@ -1,81 +1,81 @@
-//using System;
-//using System.Threading;
-//using System.Threading.Tasks;
-//using System.Windows;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
-//namespace AIStudio.Wpf.DiagramDesigner.Layout
-//{
-// ///
-// /// Reposition the nodes in a network using a physics-based approach.
-// /// The nodes are interpreted as point masses, and the connections are represented
-// /// by springs. This system, along with a few additional forces such as friction and a
-// /// horizontal force, is then simulated to calculate the new position of the nodes.
-// ///
-// public class ForceDirectedLayouter
-// {
-// ///
-// /// Layout the nodes in the network.
-// ///
-// /// The configuration to use.
-// /// The maximum amount of iterations after which the physics simulation ends.
-// public void Layout(Configuration config, int maxIterations)
-// {
-// var engine = new Engine();
-// var state = new BufferedState();
+namespace AIStudio.Wpf.DiagramDesigner.Layout
+{
+ ///
+ /// Reposition the nodes in a network using a physics-based approach.
+ /// The nodes are interpreted as point masses, and the connections are represented
+ /// by springs. This system, along with a few additional forces such as friction and a
+ /// horizontal force, is then simulated to calculate the new position of the nodes.
+ ///
+ public class ForceDirectedLayouter
+ {
+ ///
+ /// Layout the nodes in the network.
+ ///
+ /// The configuration to use.
+ /// The maximum amount of iterations after which the physics simulation ends.
+ public void Layout(Configuration config, int maxIterations)
+ {
+ var engine = new Engine();
+ var state = new BufferedState();
-// // Move each node so no two nodes have the exact same position.
-// engine.ApplyRandomShift(config.Network);
+ // Move each node so no two nodes have the exact same position.
+ engine.ApplyRandomShift(config.Network);
-// int deltaT = (int)Math.Ceiling(10.0 / (double)config.UpdatesPerIteration);
-// for (int i = 0; i < maxIterations * config.UpdatesPerIteration; i++)
-// {
-// engine.Update(deltaT, state, config);
-// }
+ int deltaT = (int)Math.Ceiling(10.0 / (double)config.UpdatesPerIteration);
+ for (int i = 0; i < maxIterations * config.UpdatesPerIteration; i++)
+ {
+ engine.Update(deltaT, state, config);
+ }
-// foreach (var newNodePosition in state.NodePositions)
-// {
-// newNodePosition.Key.Position = new Point(newNodePosition.Value.X, newNodePosition.Value.Y);
-// }
-// }
+ foreach (var newNodePosition in state.NodePositions)
+ {
+ newNodePosition.Key.Position = new Point(newNodePosition.Value.X, newNodePosition.Value.Y);
+ }
+ }
-// ///
-// /// Layout the nodes in the network, updating the user interface at each iteration.
-// /// This method, contrary to Layout(), lets users see the simulation as it happens.
-// /// The cancellation token should be used to end the simulation.
-// ///
-// /// The configuration to use.
-// /// A cancellation token to end the layout process.
-// /// The async task
-// public async Task LayoutAsync(Configuration config, CancellationToken token)
-// {
-// var engine = new Engine();
-// var state = new LiveState();
+ ///
+ /// Layout the nodes in the network, updating the user interface at each iteration.
+ /// This method, contrary to Layout(), lets users see the simulation as it happens.
+ /// The cancellation token should be used to end the simulation.
+ ///
+ /// The configuration to use.
+ /// A cancellation token to end the layout process.
+ /// The async task
+ public async Task LayoutAsync(Configuration config, CancellationToken token)
+ {
+ var engine = new Engine();
+ var state = new LiveState();
-// // Move each node so no two nodes have the exact same position.
-// engine.ApplyRandomShift(config.Network);
+ // Move each node so no two nodes have the exact same position.
+ engine.ApplyRandomShift(config.Network);
-// DateTime start = DateTime.Now;
-// TimeSpan t = TimeSpan.Zero;
-// do
-// {
-// // Current real time
-// var newT = DateTime.Now - start;
-// var deltaT = newT - t;
-
-// // Current modified time
-// //int virtT = (int)(t.Milliseconds * Settings.TimeModifier);
-// int virtDeltaT = (int)(deltaT.Milliseconds * config.TimeModifier);
-// int virtDeltaTPerUpdate = virtDeltaT / config.UpdatesPerIteration;
-// for (int i = 0; i < config.UpdatesPerIteration; i++)
-// {
-// // Modified time in this update step
-// engine.Update(virtDeltaTPerUpdate, state, config);
-// }
+ DateTime start = DateTime.Now;
+ TimeSpan t = TimeSpan.Zero;
+ do
+ {
+ // Current real time
+ var newT = DateTime.Now - start;
+ var deltaT = newT - t;
-// t = newT;
+ // Current modified time
+ //int virtT = (int)(t.Milliseconds * Settings.TimeModifier);
+ int virtDeltaT = (int)(deltaT.Milliseconds * config.TimeModifier);
+ int virtDeltaTPerUpdate = virtDeltaT / config.UpdatesPerIteration;
+ for (int i = 0; i < config.UpdatesPerIteration; i++)
+ {
+ // Modified time in this update step
+ engine.Update(virtDeltaTPerUpdate, state, config);
+ }
-// await Task.Delay(14, token);
-// } while (!token.IsCancellationRequested);
-// }
-// }
-//}
+ t = newT;
+
+ await Task.Delay(14, token);
+ } while (!token.IsCancellationRequested);
+ }
+ }
+}
diff --git a/AIStudio.Wpf.DiagramDesigner/Layout/State.cs b/AIStudio.Wpf.DiagramDesigner/Layout/State.cs
index 5691571..707d909 100644
--- a/AIStudio.Wpf.DiagramDesigner/Layout/State.cs
+++ b/AIStudio.Wpf.DiagramDesigner/Layout/State.cs
@@ -1,100 +1,100 @@
-//using System.Collections.Generic;
-//using System.Windows;
-//using AIStudio.Wpf.DiagramDesigner.Geometrys;
+using System.Collections.Generic;
+using System.Windows;
+using AIStudio.Wpf.DiagramDesigner.Geometrys;
-//namespace AIStudio.Wpf.DiagramDesigner.Layout
-//{
-// internal interface IState
-// {
-// VectorBase GetNodePosition(DesignerItemViewModelBase node);
-// void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos);
-// VectorBase GetEndpointPosition(ConnectorInfoBase endpoint);
-// VectorBase GetNodeSpeed(DesignerItemViewModelBase node);
-// void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed);
-// }
+namespace AIStudio.Wpf.DiagramDesigner.Layout
+{
+ internal interface IState
+ {
+ VectorBase GetNodePosition(DesignerItemViewModelBase node);
+ void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos);
+ VectorBase GetEndpointPosition(ConnectorInfoBase endpoint);
+ VectorBase GetNodeSpeed(DesignerItemViewModelBase node);
+ void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed);
+ }
-// internal class BufferedState : IState
-// {
-// private readonly Dictionary _nodePositions = new Dictionary();
-// private readonly Dictionary _endpointRelativePositions = new Dictionary();
-// public IEnumerable> NodePositions => _nodePositions;
+ internal class BufferedState : IState
+ {
+ private readonly Dictionary _nodePositions = new Dictionary();
+ private readonly Dictionary _endpointRelativePositions = new Dictionary();
+ public IEnumerable> NodePositions => _nodePositions;
-// private readonly Dictionary _nodeSpeeds = new Dictionary();
+ private readonly Dictionary _nodeSpeeds = new Dictionary();
-// public VectorBase GetNodePosition(DesignerItemViewModelBase node)
-// {
-// if (!_nodePositions.TryGetValue(node, out VectorBase result))
-// {
-// result = new VectorBase(node.Position.X, node.Position.Y);
-// }
+ public VectorBase GetNodePosition(DesignerItemViewModelBase node)
+ {
+ if (!_nodePositions.TryGetValue(node, out VectorBase result))
+ {
+ result = new VectorBase(node.Position.X, node.Position.Y);
+ }
-// return result;
-// }
+ return result;
+ }
-// public void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos)
-// {
-// _nodePositions[node] = pos;
-// }
+ public void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos)
+ {
+ _nodePositions[node] = pos;
+ }
-// public VectorBase GetEndpointPosition(ConnectorInfoBase endpoint)
-// {
-// if (!_endpointRelativePositions.TryGetValue(endpoint, out VectorBase result))
-// {
-// result = new VectorBase(endpoint.MiddlePosition.X, endpoint.MiddlePosition.Y) - GetNodePosition(endpoint.Parent);
-// _endpointRelativePositions[endpoint] = result;
-// }
+ public VectorBase GetEndpointPosition(ConnectorInfoBase endpoint)
+ {
+ if (!_endpointRelativePositions.TryGetValue(endpoint, out VectorBase result))
+ {
+ result = new VectorBase(endpoint.MiddlePosition.X, endpoint.MiddlePosition.Y) - GetNodePosition(endpoint.Parent as DesignerItemViewModelBase);
+ _endpointRelativePositions[endpoint] = result;
+ }
-// return result + GetNodePosition(endpoint.Parent as DesignerItemViewModelBase);
-// }
+ return result + GetNodePosition(endpoint.Parent as DesignerItemViewModelBase);
+ }
-// public VectorBase GetNodeSpeed(DesignerItemViewModelBase node)
-// {
-// if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
-// {
-// result = new VectorBase(0, 0);
-// }
+ public VectorBase GetNodeSpeed(DesignerItemViewModelBase node)
+ {
+ if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
+ {
+ result = new VectorBase(0, 0);
+ }
-// return result;
-// }
+ return result;
+ }
-// public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
-// {
-// _nodeSpeeds[node] = speed;
-// }
-// }
+ public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
+ {
+ _nodeSpeeds[node] = speed;
+ }
+ }
-// internal class LiveState : IState
-// {
-// private readonly Dictionary _nodeSpeeds = new Dictionary();
+ internal class LiveState : IState
+ {
+ private readonly Dictionary _nodeSpeeds = new Dictionary();
-// public VectorBase GetNodePosition(DesignerItemViewModelBase node)
-// {
-// return new VectorBase(node.Position.X, node.Position.Y);
-// }
+ public VectorBase GetNodePosition(DesignerItemViewModelBase node)
+ {
+ return new VectorBase(node.Position.X, node.Position.Y);
+ }
-// public void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos)
-// {
-// node.Position = new Point(pos.X, pos.Y);
-// }
+ public void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos)
+ {
+ node.Position = new Point(pos.X, pos.Y);
+ }
-// public VectorBase GetEndpointPosition(ConnectorInfoBase endpoint)
-// {
-// return new VectorBase(endpoint.MiddlePosition.X, endpoint.MiddlePosition.Y);
-// }
+ public VectorBase GetEndpointPosition(ConnectorInfoBase endpoint)
+ {
+ return new VectorBase(endpoint.MiddlePosition.X, endpoint.MiddlePosition.Y);
+ }
-// public VectorBase GetNodeSpeed(DesignerItemViewModelBase node)
-// {
-// if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
-// {
-// result = new VectorBase(0, 0);
-// }
+ public VectorBase GetNodeSpeed(DesignerItemViewModelBase node)
+ {
+ if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
+ {
+ result = new VectorBase(0, 0);
+ }
-// return result;
-// }
+ return result;
+ }
-// public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
-// {
-// _nodeSpeeds[node] = speed;
-// }
-// }
-//}
+ public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
+ {
+ _nodeSpeeds[node] = speed;
+ }
+ }
+}
diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs
index de24da7..7cf3831 100644
--- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs
+++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs
@@ -10,6 +10,7 @@ using System.Windows.Input;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Helpers;
+using AIStudio.Wpf.DiagramDesigner.Layout;
using AIStudio.Wpf.DiagramDesigner.Models;
using Newtonsoft.Json;
using static System.Net.Mime.MediaTypeNames;
@@ -676,6 +677,16 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
+ private ICommand _autoLayoutCommand;
+ public ICommand AutoLayoutCommand
+ {
+ get
+ {
+ return this._autoLayoutCommand ?? (this._autoLayoutCommand = new SimpleCommand(ExecuteEnable, ExecuteAutoLayoutCommand));
+ }
+ }
+
+
private ICommand _groupCommand;
public ICommand GroupCommand
{
@@ -2438,6 +2449,12 @@ namespace AIStudio.Wpf.DiagramDesigner
FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(Items.OfType()), FitMode = FitMode.FitHeight };
}
}
+
+ private void ExecuteAutoLayoutCommand(object parameter)
+ {
+ ForceDirectedLayouter layouter = new ForceDirectedLayouter();
+ layouter.Layout(new Configuration { Network = this }, 10000);
+ }
#endregion
#region 分组