diff --git a/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml b/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml
index 9a51c94..5aa58b8 100644
--- a/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml
+++ b/AIStudio.Wpf.DiagramApp/Views/MainWindow.xaml
@@ -2531,11 +2531,6 @@
-
-
-
-
-
diff --git a/AIStudio.Wpf.DiagramDesigner/Layout/Configuration.cs b/AIStudio.Wpf.DiagramDesigner/Layout/Configuration.cs
deleted file mode 100644
index f27cdec..0000000
--- a/AIStudio.Wpf.DiagramDesigner/Layout/Configuration.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System;
-
-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;
-
- ///
- /// 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 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 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 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 node onto its mass in the physics simulation.
- /// Greater mass makes the node harder to move.
- ///
- public Func NodeMass { get; set; } = node => 10;
-
- ///
- /// 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
deleted file mode 100644
index c5b7c46..0000000
--- a/AIStudio.Wpf.DiagramDesigner/Layout/Engine.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-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());
- }
- }
-
- 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)));
- }
- }
-
- // 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();
-
- // 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;
- }
-
- 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;
- }
-
- // 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;
- }
-
- private VectorBase CalculateEndpointForce(ConnectorInfoBase endpoint, IState state, Configuration config)
- {
- var pos = state.GetEndpointPosition(endpoint);
-
- VectorBase force = new VectorBase();
-
- 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;
-
- // 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;
- }
- }
-}
diff --git a/AIStudio.Wpf.DiagramDesigner/Layout/ForceDirectedLayouter.cs b/AIStudio.Wpf.DiagramDesigner/Layout/ForceDirectedLayouter.cs
deleted file mode 100644
index 5e47dda..0000000
--- a/AIStudio.Wpf.DiagramDesigner/Layout/ForceDirectedLayouter.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-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();
-
- // 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);
- }
-
- 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();
-
- // 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);
- }
-
- 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
deleted file mode 100644
index 707d909..0000000
--- a/AIStudio.Wpf.DiagramDesigner/Layout/State.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-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);
- }
-
- 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();
-
- public VectorBase GetNodePosition(DesignerItemViewModelBase node)
- {
- if (!_nodePositions.TryGetValue(node, out VectorBase result))
- {
- result = new VectorBase(node.Position.X, node.Position.Y);
- }
-
- return result;
- }
-
- 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 as DesignerItemViewModelBase);
- _endpointRelativePositions[endpoint] = result;
- }
-
- return result + GetNodePosition(endpoint.Parent as DesignerItemViewModelBase);
- }
-
- public VectorBase GetNodeSpeed(DesignerItemViewModelBase node)
- {
- if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
- {
- result = new VectorBase(0, 0);
- }
-
- return result;
- }
-
- public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
- {
- _nodeSpeeds[node] = speed;
- }
- }
-
- 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 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 GetNodeSpeed(DesignerItemViewModelBase node)
- {
- if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
- {
- result = new VectorBase(0, 0);
- }
-
- return result;
- }
-
- public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
- {
- _nodeSpeeds[node] = speed;
- }
- }
-}
diff --git a/AIStudio.Wpf.DiagramDesigner/Styles/ToggleButton.xaml b/AIStudio.Wpf.DiagramDesigner/Styles/ToggleButton.xaml
new file mode 100644
index 0000000..9ab98f4
--- /dev/null
+++ b/AIStudio.Wpf.DiagramDesigner/Styles/ToggleButton.xaml
@@ -0,0 +1,96 @@
+
+
+
+
\ No newline at end of file
diff --git a/AIStudio.Wpf.DiagramDesigner/Themes/Style.xaml b/AIStudio.Wpf.DiagramDesigner/Themes/Style.xaml
index 76d04a9..1998cd9 100644
--- a/AIStudio.Wpf.DiagramDesigner/Themes/Style.xaml
+++ b/AIStudio.Wpf.DiagramDesigner/Themes/Style.xaml
@@ -9,5 +9,6 @@
+
\ No newline at end of file
diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs
index a6b9a5e..d5ed9eb 100644
--- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs
+++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModel.cs
@@ -10,10 +10,8 @@ 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;
namespace AIStudio.Wpf.DiagramDesigner
{
@@ -680,17 +678,7 @@ namespace AIStudio.Wpf.DiagramDesigner
{
return this._fitHeightCommand ?? (this._fitHeightCommand = new SimpleCommand(ExecuteEnable, ExecuteFitHeightCommand));
}
- }
-
- private ICommand _autoLayoutCommand;
- public ICommand AutoLayoutCommand
- {
- get
- {
- return this._autoLayoutCommand ?? (this._autoLayoutCommand = new SimpleCommand(ExecuteEnable, ExecuteAutoLayoutCommand));
- }
- }
-
+ }
private ICommand _groupCommand;
public ICommand GroupCommand
@@ -2462,12 +2450,6 @@ 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 分组