diff --git a/PamhagenSysCtrl/Helpers/PamhagenGraph.cs b/PamhagenSysCtrl/Helpers/PamhagenGraph.cs index 7724ae7..189a633 100644 --- a/PamhagenSysCtrl/Helpers/PamhagenGraph.cs +++ b/PamhagenSysCtrl/Helpers/PamhagenGraph.cs @@ -28,8 +28,8 @@ namespace PamhagenSysCtrl.Helpers { double t8X = t7X + 80; double t9X = t8X + 80; - MW1 = new Trough("MW1", mw1X, mpY - 40, () => App.Plant?.FillLevelA1 != FillState.Empty); - MW2 = new Trough("MW2", mw2X, mpY - 40, () => App.Plant?.FillLevelA1 != FillState.Empty); + MW1 = new Trough("MW1", mw1X, mpY - 70, () => App.Plant?.FillLevelA1 != FillState.Empty); + MW2 = new Trough("MW2", mw2X, mpY - 70, () => App.Plant?.FillLevelA1 != FillState.Empty); var mp1 = new Pump("MP1", mw1X, mpY); var mp2 = new Pump("MP2", mw2X, mpY); var x1 = new PipeJoin(mw1X, mpY + 40); diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Graph.cs b/PamhagenSysCtrl/Helpers/Pipeline/Graph.cs index 5979807..fb0be24 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Graph.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Graph.cs @@ -62,7 +62,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { foreach (var o in start.Outputs) { if (o.End == end) { return new(start, [(o, o.End)]); - } else if (!valid(o.End)) { + } else if (!valid(o.End) || (!o.IsTwoWay && o.End == start) || (o.IsTwoWay && o.End == start)) { continue; } @@ -91,13 +91,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { } } - public ISet Update(double x, double y) { + public ISet Update(double x, double y, bool down) { HashSet hover = new(); foreach (var e in Edges) { - e.Update(x, y); + e.Update(); } foreach (var n in Nodes) { - if (n.Update(x, y)) { + if (n.Update(x, y, down)) { hover.Add(n); } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/IEdge.cs b/PamhagenSysCtrl/Helpers/Pipeline/IEdge.cs index 4211e6d..538cf70 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/IEdge.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/IEdge.cs @@ -11,7 +11,6 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public Brush? Highlight { get; set; } public void Draw(Canvas canvas); - public bool Update(double x, double y); - + public void Update(); } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/INode.cs b/PamhagenSysCtrl/Helpers/Pipeline/INode.cs index 85dc744..3de60f3 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/INode.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/INode.cs @@ -10,7 +10,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public ISet Outputs { get; } public void Draw(Canvas canvas); - public bool Update(double x, double y); + public bool Update(double x, double y, bool down); } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/ISource.cs b/PamhagenSysCtrl/Helpers/Pipeline/ISource.cs index 5a9da86..2913d6c 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/ISource.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/ISource.cs @@ -2,5 +2,6 @@ public interface ISource : INode { public double BottomY { get; } public bool IsFilled { get; } + public bool IsSelected { get; set; } } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Inlet.cs b/PamhagenSysCtrl/Helpers/Pipeline/Inlet.cs index 16a8e52..da2561a 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Inlet.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Inlet.cs @@ -76,10 +76,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_inner2); } - public bool Update(double x, double y) { + public void Update() { _inner1?.Stroke = Highlight ?? Brushes.DarkGray; _inner2?.Stroke = Highlight ?? Brushes.DarkGray; - return false; } } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Outlet.cs b/PamhagenSysCtrl/Helpers/Pipeline/Outlet.cs index 24fe67c..e51db1e 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Outlet.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Outlet.cs @@ -86,11 +86,10 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_inner2); } - public bool Update(double x, double y) { + public void Update() { _inner1?.Stroke = Highlight ?? Brushes.DarkGray; _inner2?.Stroke = Highlight ?? Brushes.DarkGray; _hopper?.Fill = Highlight ?? Brushes.DarkGray; - return false; } } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Pipe.cs b/PamhagenSysCtrl/Helpers/Pipeline/Pipe.cs index b4518bf..c10f022 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Pipe.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Pipe.cs @@ -65,10 +65,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_inner2); } - public bool Update(double x, double y) { + public void Update() { _inner1?.Stroke = Highlight ?? Brushes.DarkGray; _inner2?.Stroke = Highlight ?? Brushes.DarkGray; - return false; } } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/PipeJoin.cs b/PamhagenSysCtrl/Helpers/Pipeline/PipeJoin.cs index cd50c58..ba455e4 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/PipeJoin.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/PipeJoin.cs @@ -81,7 +81,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_rect); } - public bool Update(double x, double y) { + public bool Update(double x, double y, bool down) { var hover = Math.Abs(x - CenterX) <= SIZE / 2 && Math.Abs(y - CenterY) <= SIZE / 2; _rect?.Stroke = hover ? Brushes.Black : Brushes.Black; return hover; diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Press.cs b/PamhagenSysCtrl/Helpers/Pipeline/Press.cs index 7b7dc24..54af9d4 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Press.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Press.cs @@ -59,7 +59,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_text); } - public bool Update(double x, double y) { + public bool Update(double x, double y, bool down) { var hover = Math.Sqrt(Math.Pow(CenterX - x, 2) + Math.Pow(CenterY - y, 2)) <= DIAMETER / 2; _circle?.Fill = hover ? Brushes.LightGray : Brushes.WhiteSmoke; return hover; diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Pump.cs b/PamhagenSysCtrl/Helpers/Pipeline/Pump.cs index 8c41a9d..e3a3570 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Pump.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Pump.cs @@ -58,7 +58,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_text); } - public bool Update(double x, double y) { + public bool Update(double x, double y, bool down) { var hover = Math.Sqrt(Math.Pow(CenterX - x, 2) + Math.Pow(CenterY - y, 2)) <= DIAMETER / 2; _circle?.Fill = hover ? Brushes.LightGray : Brushes.WhiteSmoke; return hover; diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs b/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs index 740b990..d4b6eea 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs @@ -16,6 +16,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public string Label { get; set; } public bool IsFull => CallbackIsFull(); public bool IsFilled => CallbackIsFilled(); + public bool IsSelected { get; set; } public ISet Inputs { get; init; } public ISet Outputs { get; init; } @@ -62,9 +63,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_text); } - public bool Update(double x, double y) { + public bool Update(double x, double y, bool down) { var hover = Math.Abs(x - CenterX) <= WIDTH / 2 && Math.Abs(y - CenterY) <= HEIGHT / 2; - _rect?.Fill = hover ? Brushes.LightGray : Brushes.WhiteSmoke; + _rect?.Fill = IsSelected ? Brushes.LightGray : hover ? Brushes.LightGray : Brushes.WhiteSmoke; return hover; } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Trough.cs b/PamhagenSysCtrl/Helpers/Pipeline/Trough.cs index 9f7dde0..e0a9b0b 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Trough.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Trough.cs @@ -1,18 +1,28 @@ -using System.Windows.Controls; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Shapes; namespace PamhagenSysCtrl.Helpers.Pipeline { public class Trough : INode, ISource { + public const double WIDTH = 100; + public const double HEIGHT = 60; + public double CenterX { get; set; } public double CenterY { get; set; } - public double BottomY => CenterY; + public double BottomY => CenterY + HEIGHT / 2; public string Label { get; set; } public bool IsFilled => CallbackIsFilled(); + public bool IsSelected { get; set; } public ISet Inputs { get; init; } public ISet Outputs { get; init; } protected Func CallbackIsFilled; + private Shape? _rect; + private TextBlock? _text; + public Trough(string label, double x, double y, Func cbFilled) { CenterX = x; CenterY = y; @@ -23,11 +33,32 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { } public void Draw(Canvas canvas) { - + _rect = new Rectangle() { + Width = WIDTH, + Height = HEIGHT, + Stroke = Brushes.Black, + StrokeThickness = 2, + Fill = Brushes.WhiteSmoke, + }; + _text = new() { + Text = Label, + FontSize = 12, + Width = WIDTH, + TextAlignment = TextAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + }; + _rect.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2); + _rect.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2); + _text.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2); + _text.SetValue(Canvas.TopProperty, CenterY - 8); + canvas.Children.Add(_rect); + canvas.Children.Add(_text); } - public bool Update(double x, double y) { - return false; + public bool Update(double x, double y, bool down) { + var hover = Math.Abs(x - CenterX) <= WIDTH / 2 && Math.Abs(y - CenterY) <= HEIGHT / 2; + _rect?.Fill = IsSelected ? Brushes.LightGray : hover ? Brushes.LightGray : Brushes.WhiteSmoke; + return hover; } } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs b/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs index 96f5217..bacf8de 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs @@ -11,7 +11,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public double CenterX { get; set; } public double CenterY { get; set; } public string Label { get; set; } + public Brush? Highlight { get; set; } + public bool IsLocked { get; set; } public bool IsOpen => CallbackIsOpen(); public bool WantOpen => CallbackWantOpen(); public ISet Inputs { get; init; } @@ -57,9 +59,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { canvas.Children.Add(_text); } - public bool Update(double x, double y) { + public bool Update(double x, double y, bool down) { var hover = Math.Sqrt(Math.Pow(CenterX - x, 2) + Math.Pow(CenterY - y, 2)) <= DIAMETER / 2; - _circle?.Fill = hover ? Brushes.LightGray : Brushes.DarkGray; + _circle?.Fill = IsLocked ? Brushes.Red : Highlight ?? (hover ? Brushes.LightGray : Brushes.DarkGray); return hover; } } diff --git a/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml b/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml index 00fb485..90ddc3f 100644 --- a/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml +++ b/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:PamhagenSysCtrl.Windows" Title="Schema - Anlagensteuerung Pamhagen" Height="800" Width="1600"> - + diff --git a/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs b/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs index ef8a22e..6c8e021 100644 --- a/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs +++ b/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs @@ -8,6 +8,10 @@ namespace PamhagenSysCtrl.Windows { public partial class PlantSchemeWindow : Window { private readonly PamhagenGraph Graph; + private readonly List Paths = []; + + private ISource? _lastSource; + private ISet? _lastSelected; public PlantSchemeWindow() { InitializeComponent(); @@ -18,18 +22,83 @@ namespace PamhagenSysCtrl.Windows { private void SchemeCanvas_MouseMove(object sender, MouseEventArgs evt) { var p = evt.GetPosition(SchemeCanvas); + UpdateScheme(evt.GetPosition(SchemeCanvas), evt.LeftButton == MouseButtonState.Pressed); + } + + private void SchemeCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs evt) { + var p = evt.GetPosition(SchemeCanvas); + _lastSelected = UpdateScheme(evt.GetPosition(SchemeCanvas), evt.LeftButton == MouseButtonState.Pressed); + } + + private void SchemeCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs evt) { + var p = evt.GetPosition(SchemeCanvas); + var curSelected = UpdateScheme(evt.GetPosition(SchemeCanvas), evt.LeftButton == MouseButtonState.Pressed); + var clicked = curSelected.Intersect(_lastSelected ?? new HashSet()).ToList(); + _lastSource?.IsSelected = false; + if (clicked.Count == 0) { + _lastSource = null; + } + foreach (var c in clicked) { + if (_lastSource != null && c is ISink sink) { + var path = Graph.GetPath(_lastSource, sink, (n) => n is not ISink && (n is not Valve v || !v.IsLocked)); + if (path != null) { + Paths.Add(path.Value); + _lastSource = null; + } + } else if (c is ISource source) { + _lastSource = source; + _lastSource.IsSelected = true; + } else { + _lastSource = null; + } + } + UpdateScheme(evt.GetPosition(SchemeCanvas), evt.LeftButton == MouseButtonState.Pressed); + } + + private ISet UpdateScheme(Point pos, bool down) { foreach (var e in Graph.Edges) { e.Highlight = null; } - var hover = Graph.Update(p.X, p.Y); - if (hover.Count > 0) { - var path = Graph.GetPath(Graph.MW1, hover.First(), (n) => n is not ISink); + foreach (var p in Paths) { + var c = Brushes.Green; + foreach (var (edge, node) in p.Hops) { + edge.Highlight = Brushes.Green; + if (node is Pump) c = Brushes.Orange; + ColorSubgraph(node, c, (v) => v.IsLocked = true); + } + } + var hover = Graph.Update(pos.X, pos.Y, down); + if (_lastSource != null && hover.Count > 0) { + var path = Graph.GetPath(_lastSource, hover.First(), (n) => n is not ISink && (n is not Valve v || !v.IsLocked)); if (path != null) { + var c = Brushes.Green; foreach (var (edge, node) in path.Value.Hops) { edge.Highlight = Brushes.Green; + if (node is Pump) c = Brushes.Orange; + ColorSubgraph(node, c); } } - Graph.Update(p.X, p.Y); + Graph.Update(pos.X, pos.Y, down); + } + return hover; + } + + private void ColorSubgraph(INode start, Brush color, Action? valveAction = null) { + if (start is Valve v) { + valveAction?.Invoke(v); + return; + } else if (start is ISink || start is Pump) { + return; + } + foreach (var edge in start.Inputs) { + if (edge.Highlight != null) continue; + edge.Highlight = color; + ColorSubgraph(edge.Start, color, valveAction); + } + foreach (var edge in start.Outputs) { + if (edge.Highlight != null) continue; + edge.Highlight = color; + ColorSubgraph(edge.End, color, valveAction); } }