diff --git a/PamhagenSysCtrl/Helpers/PamhagenGraph.cs b/PamhagenSysCtrl/Helpers/PamhagenGraph.cs index 604c8a5..9d68498 100644 --- a/PamhagenSysCtrl/Helpers/PamhagenGraph.cs +++ b/PamhagenSysCtrl/Helpers/PamhagenGraph.cs @@ -94,10 +94,10 @@ namespace PamhagenSysCtrl.Helpers { CreatePipe(MP1, x1); CreatePipe(MP2, x2); - var v1 = CreateValve(1, mw1X, mpY + 16); - var v2 = CreateValve(2, mw2X, mpY + 16); - var v3 = CreateValve(3, mw2X + 6, mpY + 16); - var v4 = CreateValve(4, mw1X - 6, mpY + 16); + var v1 = CreateValve(1, mw1X, mpY + 16, 2); + var v2 = CreateValve(2, mw2X, mpY + 16, 0); + var v3 = CreateValve(3, mw2X + 6, mpY + 16, 2); + var v4 = CreateValve(4, mw1X - 6, mpY + 16, 0); CreatePipe(x1, v1); CreatePipe(x1, v4); @@ -116,11 +116,11 @@ namespace PamhagenSysCtrl.Helpers { CreatePipe(v4, x5, true); CreatePipe(x5, x6, true); - var v5 = CreateValve(5, x1X + 6, ltg1Y); - var v6 = CreateValve(6, x1X + 6, ltg2Y + 8); - var v7 = CreateValve(7, x1X + 6, ltg2Y); - var v8 = CreateValve(8, x1X - 6, ltg2Y + 8); - var v9 = CreateValve(9, ltg2X, ltg5Y + 8); + var v5 = CreateValve(5, x1X + 6, ltg1Y, 1); + var v6 = CreateValve(6, x1X + 6, ltg2Y + 8, 3); + var v7 = CreateValve(7, x1X + 6, ltg2Y, 3); + var v8 = CreateValve(8, x1X - 6, ltg2Y + 8, 0); + var v9 = CreateValve(9, ltg2X, ltg5Y + 8, 2); CreatePipe(x4, v5); CreatePipe(x4, v6, true); @@ -136,13 +136,13 @@ namespace PamhagenSysCtrl.Helpers { CreatePipe(v9, x7); CreatePipe(x7, xv11); - var v10 = CreateValve(10, ltg2X + 8, ltg5Y); - var v11 = CreateValve(11, ltg1X - 6, wt1Y + 14); - var v12 = CreateValve(12, ltg1X, wt1Y); - var v13 = CreateValve(13, ltg2X, wt1Y); - var v14 = CreateValve(14, ltg1X - 6, wt1Y - 8); - var v15 = CreateValve(15, ltg1X - 6, wt1Y + 8); - var v16 = CreateValve(16, ltg1X - 6, wt1Y - 14); + var v10 = CreateValve(10, ltg2X + 8, ltg5Y, 3); + var v11 = CreateValve(11, ltg1X - 6, wt1Y + 14, 3); + var v12 = CreateValve(12, ltg1X, wt1Y, 0); + var v13 = CreateValve(13, ltg2X, wt1Y, 2); + var v14 = CreateValve(14, ltg1X - 6, wt1Y - 8, 3); + var v15 = CreateValve(15, ltg1X - 6, wt1Y + 8, 1); + var v16 = CreateValve(16, ltg1X - 6, wt1Y - 14, 1); CreatePipe(v10, x7); CreatePipe(xv11, v11); CreatePipe(xv15, v15); @@ -156,8 +156,8 @@ namespace PamhagenSysCtrl.Helpers { CreatePipe(v16, xv16); CreatePipe(v14, xv14); - var v20 = CreateValve(20, ltg1X - 6, wt2Y - 14); - var v21 = CreateValve(21, ltg1X - 6, wt2Y - 8); + var v20 = CreateValve(20, ltg1X - 6, wt2Y - 14, 1); + var v21 = CreateValve(21, ltg1X - 6, wt2Y - 8, 3); var xv20 = new PipeJoin(ltg1X, wt2Y - 14); var xv21 = new PipeJoin(ltg2X, wt2Y - 8); CreatePipe(xv16, xv20); @@ -167,9 +167,9 @@ namespace PamhagenSysCtrl.Helpers { var wt1 = new HeatExchanger("WT Most", wtX, wt1Y); var wt2 = new HeatExchanger("WT Warmwasser", wtX, wt2Y); - var v17 = CreateValve(17, wtX + 14, wt1Y); - var v18 = CreateValve(18, wtX + 8, wt1Y + 8); - var v19 = CreateValve(19, wtX + 8, (wt1Y + wt2Y) / 2); + var v17 = CreateValve(17, wtX + 14, wt1Y, 2); + var v18 = CreateValve(18, wtX + 8, wt1Y + 8, 3); + var v19 = CreateValve(19, wtX + 8, (wt1Y + wt2Y) / 2, 0); var xwt1 = new PipeJoin(wtX + 24, wt1Y + 8); var xwt2 = new PipeJoin(wtX + 14, wt1Y + 8); var xwt3 = new PipeJoin(wtX + 8, wt1Y - 8); @@ -196,8 +196,8 @@ namespace PamhagenSysCtrl.Helpers { var xv22 = new PipeJoin(t1X - 3, ltg7Y); var xv23 = new PipeJoin(t1X + 3, ltg6Y); - var v22 = CreateValve(22, t1X - 3, tValveY); - var v23 = CreateValve(23, t1X + 3, tValveY); + var v22 = CreateValve(22, t1X - 3, tValveY, 0); + var v23 = CreateValve(23, t1X + 3, tValveY, 2); Tank1 = CreateTank(1, t1X, tanksY, 35000); CreatePipe(xv20, xv22, true, label: "Ltg. 7", labelOffsetX: 10); CreatePipe(xv21, xv23, true, label: "Ltg. 6", labelOffsetX: 4); @@ -208,8 +208,8 @@ namespace PamhagenSysCtrl.Helpers { var xv24 = new PipeJoin(t2X - 3, ltg7Y); var xv25 = new PipeJoin(t2X + 3, ltg6Y); - var v24 = CreateValve(24, t2X - 3, tValveY); - var v25 = CreateValve(25, t2X + 3, tValveY); + var v24 = CreateValve(24, t2X - 3, tValveY, 0); + var v25 = CreateValve(25, t2X + 3, tValveY, 2); Tank2 = CreateTank(2, t2X, tanksY, 35000); CreatePipe(xv22, xv24); CreatePipe(xv23, xv25); @@ -220,8 +220,8 @@ namespace PamhagenSysCtrl.Helpers { var xv26 = new PipeJoin(t3X - 3, ltg7Y); var xv27 = new PipeJoin(t3X + 3, ltg6Y); - var v26 = CreateValve(26, t3X - 3, tValveY); - var v27 = CreateValve(27, t3X + 3, tValveY); + var v26 = CreateValve(26, t3X - 3, tValveY, 0); + var v27 = CreateValve(27, t3X + 3, tValveY, 2); Tank3 = CreateTank(3, t3X, tanksY, 35000); CreatePipe(xv24, xv26); CreatePipe(xv25, xv27); @@ -230,15 +230,15 @@ namespace PamhagenSysCtrl.Helpers { CreateInlet(v26, Tank3); CreateInlet(v27, Tank3); - var v28 = CreateValve(28, (t3X + t4X) / 2, ltg7Y); - var v29 = CreateValve(29, (t3X + t4X) / 2, ltg6Y); + var v28 = CreateValve(28, (t3X + t4X) / 2, ltg7Y, 1); + var v29 = CreateValve(29, (t3X + t4X) / 2, ltg6Y, 3); CreatePipe(xv26, v28); CreatePipe(xv27, v29); var xv30 = new PipeJoin(t4X - 3, ltg7Y); var xv31 = new PipeJoin(t4X + 3, ltg6Y); - var v30 = CreateValve(30, t4X - 3, tValveY); - var v31 = CreateValve(31, t4X + 3, tValveY); + var v30 = CreateValve(30, t4X - 3, tValveY, 0); + var v31 = CreateValve(31, t4X + 3, tValveY, 2); Tank4 = CreateTank(4, t4X, tanksY, 35000); CreatePipe(v28, xv30); CreatePipe(v29, xv31); @@ -249,8 +249,8 @@ namespace PamhagenSysCtrl.Helpers { var xv32 = new PipeJoin(t5X - 3, ltg7Y); var xv33 = new PipeJoin(t5X + 3, ltg6Y); - var v32 = CreateValve(32, t5X - 3, tValveY); - var v33 = CreateValve(33, t5X + 3, tValveY); + var v32 = CreateValve(32, t5X - 3, tValveY, 0); + var v33 = CreateValve(33, t5X + 3, tValveY, 2); Tank5 = CreateTank(5, t5X, tanksY, 35000); CreatePipe(xv30, xv32, label: "Ltg. 7", labelOffsetX: 6); CreatePipe(xv31, xv33, label: "Ltg. 6", labelOffsetX: 0); @@ -259,15 +259,15 @@ namespace PamhagenSysCtrl.Helpers { CreateInlet(v32, Tank5); CreateInlet(v33, Tank5); - var v34 = CreateValve(34, (t5X + t6X) / 2, ltg7Y); - var v35 = CreateValve(35, (t5X + t6X) / 2, ltg6Y); + var v34 = CreateValve(34, (t5X + t6X) / 2, ltg7Y, 1); + var v35 = CreateValve(35, (t5X + t6X) / 2, ltg6Y, 3); CreatePipe(xv32, v34); CreatePipe(xv33, v35); var xv36 = new PipeJoin(t6X + 3, ltg6Y); var xv37 = new PipeJoin(t6X - 3, ltg7Y); - var v36 = CreateValve(36, t6X + 3, tValveY); - var v37 = CreateValve(37, t6X - 3, tValveY); + var v36 = CreateValve(36, t6X + 3, tValveY, 2); + var v37 = CreateValve(37, t6X - 3, tValveY, 0); Tank6 = CreateTank(6, t6X, tanksY, 35000); CreatePipe(v34, xv37); CreatePipe(v35, xv36); @@ -278,8 +278,8 @@ namespace PamhagenSysCtrl.Helpers { var xv38 = new PipeJoin(t7X + 3, ltg6Y); var xv39 = new PipeJoin(t7X - 3, ltg7Y); - var v38 = CreateValve(38, t7X + 3, tValveY); - var v39 = CreateValve(39, t7X - 3, tValveY); + var v38 = CreateValve(38, t7X + 3, tValveY, 2); + var v39 = CreateValve(39, t7X - 3, tValveY, 0); Tank7 = CreateTank(7, t7X, tanksY, 35000); CreatePipe(xv37, xv39); CreatePipe(xv36, xv38); @@ -290,8 +290,8 @@ namespace PamhagenSysCtrl.Helpers { var xv40 = new PipeJoin(t8X + 3, ltg6Y); var xv41 = new PipeJoin(t8X - 3, ltg7Y); - var v40 = CreateValve(40, t8X + 3, tValveY); - var v41 = CreateValve(41, t8X - 3, tValveY); + var v40 = CreateValve(40, t8X + 3, tValveY, 2); + var v41 = CreateValve(41, t8X - 3, tValveY, 0); Tank8 = CreateTank(8, t8X, tanksY, 35000); CreatePipe(xv38, xv40, label: "Ltg. 6", labelOffsetX: 0); CreatePipe(xv39, xv41, label: "Ltg. 7", labelOffsetX: 6); @@ -300,8 +300,8 @@ namespace PamhagenSysCtrl.Helpers { CreateInlet(v40, Tank8); CreateInlet(v41, Tank8); - var v42 = CreateValve(42, t9X + 3, tValveY); - var v43 = CreateValve(43, t9X - 3, tValveY); + var v42 = CreateValve(42, t9X + 3, tValveY, 2); + var v43 = CreateValve(43, t9X - 3, tValveY, 0); Tank9 = CreateTank(9, t9X, tanksY, 35000); CreatePipe(xv40, v42); CreatePipe(xv41, v43); @@ -321,11 +321,11 @@ namespace PamhagenSysCtrl.Helpers { CreateOutlet(Tank4, P4); CreateOutlet(Tank5, P5); - var v44 = CreateValve(44, (t1X + t2X) / 2, tanksY + 30); - var v45 = CreateValve(45, t3X, tanksY + 30); - var v46 = CreateValve(46, (t3X + t4X) / 2, ltg5Y); - var v47 = CreateValve(47, t4X, tanksY + 30); - var v48 = CreateValve(48, t5X, tanksY + 30); + var v44 = CreateValve(44, (t1X + t2X) / 2, tanksY + 30, 2); + var v45 = CreateValve(45, t3X, tanksY + 30, 2); + var v46 = CreateValve(46, (t3X + t4X) / 2, ltg5Y, 3); + var v47 = CreateValve(47, t4X, tanksY + 30, 2); + var v48 = CreateValve(48, t5X, tanksY + 30, 2); var xv44 = new PipeJoin((t1X + t2X) / 2, tanksY + 36); var xv45 = new PipeJoin(t3X, tanksY + 36); var xv47 = new PipeJoin(t4X, tanksY + 36); @@ -355,7 +355,7 @@ namespace PamhagenSysCtrl.Helpers { CreatePipe(xt7, xt6); CreatePipe(xt6, P6); - var v49 = CreateValve(49, t4X, tanksY + 44); + var v49 = CreateValve(49, t4X, tanksY + 44, 2); CreatePipe(xv47, v49); var prX = (pr1X + pr2X) / 2; @@ -363,14 +363,14 @@ namespace PamhagenSysCtrl.Helpers { var pr2cX = prX + 3; Press1 = new Press("Presse 1", pr1X, prY, 20000, () => FillState.Unknown); Press2 = new Press("Presse 2", pr2X, prY, 15000, () => FillState.Unknown); - var v50 = CreateValve(50, pr2cX + 6, ltg3Y); - var v51 = CreateValve(51, pr1cX - 6, ltg3Y); - var v52 = CreateValve(52, pr1cX - 6, ltg4Y); - var v53 = CreateValve(53, pr2cX + 6, ltg4Y); - var v54 = CreateValve(54, pr2cX + 6, ltg8Y); - var v55 = CreateValve(55, pr1cX - 6, ltg8Y); - var v56 = CreateValve(56, pr1cX - 6, ltg9Y); - var v57 = CreateValve(57, pr2cX + 6, ltg9Y); + var v50 = CreateValve(50, pr2cX + 6, ltg3Y, 1); + var v51 = CreateValve(51, pr1cX - 6, ltg3Y, 1); + var v52 = CreateValve(52, pr1cX - 6, ltg4Y, 3); + var v53 = CreateValve(53, pr2cX + 6, ltg4Y, 3); + var v54 = CreateValve(54, pr2cX + 6, ltg8Y, 1); + var v55 = CreateValve(55, pr1cX - 6, ltg8Y, 1); + var v56 = CreateValve(56, pr1cX - 6, ltg9Y, 3); + var v57 = CreateValve(57, pr2cX + 6, ltg9Y, 3); var xp1 = new PipeJoin(pr1cX - 14, ltg3Y); var xp2 = new PipeJoin(pr1cX - 14, ltg4Y); var xp3 = new PipeJoin(pr2cX + 14, ltg8Y); @@ -404,16 +404,16 @@ namespace PamhagenSysCtrl.Helpers { CreatePipe(xp5, xp6); CreatePipe(xp7, xp8); - var zv1 = new CenterValve("ZV1", pr1cX, prY - 8, () => App.Plant?.Press1HasClearance ?? false); - var zv2 = new CenterValve("ZV2", pr2cX, prY - 8, () => App.Plant?.Press2HasClearance ?? false); + var zv1 = new ExternalValve("ZV1", pr1cX, prY - 8, 0, () => App.Plant?.Press1HasClearance ?? false); + var zv2 = new ExternalValve("ZV2", pr2cX, prY - 8, 2, () => App.Plant?.Press2HasClearance ?? false); CreatePipe(xp6, zv1, true); CreatePipe(xp8, zv2, true); CreateInlet(zv1, Press1, true); CreateInlet(zv2, Press2, true); } - protected Valve CreateValve(int n, double x, double y) { - return new(n, x, y, () => App.Plant?.IsValveOpen(n) ?? false, (v) => App.Plant?.ManualControlMode ?? false ? App.Plant.WantValveOpen(n) : SelectedPaths.Any(p => p.Hops.Any(h => h.Node == v))); + protected ControlledValve CreateValve(int n, double x, double y, int o) { + return new(n, x, y, o, () => App.Plant?.IsValveOpen(n) ?? false, (v) => App.Plant?.ManualControlMode ?? false ? App.Plant.WantValveOpen(n) : SelectedPaths.Any(p => p.Hops.Any(h => h.Node == v))); } protected static Tank CreateTank(int n, double x, double y, int capacity) { @@ -423,23 +423,23 @@ namespace PamhagenSysCtrl.Helpers { private int PathCost(Path p) { return 1000 * p.Hops.Count(h => h.Node is Valve) + - (p.Hops.Any(h => h.Node is Valve v && v.Nr == 15) && !p.Hops.Any(h => h.Node is Valve v && (v.Nr == 16 || v.Nr == 20)) ? 10 : 0) + - (p.Hops.Any(h => h.Node is Valve v && v.Nr == 11) && !p.Hops.Any(h => h.Node is Valve v && (v.Nr == 14 || v.Nr == 21)) ? 10 : 0) + - (p.Hops.Any(h => h.Node is Valve v && v.Nr == 6) ? 10 : 0) + + (p.Hops.Any(h => h.Node is ControlledValve v && v.Nr == 15) && !p.Hops.Any(h => h.Node is ControlledValve v && (v.Nr == 16 || v.Nr == 20)) ? 10 : 0) + + (p.Hops.Any(h => h.Node is ControlledValve v && v.Nr == 11) && !p.Hops.Any(h => h.Node is ControlledValve v && (v.Nr == 14 || v.Nr == 21)) ? 10 : 0) + + (p.Hops.Any(h => h.Node is ControlledValve v && v.Nr == 6) ? 10 : 0) + p.Bends; } public Path? GetFreePath(IEnumerable points, bool overrideStart = false) { if (overrideStart) { - return GetPath(points, (n) => n is not ISink && (n is not Valve v || !v.LockedForPaths.Any(p => p.Start != points.First())), PathCost); + return GetPath(points, (n) => n is not ISink && (n is not ControlledValve v || !v.LockedForPaths.Any(p => p.Start != points.First())), PathCost); } else { - return GetPath(points, (n) => n is not ISink && (n is not Valve v || !v.IsLocked), PathCost); + return GetPath(points, (n) => n is not ISink && (n is not ControlledValve v || !v.IsLocked), PathCost); } } - public void TraverseSubgraph(INode start, Func invalid, HashSet? _visited = null, Action? edgeAction = null, Action? valveAction = null, bool reverse = false) { + public void TraverseSubgraph(INode start, Func invalid, HashSet? _visited = null, Action? edgeAction = null, Action? valveAction = null, bool reverse = false) { var visited = _visited ?? []; - if (start is Valve v) { + if (start is ControlledValve v) { valveAction?.Invoke(v); } if (invalid(start)) { @@ -467,7 +467,7 @@ namespace PamhagenSysCtrl.Helpers { UpdateValvesAdjacientToPath(path, true, false); if (App.Plant is PamhagenPlant plant) { foreach (var (_, node) in path.Hops) { - if (node is Valve v) { + if (node is ControlledValve v) { plant.OpenV(v.Nr); } } @@ -480,7 +480,7 @@ namespace PamhagenSysCtrl.Helpers { foreach (var p in _selectedPaths) UpdateValvesAdjacientToPath(p, true); if (App.Plant is PamhagenPlant plant) { foreach (var (_, node) in path.Hops) { - if (node is Valve v) { + if (node is ControlledValve v) { plant.CloseV(v.Nr); } } @@ -489,7 +489,7 @@ namespace PamhagenSysCtrl.Helpers { private void UpdateValvesAdjacientToPath(Path path, bool locked, bool? wantOpen = null) { foreach (var (edge, node) in path.Hops) { - TraverseSubgraph(node, (n) => n is Valve || n is ISink || n is Pump, valveAction: (v) => { + TraverseSubgraph(node, (n) => n is ControlledValve || n is ISink || n is Pump, valveAction: (v) => { if (locked) { v.LockedForPaths.Add(path); } else { @@ -526,7 +526,7 @@ namespace PamhagenSysCtrl.Helpers { public void ColorPipesByValves(INode start, Brush? color1, MotorState flowArrows, Brush? color2) { var flowPathOffset = 0.0; - TraverseSubgraph(start, (n) => n is ISink || n is Outlet || !((n as Valve)?.IsOpen ?? (n as CenterValve)?.IsOpen ?? true), null, + TraverseSubgraph(start, (n) => n is ISink || n is Outlet || !((n as Valve)?.IsOpen ?? (n as ExternalValve)?.IsOpen ?? true), null, edgeAction: (s, r, e) => { if (((e.Start as Valve)?.IsOpen ?? true) && ((e.End as Valve)?.IsOpen ?? true)) { e.Highlight = color1; diff --git a/PamhagenSysCtrl/Helpers/Pipeline/CenterValve.cs b/PamhagenSysCtrl/Helpers/Pipeline/CenterValve.cs deleted file mode 100644 index 579ba56..0000000 --- a/PamhagenSysCtrl/Helpers/Pipeline/CenterValve.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; - -namespace PamhagenSysCtrl.Helpers.Pipeline { - public class CenterValve : INode { - - public const double DIAMETER = 4.8; - - public double CenterX { get; set; } - public double CenterY { get; set; } - public string Label { get; set; } - public Brush? Highlight { get; set; } - - public bool IsOpen => CallbackIsOpen(); - public ISet Inputs { get; init; } - public ISet Outputs { get; init; } - - protected Func CallbackIsOpen; - - private Shape? _circle; - private TextBlock? _text; - - public CenterValve(string label, double x, double y, Func cbOpen) { - CenterX = x; - CenterY = y; - Label = label; - CallbackIsOpen = cbOpen; - Inputs = new HashSet(); - Outputs = new HashSet(); - } - - public void Draw(Canvas canvas) { - _circle = new Ellipse() { - Fill = Brushes.DarkGray, - Stroke = Brushes.Black, - }; - _text = new() { - Text = Label, - TextAlignment = TextAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - SnapsToDevicePixels = true, - }; - canvas.Children.Add(_circle); - canvas.Children.Add(_text); - } - - public void Scale(double scale) { - var border = Graph.ToBorder(scale); - Graph.SetCenter(_circle, CenterX, CenterY, DIAMETER, DIAMETER, scale); - _circle?.StrokeThickness = border; - _text?.Width = DIAMETER * scale; - _text?.Height = DIAMETER * scale; - _text?.FontSize = 2 * scale; - _text?.SetValue(Canvas.LeftProperty, (CenterX - DIAMETER / 2 + 0.1) * scale); - _text?.SetValue(Canvas.TopProperty, (CenterY - DIAMETER / 2 + 1.1) * scale); - } - - public bool IsInside(double x, double y) { - return Math.Sqrt(Math.Pow(CenterX - x, 2) + Math.Pow(CenterY - y, 2)) <= DIAMETER / 2; - } - - public void Update(bool isHovering, bool isPressed) { - _circle?.Fill = - !IsOpen ? PamhagenBrushes.Red : - IsOpen ? PamhagenBrushes.Green : - Highlight ?? Brushes.DarkGray; - } - } -} diff --git a/PamhagenSysCtrl/Helpers/Pipeline/ControlledValve.cs b/PamhagenSysCtrl/Helpers/Pipeline/ControlledValve.cs new file mode 100644 index 0000000..f4e663d --- /dev/null +++ b/PamhagenSysCtrl/Helpers/Pipeline/ControlledValve.cs @@ -0,0 +1,44 @@ +using System.Windows; +using System.Windows.Media; + +namespace PamhagenSysCtrl.Helpers.Pipeline { + public class ControlledValve : Valve { + + public int Nr { get; set; } + public override string Label => $"V{Nr}"; + + public readonly ISet LockedForPaths = new HashSet(); + public bool IsLocked => LockedForPaths.Any(); + public bool WantOpen => CallbackWantOpen(this); + + protected Func CallbackWantOpen; + + public ControlledValve(int nr, double x, double y, int orientation, Func cbOpen, Func cbWant) : + base(x, y, orientation, cbOpen) { + Nr = nr; + CallbackWantOpen = cbWant; + } + + public override void Update(bool isHovering, bool isPressed) { + if (App.Plant?.ManualControlMode ?? false) { + _text?.Visibility = Visibility.Visible; + _triangles?.Fill = + !WantOpen && !IsOpen && !isHovering ? PamhagenBrushes.Red : + !WantOpen && !IsOpen ? PamhagenBrushes.Green : + !WantOpen && IsOpen ? PamhagenBrushes.DimRed : + WantOpen && !IsOpen ? PamhagenBrushes.DimGreen : + WantOpen && IsOpen && !isHovering ? PamhagenBrushes.Green : + WantOpen && IsOpen ? PamhagenBrushes.Red : + Highlight ?? (isHovering ? Brushes.LightGray : Brushes.DarkGray); + } else { + _text?.Visibility = isHovering ? Visibility.Visible : Visibility.Hidden; + _triangles?.Fill = + IsLocked && !WantOpen && !IsOpen ? PamhagenBrushes.DimOrange : + IsLocked && !WantOpen && IsOpen ? PamhagenBrushes.Red : + IsLocked && WantOpen && !IsOpen ? PamhagenBrushes.Yellow : + IsLocked && WantOpen && IsOpen ? PamhagenBrushes.Green : + Highlight ?? (isHovering ? Brushes.LightGray : Brushes.DarkGray); + } + } + } +} diff --git a/PamhagenSysCtrl/Helpers/Pipeline/ExternalValve.cs b/PamhagenSysCtrl/Helpers/Pipeline/ExternalValve.cs new file mode 100644 index 0000000..eff2ff2 --- /dev/null +++ b/PamhagenSysCtrl/Helpers/Pipeline/ExternalValve.cs @@ -0,0 +1,22 @@ +using System.Windows; +using System.Windows.Media; + +namespace PamhagenSysCtrl.Helpers.Pipeline { + public class ExternalValve : Valve { + + public override string Label { get; } + + public ExternalValve(string label, double x, double y, int orientation, Func cbOpen) : + base(x, y, orientation, cbOpen) { + Label = label; + } + + public override void Update(bool isHovering, bool isPressed) { + _text?.Visibility = isHovering || (App.Plant?.ManualControlMode ?? false) ? Visibility.Visible : Visibility.Hidden; + _triangles?.Fill = + !IsOpen ? PamhagenBrushes.Red : + IsOpen ? PamhagenBrushes.Green : + Highlight ?? Brushes.DarkGray; + } + } +} diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs b/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs index c2439d4..f2b79b1 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Valve.cs @@ -4,88 +4,134 @@ using System.Windows.Media; using System.Windows.Shapes; namespace PamhagenSysCtrl.Helpers.Pipeline { - public class Valve : INode { + public abstract class Valve : INode { - public const double DIAMETER = 4.8; + public const double LENGTH = 4.8; + public const double WIDTH = 2.6; public double CenterX { get; set; } public double CenterY { get; set; } - public int Nr { get; set; } - public string Label => $"V{Nr}"; + public abstract string Label { get; } public Brush? Highlight { get; set; } - public readonly ISet LockedForPaths = new HashSet(); + public int Orientation { get; set; } - public bool IsLocked => LockedForPaths.Any(); public bool IsOpen => CallbackIsOpen(); - public bool WantOpen => CallbackWantOpen(this); public ISet Inputs { get; init; } public ISet Outputs { get; init; } protected Func CallbackIsOpen; - protected Func CallbackWantOpen; - private Shape? _circle; - private TextBlock? _text; + protected Rectangle? _background; + protected Polygon? _triangles; + protected Polyline? _topLine; + protected Polyline? _bottomLine; + protected TextBlock? _text; - public Valve(int nr, double x, double y, Func cbOpen, Func cbWant) { + public Valve(double x, double y, int orientation, Func cbOpen) { CenterX = x; CenterY = y; - Nr = nr; CallbackIsOpen = cbOpen; - CallbackWantOpen = cbWant; Inputs = new HashSet(); Outputs = new HashSet(); + Orientation = orientation; } public void Draw(Canvas canvas) { - _circle = new Ellipse() { + _background = new Rectangle() { + Fill = Brushes.White, + }; + _triangles = new Polygon() { Fill = Brushes.DarkGray, Stroke = Brushes.Black, }; + _topLine = new Polyline() { + Stroke = Brushes.Black, + }; + _bottomLine = new Polyline() { + Stroke = Brushes.Black, + }; _text = new() { Text = Label, - TextAlignment = TextAlignment.Center, VerticalAlignment = VerticalAlignment.Center, SnapsToDevicePixels = true, }; - canvas.Children.Add(_circle); + canvas.Children.Add(_background); + canvas.Children.Add(_triangles); + canvas.Children.Add(_topLine); + canvas.Children.Add(_bottomLine); canvas.Children.Add(_text); } public void Scale(double scale) { var border = Graph.ToBorder(scale); - Graph.SetCenter(_circle, CenterX, CenterY, DIAMETER, DIAMETER, scale); - _circle?.StrokeThickness = border; - _text?.Width = DIAMETER * scale; - _text?.Height = DIAMETER * scale; - _text?.FontSize = 2 * scale; - _text?.SetValue(Canvas.LeftProperty, (CenterX - DIAMETER / 2 + 0.1) * scale); - _text?.SetValue(Canvas.TopProperty, (CenterY - DIAMETER / 2 + 1.1) * scale); + if (Orientation == 0 || Orientation == 2) { + Graph.SetCenter(_background, CenterX, CenterY, LENGTH / 2, LENGTH, scale); + _triangles?.Points = [ + Graph.ToPx(CenterX - WIDTH / 2, CenterY - LENGTH / 2, scale), + Graph.ToPx(CenterX + WIDTH / 2, CenterY + LENGTH / 2, scale), + Graph.ToPx(CenterX - WIDTH / 2, CenterY + LENGTH / 2, scale), + Graph.ToPx(CenterX + WIDTH / 2, CenterY - LENGTH / 2, scale), + ]; + _topLine?.Points = [ + Graph.ToPx(CenterX - WIDTH / 2, CenterY - LENGTH / 4, scale), + Graph.ToPx(CenterX - WIDTH / 4, CenterY, scale), + Graph.ToPx(CenterX - WIDTH / 2, CenterY + LENGTH / 4, scale), + ]; + _bottomLine?.Points = [ + Graph.ToPx(CenterX + WIDTH / 2, CenterY - LENGTH / 4, scale), + Graph.ToPx(CenterX + WIDTH / 4, CenterY, scale), + Graph.ToPx(CenterX + WIDTH / 2, CenterY + LENGTH / 4, scale), + ]; + } else { + Graph.SetCenter(_background, CenterX, CenterY, LENGTH, LENGTH / 2, scale); + _triangles?.Points = [ + Graph.ToPx(CenterX - LENGTH / 2, CenterY - WIDTH / 2, scale), + Graph.ToPx(CenterX + LENGTH / 2, CenterY + WIDTH / 2, scale), + Graph.ToPx(CenterX + LENGTH / 2, CenterY - WIDTH / 2, scale), + Graph.ToPx(CenterX - LENGTH / 2, CenterY + WIDTH / 2, scale), + ]; + _topLine?.Points = [ + Graph.ToPx(CenterX - LENGTH / 4, CenterY - WIDTH / 2, scale), + Graph.ToPx(CenterX, CenterY - WIDTH / 4, scale), + Graph.ToPx(CenterX + LENGTH / 4, CenterY - WIDTH / 2, scale), + ]; + _bottomLine?.Points = [ + Graph.ToPx(CenterX - LENGTH / 4, CenterY + WIDTH / 2, scale), + Graph.ToPx(CenterX, CenterY + WIDTH / 4, scale), + Graph.ToPx(CenterX + LENGTH / 4, CenterY + WIDTH / 2, scale), + ]; + } + _triangles?.StrokeThickness = border; + _topLine?.StrokeThickness = border; + _bottomLine?.StrokeThickness = border; + _text?.Width = 40; + _text?.Height = 16; + _text?.FontSize = 12; + _text?.TextAlignment = Orientation == 0 ? TextAlignment.Right : Orientation == 2 ? TextAlignment.Left : TextAlignment.Center; + if (Orientation == 0) { + _text?.SetValue(Canvas.LeftProperty, (CenterX - WIDTH / 1.5) * scale - 40); + _text?.SetValue(Canvas.TopProperty, CenterY * scale - 8); + } else if (Orientation == 2) { + _text?.SetValue(Canvas.LeftProperty, (CenterX + WIDTH / 1.5) * scale); + _text?.SetValue(Canvas.TopProperty, CenterY * scale - 8 ); + } else if (Orientation == 1) { + _text?.SetValue(Canvas.LeftProperty, CenterX * scale - 20); + _text?.SetValue(Canvas.TopProperty, (CenterY - WIDTH / 2) * scale - 16); + } else { + _text?.SetValue(Canvas.LeftProperty, CenterX * scale - 20); + _text?.SetValue(Canvas.TopProperty, (CenterY + WIDTH / 2) * scale); + } } public bool IsInside(double x, double y) { - return Math.Sqrt(Math.Pow(CenterX - x, 2) + Math.Pow(CenterY - y, 2)) <= DIAMETER / 2; - } - - public void Update(bool isHovering, bool isPressed) { - if (App.Plant?.ManualControlMode ?? false) { - _circle?.Fill = - !WantOpen && !IsOpen && !isHovering ? PamhagenBrushes.Red : - !WantOpen && !IsOpen ? PamhagenBrushes.Green : - !WantOpen && IsOpen ? PamhagenBrushes.DimRed : - WantOpen && !IsOpen ? PamhagenBrushes.DimGreen : - WantOpen && IsOpen && !isHovering ? PamhagenBrushes.Green : - WantOpen && IsOpen ? PamhagenBrushes.Red : - Highlight ?? (isHovering ? Brushes.LightGray : Brushes.DarkGray); + if (Orientation == 0 || Orientation == 2) { + return Math.Abs(x - CenterX) <= WIDTH / 2 && Math.Abs(y - CenterY) <= LENGTH / 2; } else { - _circle?.Fill = - IsLocked && !WantOpen && !IsOpen ? PamhagenBrushes.DimOrange : - IsLocked && !WantOpen && IsOpen ? PamhagenBrushes.Red : - IsLocked && WantOpen && !IsOpen ? PamhagenBrushes.Yellow : - IsLocked && WantOpen && IsOpen ? PamhagenBrushes.Green : - Highlight ?? (isHovering ? Brushes.LightGray : Brushes.DarkGray); + return Math.Abs(x - CenterX) <= LENGTH / 2 && Math.Abs(y - CenterY) <= WIDTH / 2; } } + + public abstract void Update(bool isHovering, bool isPressed); } } diff --git a/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs b/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs index e0301f7..620e088 100644 --- a/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs +++ b/PamhagenSysCtrl/Windows/PlantSchemeWindow.xaml.cs @@ -349,7 +349,7 @@ namespace PamhagenSysCtrl.Windows { } foreach (var c in clicked) { if (App.Plant?.ManualControlMode ?? false) { - if (c is Valve v) { + if (c is ControlledValve v) { if (v.WantOpen) { App.Plant.CloseV(v.Nr); } else { @@ -564,14 +564,14 @@ namespace PamhagenSysCtrl.Windows { if (Graph.SelectedPaths.Select(p => (Path?)p).FirstOrDefault(p => p?.Start == Graph.MW1) is Path pmw1) { MP1_Target.Text = "\u2b9e " + string.Join(" \u2b9e ", pmw1.Hops - .Select(h => h.Node is Valve || h.Node is Pump || h.Node is CenterValve ? null : h.Node.Label) + .Select(h => h.Node is Valve || h.Node is Pump ? null : h.Node.Label) .Where(l => !string.IsNullOrWhiteSpace(l))); } else { MP1_Target.Text = "Vor"; } if (Graph.SelectedPaths.Select(p => (Path?)p).FirstOrDefault(p => p?.Start == Graph.MW2) is Path pmw2) { MP2_Target.Text = "\u2b9e " + string.Join(" \u2b9e ", pmw2.Hops - .Select(h => h.Node is Valve || h.Node is Pump || h.Node is CenterValve ? null : h.Node.Label) + .Select(h => h.Node is Valve || h.Node is Pump ? null : h.Node.Label) .Where(l => !string.IsNullOrWhiteSpace(l))); } else { MP2_Target.Text = "Vor"; @@ -605,7 +605,7 @@ namespace PamhagenSysCtrl.Windows { App.Plant?.CloseV(i); } foreach (var p in add) { - if (p.Hops.Any(h => h.Node is Valve v && v.IsLocked)) continue; + if (p.Hops.Any(h => h.Node is ControlledValve v && v.IsLocked)) continue; Graph.AddPath(p); } } @@ -617,7 +617,7 @@ namespace PamhagenSysCtrl.Windows { foreach (var src in sources) { var paths = new List(); foreach (var sink in sinks) { - paths.AddRange(Graph.GetPaths(src, sink, null, (n) => n is not ISink && (n is not Valve v || p.WantValveOpen(v.Nr)))); + paths.AddRange(Graph.GetPaths(src, sink, null, (n) => n is not ISink && (n is not ControlledValve v || p.WantValveOpen(v.Nr)))); } if (paths.Count == 1) yield return paths.First();