6 Commits
20 changed files with 853 additions and 324 deletions
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
</dependentAssembly>
</dependency>
</assembly>
@@ -0,0 +1,4 @@
namespace PamhagenSysCtrl.Helpers {
public class NoClearanceException(string msg) : Exception(msg) {
}
}
+61 -43
View File
@@ -9,6 +9,15 @@ namespace PamhagenSysCtrl.Helpers {
public readonly Trough MW1;
public readonly Trough MW2;
public readonly Pump MP1;
public readonly Pump MP2;
public readonly Pump P12;
public readonly Pump P3;
public readonly Pump P4;
public readonly Pump P5;
public readonly Pump P6;
public readonly EncasedAuger Auger1;
public readonly EncasedAuger Auger2;
public PamhagenGraph() {
double mw2X = 180;
@@ -38,31 +47,33 @@ namespace PamhagenSysCtrl.Helpers {
var pr1X = 750;
var pr2X = 900;
var trough = new EntryTrough("Auffangwanne", mw1X + 70, 100);
var trough = new EntryTrough("Auffangwanne", mw1X + 70, 100, () => App.Plant?.IsTroughAugerActive ?? false);
Nodes.Add(trough);
var auger1 = new EncasedAuger("", (mw1X + mw2X) / 2 - 100, 200);
var auger2 = new EncasedAuger("Pressen-\nQuerschnecke", 40, 200, 180);
var auger3 = new EncasedAuger("", 120, 80, 135);
var belt = new ConveyorBelt("", 90, 160);
Auger1 = new EncasedAuger("", (mw1X + mw2X) / 2 - 100, 200, () => App.Plant?.IsAuger1Active ?? false);
var auger3 = new EncasedAuger("Pressen-\nQuerschnecke", 40, 200, () => App.Plant?.IsPresseQuerSchneckeActive ?? false, 180, clickable: false);
Auger2 = new EncasedAuger("", 120, 80, () => App.Plant?.IsAuger2Active ?? false, 135);
var belt = new ConveyorBelt("", 90, 160, () => App.Plant?.IsBeltActive ?? false);
Nodes.Add(belt);
Nodes.Add(auger1);
Nodes.Add(auger2);
Nodes.Add(Auger1);
Nodes.Add(auger3);
var rebler = new Rebler("Rebler", (mw1X + mw2X) / 2, 200);
Nodes.Add(Auger2);
var rebler = new Rebler("Rebler", (mw1X + mw2X) / 2, 200, () => App.Plant?.IsReblerActive ?? false);
Nodes.Add(rebler);
var switcher = new Switcher("", (mw1X + mw2X) / 2, 260, () => App.Plant?.TroughSelector ?? 0, () => App.Plant == null ? 0 : App.Plant.WantA1Selected ? 1 : 2);
Nodes.Add(switcher);
MW1 = new Trough("MW1", mw1X, mpY - 70, () => App.Plant?.FillLevelA1 ?? FillState.Unknown);
MW2 = new Trough("MW2", mw2X, mpY - 70, () => App.Plant?.FillLevelA1 ?? FillState.Unknown);
var mp1 = new Pump("MP1", mw1X, mpY);
var mp2 = new Pump("MP2", mw2X, mpY);
MW2 = new Trough("MW2", mw2X, mpY - 70, () => App.Plant?.FillLevelA2 ?? FillState.Unknown);
MP1 = new Pump("MP1", mw1X, mpY, () => App.Plant?.IsMP1Active ?? false, () => App.Plant?.MP1HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
MP2 = new Pump("MP2", mw2X, mpY, () => App.Plant?.IsMP2Active ?? false, () => App.Plant?.MP2HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
var x1 = new PipeJoin(mw1X, mpY + 40);
var x2 = new PipeJoin(mw2X, mpY + 40);
CreateOutlet(MW1, mp1);
CreateOutlet(MW2, mp2);
CreatePipe(mp1, x1);
CreatePipe(mp2, x2);
CreateOutlet(MW1, MP1);
CreateOutlet(MW2, MP2);
CreatePipe(MP1, x1);
CreatePipe(MP2, x2);
var v1 = CreateValve(1, mw1X, mpY + 70);
var v2 = CreateValve(2, mw2X, mpY + 70);
@@ -279,17 +290,17 @@ namespace PamhagenSysCtrl.Helpers {
CreateInlet(v43, t9);
var xp12 = new PipeJoin((t1X + t2X) / 2, tanksY + 80);
var p12 = new Pump("P1/2", (t1X + t2X) / 2, tanksY + 110);
P12 = new Pump("P1/2", (t1X + t2X) / 2, tanksY + 110, () => App.Plant?.IsP12Active ?? false, () => App.Plant?.P12HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
CreateOutlet(t1, xp12);
CreateOutlet(t2, xp12);
CreatePipe(xp12, p12);
CreatePipe(xp12, P12);
var p3 = new Pump("P3", t3X, tanksY + 110);
var p4 = new Pump("P4", t4X, tanksY + 110);
var p5 = new Pump("P5", t5X, tanksY + 110);
CreateOutlet(t3, p3);
CreateOutlet(t4, p4);
CreateOutlet(t5, p5);
P3 = new Pump("P3", t3X, tanksY + 110, () => App.Plant?.IsP3Active ?? false, () => App.Plant?.P3HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
P4 = new Pump("P4", t4X, tanksY + 110, () => App.Plant?.IsP4Active ?? false, () => App.Plant?.P4HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
P5 = new Pump("P5", t5X, tanksY + 110, () => App.Plant?.IsP5Active ?? false, () => App.Plant?.P5HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
CreateOutlet(t3, P3);
CreateOutlet(t4, P4);
CreateOutlet(t5, P5);
var v44 = CreateValve(44, (t1X + t2X) / 2, tanksY + 150);
var v45 = CreateValve(45, t3X, tanksY + 150);
@@ -299,10 +310,10 @@ namespace PamhagenSysCtrl.Helpers {
var xv44 = new PipeJoin((t1X + t2X) / 2, tanksY + 180);
var xv45 = new PipeJoin(t3X, tanksY + 180);
var xv47 = new PipeJoin(t4X, tanksY + 180);
CreatePipe(p12, v44);
CreatePipe(p3, v45);
CreatePipe(p4, v47);
CreatePipe(p5, v48);
CreatePipe(P12, v44);
CreatePipe(P3, v45);
CreatePipe(P4, v47);
CreatePipe(P5, v48);
CreatePipe(v44, xv44);
CreatePipe(v45, xv45);
CreatePipe(v47, xv47);
@@ -316,20 +327,20 @@ namespace PamhagenSysCtrl.Helpers {
var xt6 = new PipeJoin(t6X, tanksY + 110);
var xt7 = new PipeJoin(t7X, tanksY + 110);
var xt8 = new PipeJoin(t8X, tanksY + 110);
var p6 = new Pump("P6", t6X, tanksY + 150);
P6 = new Pump("P6", t6X, tanksY + 150, () => App.Plant?.IsP6Active ?? false, () => App.Plant?.P6HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
CreateOutlet(t6, xt6);
CreateOutlet(t7, xt7);
CreateOutlet(t8, xt8);
CreateOutlet(t9, xt8);
CreatePipe(xt8, xt7);
CreatePipe(xt7, xt6);
CreatePipe(xt6, p6);
CreatePipe(xt6, P6);
var v49 = CreateValve(49, t4X, tanksY + 220);
CreatePipe(xv47, v49);
var press1 = new Press("Presse 1", pr1X, prY, 200000, () => App.Plant?.FillLevelPress1 ?? FillState.Unknown);
var press2 = new Press("Presse 2", pr2X, prY, 150000, () => App.Plant?.FillLevelPress1 ?? FillState.Unknown);
var press2 = new Press("Presse 2", pr2X, prY, 150000, () => App.Plant?.FillLevelPress2 ?? FillState.Unknown);
var v50 = CreateValve(50, pr1X - 45, prY - 100);
var v51 = CreateValve(51, pr1X - 15, prY - 100);
var v52 = CreateValve(52, pr1X + 15, prY - 100);
@@ -346,7 +357,7 @@ namespace PamhagenSysCtrl.Helpers {
CreatePipe(v6, xp1, true);
CreatePipe(v8, xp2, true);
CreatePipe(v49, xp3, true);
CreatePipe(p6, xp4, true);
CreatePipe(P6, xp4, true);
CreatePipe(xp1, v51);
CreatePipe(xp1, v55);
CreatePipe(xp2, v52);
@@ -367,7 +378,7 @@ namespace PamhagenSysCtrl.Helpers {
}
protected static Valve CreateValve(int n, double x, double y) {
return new(n, x, y, () => App.Plant?.IsValveOpen(4) ?? false, () => App.Plant?.WantValveOpen(4) ?? false);
return new(n, x, y, () => App.Plant?.IsValveOpen(n) ?? false, () => App.Plant?.WantValveOpen(n) ?? false);
}
protected static Tank CreateTank(int n, double x, double y, int capacity) {
@@ -400,14 +411,13 @@ namespace PamhagenSysCtrl.Helpers {
public void AddPath(Path path) {
_selectedPaths.Add(path);
UpdateValvesAdjacientToPath(path, true);
UpdateValvesAdjacientToPath(path, true, false);
if (App.Plant is PamhagenPlant plant) {
foreach (var (edge, _) in path.Hops) {
if (edge is Valve v) {
foreach (var (_, node) in path.Hops) {
if (node is Valve v) {
plant.OpenV(v.Nr);
}
}
plant.CommitChanges();
}
}
@@ -416,28 +426,36 @@ namespace PamhagenSysCtrl.Helpers {
UpdateValvesAdjacientToPath(path, false);
foreach (var p in _selectedPaths) UpdateValvesAdjacientToPath(p, true);
if (App.Plant is PamhagenPlant plant) {
foreach (var (edge, _) in path.Hops) {
if (edge is Valve v) {
foreach (var (_, node) in path.Hops) {
if (node is Valve v) {
plant.CloseV(v.Nr);
}
}
plant.CommitChanges();
}
}
private void UpdateValvesAdjacientToPath(Path path, bool locked) {
private void UpdateValvesAdjacientToPath(Path path, bool locked, bool? wantOpen = null) {
foreach (var (edge, node) in path.Hops) {
TraverseSubgraph(node, valveAction: (v) => v.IsLocked = locked);
TraverseSubgraph(node, valveAction: (v) => {
v.IsLocked = locked;
if (wantOpen.HasValue) {
if (wantOpen.Value) {
App.Plant?.OpenV(v.Nr);
} else {
App.Plant?.CloseV(v.Nr);
}
}
});
}
}
public void ColorPipesAdjacientToPath(Path path, Brush? color1, Brush? color2) {
public void ColorPipesAdjacientToPath(Path path, Brush? color1, bool flowArrows, Brush? color2) {
var color = color1;
var flowPathOffset = 0.0;
HashSet<IEdge> visited = [];
foreach (var (edge, node) in path.Hops) {
edge.Highlight = color1;
edge.Flow = color1 == PamhagenBrushes.Green ? (edge.End == node, flowPathOffset) : null;
edge.Flow = flowArrows ? (edge.End == node, flowPathOffset) : null;
if (edge.Flow != null) flowPathOffset += edge.FlowLength;
visited.Add(edge);
if (node is Pump) color = color2;
+273 -17
View File
@@ -13,13 +13,19 @@ namespace PamhagenSysCtrl.Helpers {
protected bool ActuatorsChanged = false;
protected PamhagenPlc.ActuatorStates Actuators;
protected PamhagenPlc.SensorStates Sensors;
protected PamhagenPlc.SensorStates Sensors = new(default, default, default, default, [
FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown
], default);
public bool IsValveOpen(int n) => !IsValveClosed(n);
public bool IsValveClosed(int n) => Sensors.GetDS(n);
public bool WantValveClosed(int n) => !WantValveOpen(n);
public bool WantValveOpen(int n) => Actuators.GetV(n);
public bool AreValvesOpen(params int[] ns) => ns.All(IsValveOpen);
public bool AreValvesClosed(params int[] ns) => ns.All(IsValveClosed);
public int TroughSelector => Sensors.TroughSelector;
public bool IsA1Selected => Sensors.TroughSelector == 1;
public bool IsA2Selected => Sensors.TroughSelector == 2;
public FillState FillLevelA1 => Sensors.FillingLevels.A1;
@@ -38,6 +44,7 @@ namespace PamhagenSysCtrl.Helpers {
public FillState[] TankFillLevels => Sensors.FillingLevelTanks;
public double GradationOe => Sensors.GradationOe;
public MotorState PresseQuerSchnecke => Sensors.PresseQuerSchnecke;
public bool IsPresseQuerSchneckeActive => PresseQuerSchnecke == MotorState.Forward;
public bool WantA1Selected => Actuators.GetV(58);
public bool WantA2Selected => !Actuators.GetV(58);
@@ -52,14 +59,40 @@ namespace PamhagenSysCtrl.Helpers {
public bool IsWasteDisposalActive => IsBeltActive || IsAuger1Active || IsAuger2Active;
public bool IsGradationPumpActive => Actuators.GradationPump;
public bool IsMP1Active => Actuators.MP1 == MotorState.Forward || Actuators.MP1 == MotorState.Backward;
public bool IsMP2Active => Actuators.MP2 == MotorState.Forward || Actuators.MP2 == MotorState.Backward;
public bool IsP12Active => Actuators.P12 == MotorState.Forward;
public bool IsP3Active => Actuators.P3 == MotorState.Forward;
public bool IsP4Active => Actuators.P4 == MotorState.Forward;
public bool IsP5Active => Actuators.P5 == MotorState.Forward;
public bool IsP6Active => Actuators.P6 == MotorState.Forward;
public PamhagenPlant(string portName) {
Plc = new(portName);
Update += OnUpdate;
}
protected virtual void RaiseUpdateEvent(PlantEventArgs evt) {
App.MainDispatcher.BeginInvoke(() => Update?.Invoke(this, evt));
}
protected static void OnUpdate(object? sender, PlantEventArgs evt) {
if (sender is not PamhagenPlant p) return;
if (p.IsPresseQuerSchneckeActive && !p.IsBeltActive) p.StartBelt();
if (p.IsReblerActive && !p.IsAuger1Active) p.StartAuger1();
if (p.IsAuger1Active && !p.IsBeltActive) p.StartBelt();
if (p.IsBeltActive && !p.IsAuger2Active) p.StartAuger2();
if (p.IsTroughAugerActive && (!p.IsReblerActive || (p.IsA1Selected && p.FillLevelA1 == FillState.Full) || (p.IsA2Selected && p.FillLevelA2 == FillState.Full)))
p.StopTroughAuger();
if (p.IsMP1Active && !p.MP1HasClearance) p.StopMP1();
if (p.IsMP2Active && !p.MP2HasClearance) p.StopMP2();
if (p.IsP12Active && !p.P12HasClearance) p.StopP12();
if (p.IsP3Active && !p.P3HasClearance) p.StopP3();
if (p.IsP4Active && !p.P4HasClearance) p.StopP4();
if (p.IsP5Active && !p.P5HasClearance) p.StopP5();
if (p.IsP6Active && !p.P6HasClearance) p.StopP6();
}
public async Task StartThread() {
if (Plc == null) throw new Exception();
await Plc.TestConnection();
@@ -107,40 +140,222 @@ namespace PamhagenSysCtrl.Helpers {
}
}
public void CommitChanges() {
ActuatorsChanged = true;
}
protected bool HasWTClearanceAA =>
(AreValvesOpen(12) && AreValvesClosed(15, 16, 20)) || // bypass
(AreValvesOpen(15, 18, 16) && AreValvesClosed(11, 12, 14, 17, 19, 20)) || // WT1
(AreValvesOpen(15, 17, 20) && AreValvesClosed(11, 12, 18, 19, 21)) || // WT2
(AreValvesOpen(15, 18, 19, 20) && AreValvesClosed(11, 12, 14, 16, 17, 21)) || // WT1+WT2
false;
protected bool HasWTClearanceAB =>
(AreValvesOpen(15, 18, 14) && AreValvesClosed(11, 12, 13, 16, 17, 19, 21)) || // WT1
(AreValvesOpen(15, 17, 21) && AreValvesClosed(11, 12, 13, 18, 19, 20)) || // WT2
(AreValvesOpen(15, 18, 19, 21) && AreValvesClosed(11, 12, 13, 14, 16, 17, 20)) || // WT1+WT2
false;
protected bool HasWTClearanceBA =>
(AreValvesOpen(11, 18, 16) && AreValvesClosed(15, 12, 13, 14, 17, 19, 20)) || // WT1
(AreValvesOpen(11, 17, 20) && AreValvesClosed(15, 12, 13, 18, 19, 21)) || // WT2
(AreValvesOpen(11, 18, 19, 20) && AreValvesClosed(15, 12, 13, 14, 16, 17, 21)) || // WT1+WT2
false;
protected bool HasWTClearanceBB =>
(AreValvesOpen(13) && AreValvesClosed(11, 14, 21)) || // bypass
(AreValvesOpen(11, 18, 14) && AreValvesClosed(15, 13, 16, 17, 19, 21)) || // WT1
(AreValvesOpen(11, 17, 21) && AreValvesClosed(15, 13, 18, 19, 20)) || // WT2
(AreValvesOpen(11, 18, 19, 21) && AreValvesClosed(15, 13, 14, 16, 17, 20)) || // WT1+WT2
false;
protected bool HasT1ClearanceA => AreValvesOpen(22) && AreValvesClosed(24, 26, 28);
protected bool HasT1ClearanceB => AreValvesOpen(23) && AreValvesClosed(25, 27, 29);
protected bool HasT2ClearanceA => AreValvesOpen(24) && AreValvesClosed(22, 26, 28);
protected bool HasT2ClearanceB => AreValvesOpen(25) && AreValvesClosed(23, 27, 29);
protected bool HasT3ClearanceA => AreValvesOpen(26) && AreValvesClosed(22, 24, 28);
protected bool HasT3ClearanceB => AreValvesOpen(27) && AreValvesClosed(23, 25, 29);
protected bool HasT4ClearanceA => AreValvesOpen(28, 30) && AreValvesClosed(22, 24, 26, 32, 34);
protected bool HasT4ClearanceB => AreValvesOpen(29, 31) && AreValvesClosed(23, 25, 27, 33, 35);
protected bool HasT5ClearanceA => AreValvesOpen(28, 32) && AreValvesClosed(22, 24, 26, 30, 34);
protected bool HasT5ClearanceB => AreValvesOpen(29, 33) && AreValvesClosed(23, 25, 27, 31, 35);
protected bool HasT6ClearanceA => AreValvesOpen(28, 34, 37) && AreValvesClosed(22, 24, 26, 30, 32, 39, 41, 43);
protected bool HasT6ClearanceB => AreValvesOpen(29, 35, 36) && AreValvesClosed(23, 25, 27, 31, 33, 38, 40, 42);
protected bool HasT7ClearanceA => AreValvesOpen(28, 34, 39) && AreValvesClosed(22, 24, 26, 30, 32, 37, 41, 43);
protected bool HasT7ClearanceB => AreValvesOpen(29, 35, 38) && AreValvesClosed(23, 25, 27, 31, 33, 36, 40, 42);
protected bool HasT8ClearanceA => AreValvesOpen(28, 34, 41) && AreValvesClosed(22, 24, 26, 30, 32, 37, 39, 43);
protected bool HasT8ClearanceB => AreValvesOpen(29, 35, 40) && AreValvesClosed(23, 25, 27, 31, 33, 36, 38, 42);
protected bool HasT9ClearanceA => AreValvesOpen(28, 34, 43) && AreValvesClosed(22, 24, 26, 30, 32, 37, 39, 41);
protected bool HasT9ClearanceB => AreValvesOpen(29, 35, 42) && AreValvesClosed(23, 25, 27, 31, 33, 36, 38, 40);
protected bool HasClearanceTank1(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT1ClearanceA) || (HasWTClearanceAB && HasT1ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT1ClearanceA) || (HasWTClearanceBB && HasT1ClearanceB)));
protected bool HasClearanceTank2(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT2ClearanceA) || (HasWTClearanceAB && HasT2ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT2ClearanceA) || (HasWTClearanceBB && HasT2ClearanceB)));
protected bool HasClearanceTank3(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT3ClearanceA) || (HasWTClearanceAB && HasT3ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT3ClearanceA) || (HasWTClearanceBB && HasT3ClearanceB)));
protected bool HasClearanceTank4(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT4ClearanceA) || (HasWTClearanceAB && HasT4ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT4ClearanceA) || (HasWTClearanceBB && HasT4ClearanceB)));
protected bool HasClearanceTank5(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT5ClearanceA) || (HasWTClearanceAB && HasT5ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT5ClearanceA) || (HasWTClearanceBB && HasT5ClearanceB)));
protected bool HasClearanceTank6(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT6ClearanceA) || (HasWTClearanceAB && HasT6ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT6ClearanceA) || (HasWTClearanceBB && HasT6ClearanceB)));
protected bool HasClearanceTank7(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT7ClearanceA) || (HasWTClearanceAB && HasT7ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT7ClearanceA) || (HasWTClearanceBB && HasT7ClearanceB)));
protected bool HasClearanceTank8(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT8ClearanceA) || (HasWTClearanceAB && HasT8ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT8ClearanceA) || (HasWTClearanceBB && HasT8ClearanceB)));
protected bool HasClearanceTank9(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT9ClearanceA) || (HasWTClearanceAB && HasT9ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT9ClearanceA) || (HasWTClearanceBB && HasT9ClearanceB)));
public bool MP1HasClearance => FillLevelA1 != FillState.Empty && (
(MP1HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(MP1HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool MP1HasClearancePress1 =>
(AreValvesOpen(1, 6, 51) && AreValvesClosed(3, 4, 5, 55)) ||
(AreValvesOpen(4, 8, 52) && AreValvesClosed(1, 2, 7, 56));
protected bool MP1HasClearancePress2 =>
(AreValvesOpen(1, 6, 55) && AreValvesClosed(3, 4, 5, 51)) ||
(AreValvesOpen(4, 8, 56) && AreValvesClosed(1, 2, 7, 52));
protected bool MP1HasClearanceTanksA => AreValvesOpen(1, 5) && AreValvesClosed(3, 4, 6);
protected bool MP1HasClearanceTanksB => AreValvesOpen(4, 7, 9) && AreValvesClosed(1, 2, 8, 10);
public MotorState MP1 {
get => Actuators.MP1;
set => Actuators.MP1 = (value != MotorState.Halt && value != MotorState.Forward && value != MotorState.Backward) ? throw new ArgumentException("Invalid state for MP1") : value;
}
public bool MP2HasClearance => FillLevelA2 != FillState.Empty && (
(MP2HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(MP2HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool MP2HasClearancePress1 =>
(AreValvesOpen(2, 8, 52) && AreValvesClosed(3, 4, 7, 56)) ||
(AreValvesOpen(3, 6, 51) && AreValvesClosed(1, 2, 5, 55));
protected bool MP2HasClearancePress2 =>
(AreValvesOpen(2, 8, 56) && AreValvesClosed(3, 4, 7, 52)) ||
(AreValvesOpen(3, 6, 55) && AreValvesClosed(2, 1, 5, 51));
protected bool MP2HasClearanceTanksA => AreValvesOpen(3, 5) && AreValvesClosed(1, 2, 6);
protected bool MP2HasClearanceTanksB => AreValvesOpen(2, 7, 9) && AreValvesClosed(3, 4, 8, 10);
public MotorState MP2 {
get => Actuators.MP2;
set => Actuators.MP2 = (value != MotorState.Halt && value != MotorState.Forward && value != MotorState.Backward) ? throw new ArgumentException("Invalid state for MP2") : value;
}
public bool P12HasClearance => (FillLevelT1 != FillState.Empty || FillLevelT2 != FillState.Empty) && (
(P12HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P12HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P12HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P12HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P12HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P12HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P12HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P12HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P12HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P12HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P12HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P12HasClearancePress1 => AreValvesOpen(44, 46, 49, 50) && AreValvesClosed(10, 45, 47, 48, 54);
protected bool P12HasClearancePress2 => AreValvesOpen(44, 46, 49, 54) && AreValvesClosed(10, 45, 47, 48, 50);
protected bool P12HasClearanceTanksB => AreValvesOpen(44, 10) && AreValvesClosed(9, 45, 46);
public MotorState P12 {
get => Actuators.P12;
set => Actuators.P12 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P12") : value;
}
public bool P3HasClearance => FillLevelT3 != FillState.Empty && (
(P3HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P3HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P3HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P3HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P3HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P3HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P3HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P3HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P3HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P3HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P3HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P3HasClearancePress1 => AreValvesOpen(45, 46, 49, 50) && AreValvesClosed(10, 44, 47, 48, 54);
protected bool P3HasClearancePress2 => AreValvesOpen(45, 46, 49, 54) && AreValvesClosed(10, 44, 47, 48, 50);
protected bool P3HasClearanceTanksB => AreValvesOpen(45, 10) && AreValvesClosed(9, 44, 46);
public MotorState P3 {
get => Actuators.P3;
set => Actuators.P3 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P3") : value;
}
public bool P4HasClearance => FillLevelT4 != FillState.Empty && (
(P4HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P4HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P4HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P4HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P4HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P4HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P4HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P4HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P4HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P4HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P4HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P4HasClearancePress1 => AreValvesOpen(47, 49, 50) && AreValvesClosed(46, 48, 54);
protected bool P4HasClearancePress2 => AreValvesOpen(47, 49, 54) && AreValvesClosed(46, 48, 50);
protected bool P4HasClearanceTanksB => AreValvesOpen(47, 46, 10) && AreValvesClosed(9, 44, 45, 48, 49);
public MotorState P4 {
get => Actuators.P4;
set => Actuators.P4 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P4") : value;
}
public bool P5HasClearance => FillLevelT5 != FillState.Empty && (
(P5HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P5HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P5HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P5HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P5HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P5HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P5HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P5HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P5HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P5HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P5HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P5HasClearancePress1 => AreValvesOpen(48, 49, 50) && AreValvesClosed(46, 47, 54);
protected bool P5HasClearancePress2 => AreValvesOpen(48, 49, 54) && AreValvesClosed(46, 47, 50);
protected bool P5HasClearanceTanksB => AreValvesOpen(48, 46, 10) && AreValvesClosed(9, 44, 45, 47, 49);
public MotorState P5 {
get => Actuators.P5;
set => Actuators.P5 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P5") : value;
}
public bool P6HasClearance =>
(IsValveOpen(53) && IsValveClosed(57) && FillLevelPress1 != FillState.Full) ||
(IsValveOpen(57) && IsValveClosed(53) && FillLevelPress2 != FillState.Full);
public MotorState P6 {
get => Actuators.P6;
set => Actuators.P6 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P6") : value;
@@ -153,157 +368,198 @@ namespace PamhagenSysCtrl.Helpers {
protected void SetV(int n, bool val) {
if (n < 1 || n > 57) throw new ArgumentException("Invalid value for n: 1 <= #V <= 57");
Actuators.SetV(n, val);
ActuatorsChanged = true;
}
public void SelectA1() {
Actuators.SetV(58, true);
//if (IsReblerActive) Actuators.StirrerA1 = true;
ActuatorsChanged = true;
}
public void SelectA2() {
Actuators.SetV(58, false);
//if (IsReblerActive) Actuators.StirrerA2 = true;
ActuatorsChanged = true;
}
public void StartTroughAuger() {
if (!IsReblerActive || (IsA1Selected && FillLevelA1 == FillState.Full) || (IsA2Selected && FillLevelA2 == FillState.Full))
throw new NoClearanceException("Schnecke Auffangwanne hat keine Freigabe");
Actuators.TroughAuger = true;
ActuatorsChanged = true;
}
public void StopTroughAuger() {
Actuators.TroughAuger = false;
ActuatorsChanged = true;
}
public void StartRebler() {
Actuators.Rebler = true;
StartAuger1();
ActuatorsChanged = true;
}
public void StopRebler() {
StopTroughAuger();
Actuators.Rebler = false;
ActuatorsChanged = true;
}
public void StartStirrerA1() {
Actuators.StirrerA1 = true;
ActuatorsChanged = true;
}
public void StopStirrerA1() {
Actuators.StirrerA1 = false;
ActuatorsChanged = true;
}
public void StartStirrerA2() {
Actuators.StirrerA2 = true;
ActuatorsChanged = true;
}
public void StopStirrerA2() {
Actuators.StirrerA2 = false;
ActuatorsChanged = true;
}
public void StartBelt() {
Actuators.Belt = true;
StartAuger2();
ActuatorsChanged = true;
}
public void StopBelt() {
if (IsPresseQuerSchneckeActive) throw new NoClearanceException("Presse-Querschnecke aktiv");
if (IsAuger1Active) throw new NoClearanceException("Förderschnecke 1 aktiv");
Actuators.Belt = false;
ActuatorsChanged = true;
}
public void StartAuger1() {
Actuators.Auger1 = true;
StartBelt();
ActuatorsChanged = true;
}
public void StopAuger1() {
if (IsReblerActive) throw new NoClearanceException("Rebler aktiv");
Actuators.Auger1 = false;
ActuatorsChanged = true;
}
public void StartAuger2() {
Actuators.Auger2 = true;
ActuatorsChanged = true;
}
public void StopAuger2() {
if (IsBeltActive) throw new NoClearanceException("Förderband aktiv");
Actuators.Auger2 = false;
}
public void StartWasteDisposal() {
StartBelt();
StartAuger1();
StartAuger2();
}
public void StopWasteDisposal() {
StopBelt();
StopAuger1();
StopAuger2();
ActuatorsChanged = true;
}
public void StartGradationPump() {
Actuators.GradationPump = true;
ActuatorsChanged = true;
}
public void StopGradationPump() {
Actuators.GradationPump = false;
ActuatorsChanged = true;
}
public void StartMP1Forward() {
if (!MP1HasClearance) throw new NoClearanceException("MP1 hat keine Freigabe");
Actuators.MP1 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StartMP1Backward() {
if (!MP1HasClearance) throw new NoClearanceException("MP1 hat keine Freigabe");
Actuators.MP1 = MotorState.Backward;
ActuatorsChanged = true;
}
public void StopMP1() {
Actuators.MP1 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartMP2Forward() {
if (!MP2HasClearance) throw new NoClearanceException("MP2 hat keine Freigabe");
Actuators.MP2 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StartMP2Backward() {
if (!MP2HasClearance) throw new NoClearanceException("MP2 hat keine Freigabe");
Actuators.MP2 = MotorState.Backward;
ActuatorsChanged = true;
}
public void StopMP2() {
Actuators.MP2 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP12() {
if (!P12HasClearance) throw new NoClearanceException("P1/2 hat keine Freigabe");
Actuators.P12 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP12() {
Actuators.P12 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP3() {
if (!P3HasClearance) throw new NoClearanceException("P3 hat keine Freigabe");
Actuators.P3 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP3() {
Actuators.P3 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP4() {
if (!P4HasClearance) throw new NoClearanceException("P4 hat keine Freigabe");
Actuators.P4 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP4() {
Actuators.P4 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP5() {
if (!P5HasClearance) throw new NoClearanceException("P5 hat keine Freigabe");
Actuators.P5 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP5() {
Actuators.P5 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP6() {
if (!P6HasClearance) throw new NoClearanceException("P6 hat keine Freigabe");
Actuators.P6 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP6() {
Actuators.P6 = MotorState.Halt;
ActuatorsChanged = true;
}
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public double Height { get; set; }
public double Angle { get; set; }
public bool IsActive {
public bool IsAnimationActive {
set {
if (value) {
_storyboard?.Resume();
@@ -2,13 +2,12 @@
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
namespace PamhagenSysCtrl.Helpers.Pipeline {
public class ConveyorBelt : INode {
public const double WIDTH = 35;
public const double WIDTH = 30;
public const double HEIGHT = 120;
public double CenterX { get; set; }
@@ -17,10 +16,11 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive {
get => _active;
public bool IsActive => CallbackActive();
public bool IsAnimationActive {
get => _animationActive;
set {
_active = value;
_animationActive = value;
if (value) {
_storyboard?.Resume();
} else {
@@ -29,15 +29,18 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
}
private bool _active;
protected Func<bool> CallbackActive;
private bool _animationActive;
private Shape? _rect;
private Polyline? _polyline;
private Storyboard? _storyboard;
public ConveyorBelt(string label, double x, double y) {
public ConveyorBelt(string label, double x, double y, Func<bool> cbActive) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -54,7 +57,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
_rect.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2);
_rect.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2);
var d = 20;
var d = 15;
int n = (int)(HEIGHT / d) + 2;
_polyline = new Polyline() {
Points = [.. Enumerable.Range(0, n).SelectMany(i => new List<Point>() {
@@ -77,12 +80,12 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
Storyboard.SetTarget(slideUp, _polyline);
Storyboard.SetTargetProperty(slideUp, new PropertyPath(Canvas.TopProperty));
var clipCanvas = new Canvas() {
Width = WIDTH - 20,
Height = HEIGHT - 2,
Width = WIDTH - 15,
Height = HEIGHT - 8,
ClipToBounds = true,
};
clipCanvas.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2 + 2);
clipCanvas.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2 + 10);
clipCanvas.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2 + 4);
clipCanvas.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2 + 7.5);
clipCanvas.Children.Add(_polyline);
canvas.Children.Add(_rect);
@@ -97,12 +100,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPressed) {
IsAnimationActive = IsActive;
_rect?.Fill =
IsActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsActive && isHovering ? PamhagenBrushes.Red :
!IsActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsActive && isHovering ? PamhagenBrushes.Green :
IsActive ? PamhagenBrushes.Green :
IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsAnimationActive && isHovering ? PamhagenBrushes.Red :
!IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsAnimationActive && isHovering ? PamhagenBrushes.Green :
IsAnimationActive ? PamhagenBrushes.Green :
Brushes.WhiteSmoke;
}
}
@@ -16,25 +16,31 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive {
get => _active;
public bool IsClickable { get; private set; }
public bool IsActive => CallbackActive();
public bool IsAnimationActive {
get => _animationActive;
set {
_active = value;
_auger?.IsActive = value;
_animationActive = value;
_auger?.IsAnimationActive = value;
}
}
private bool _active;
protected Func<bool> CallbackActive;
private bool _animationActive;
private Shape? _inner;
private Shape? _outer;
private Auger? _auger;
private TextBlock? _text;
public EncasedAuger(string label, double x, double y, double angle = 0) {
public EncasedAuger(string label, double x, double y, Func<bool> cbActive, double angle = 0, bool clickable = true) {
CenterX = x;
CenterY = y;
Label = label;
Angle = angle;
CallbackActive = cbActive;
IsClickable = clickable;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -80,12 +86,14 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPressed) {
isHovering = isHovering && IsClickable;
IsAnimationActive = IsActive;
_inner?.Fill =
IsActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsActive && isHovering ? PamhagenBrushes.Red :
!IsActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsActive && isHovering ? PamhagenBrushes.Green :
IsActive ? PamhagenBrushes.Green :
IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsAnimationActive && isHovering ? PamhagenBrushes.Red :
!IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsAnimationActive && isHovering ? PamhagenBrushes.Green :
IsAnimationActive ? PamhagenBrushes.Green :
Brushes.WhiteSmoke;
}
}
+16 -11
View File
@@ -16,11 +16,12 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive {
get => _active;
public bool IsActive => CallbackActive();
public bool IsAnimationActive {
get => _animationActive;
set {
_active = value;
_auger?.IsActive = value;
_animationActive = value;
_auger?.IsAnimationActive = value;
if (value) {
_doorTransform?.BeginAnimation(
RotateTransform.AngleProperty,
@@ -41,7 +42,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
}
private bool _active;
protected Func<bool> CallbackActive;
private bool _animationActive;
private Shape? _inner;
private Shape? _outer;
private TextBlock? _text;
@@ -49,10 +52,11 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
private Shape? _door;
private RotateTransform? _doorTransform;
public EntryTrough(string label, double x, double y) {
public EntryTrough(string label, double x, double y, Func<bool> cbActive) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -99,12 +103,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPressed) {
IsAnimationActive = IsActive;
_inner?.Fill =
IsActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsActive && isHovering ? PamhagenBrushes.Red :
!IsActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsActive && isHovering ? PamhagenBrushes.Green :
IsActive ? PamhagenBrushes.Green :
IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsAnimationActive && isHovering ? PamhagenBrushes.Red :
!IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsAnimationActive && isHovering ? PamhagenBrushes.Green :
IsAnimationActive ? PamhagenBrushes.Green :
Brushes.WhiteSmoke;
}
}
@@ -1,155 +0,0 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace PamhagenSysCtrl.Helpers.Pipeline {
internal sealed class FlowArrow {
private const double Speed = 45;
private const double Spacing = 40;
private const double HalfLength = 5;
private const double HalfWidth = 3.5;
private static readonly Stopwatch Clock = Stopwatch.StartNew();
private readonly Canvas _layer;
private readonly Point[] _path;
private Point[] _points = [];
private double _length;
private double _pathOffset;
private bool _isActive;
public double Length => GetLength(_path[0], _path[1]) + GetLength(_path[1], _path[2]);
private FlowArrow(Canvas canvas, Point[] path) {
_path = path;
_layer = new Canvas() {
IsHitTestVisible = false,
Visibility = Visibility.Collapsed,
};
_layer.Unloaded += (_, _) => Stop();
canvas.Children.Add(_layer);
}
public static FlowArrow Create(Canvas canvas, Line first, Line second) {
return new FlowArrow(canvas, [
new Point(first.X1, first.Y1),
new Point(first.X2, first.Y2),
new Point(second.X2, second.Y2),
]);
}
public static FlowArrow Create(Canvas canvas, Polyline path) {
return new FlowArrow(canvas, [.. path.Points]);
}
public void Update((bool TowardEnd, double PathOffset)? flow) {
if (flow == null) {
Stop();
return;
}
var points = flow.Value.TowardEnd
? _path
: [.. _path.Reverse()];
var length = GetLength(points[0], points[1]) + GetLength(points[1], points[2]);
if (length < 16) {
Stop();
return;
}
_points = points;
_length = length;
_pathOffset = flow.Value.PathOffset;
if (!_isActive) {
CompositionTarget.Rendering += OnRendering;
_isActive = true;
}
_layer.Visibility = Visibility.Visible;
Render();
}
private void OnRendering(object? sender, EventArgs args) {
Render();
}
private void Render() {
var distance = PositiveModulo(Clock.Elapsed.TotalSeconds * Speed - _pathOffset, Spacing);
var arrowIndex = 0;
while (distance <= _length) {
var arrow = GetArrow(arrowIndex++);
SetPosition(arrow, distance);
arrow.Visibility = Visibility.Visible;
distance += Spacing;
}
while (arrowIndex < _layer.Children.Count) {
_layer.Children[arrowIndex++].Visibility = Visibility.Collapsed;
}
}
private Polygon GetArrow(int index) {
if (index < _layer.Children.Count) {
return (Polygon)_layer.Children[index];
}
var arrow = new Polygon() {
Fill = Brushes.Black,
IsHitTestVisible = false,
Points = [
new Point(HalfLength, 0),
new Point(-HalfLength, HalfWidth),
new Point(-HalfLength, -HalfWidth),
],
RenderTransform = new MatrixTransform(Matrix.Identity),
};
_layer.Children.Add(arrow);
return arrow;
}
private void SetPosition(Polygon arrow, double distance) {
var firstLength = GetLength(_points[0], _points[1]);
var secondLength = GetLength(_points[1], _points[2]);
Point start;
Point end;
double segmentDistance;
if ((firstLength > 0 && distance <= firstLength) || secondLength == 0) {
start = _points[0];
end = _points[1];
segmentDistance = distance;
} else {
start = _points[1];
end = _points[2];
segmentDistance = distance - firstLength;
}
var segmentLength = GetLength(start, end);
if (segmentLength == 0) return;
var ux = (end.X - start.X) / segmentLength;
var uy = (end.Y - start.Y) / segmentLength;
var x = start.X + ux * segmentDistance;
var y = start.Y + uy * segmentDistance;
((MatrixTransform)arrow.RenderTransform).Matrix = new Matrix(
ux, uy, -uy, ux, x, y);
}
private void Stop() {
if (_isActive) {
CompositionTarget.Rendering -= OnRendering;
_isActive = false;
}
_layer.Visibility = Visibility.Collapsed;
}
private static double PositiveModulo(double value, double modulus) {
return (value % modulus + modulus) % modulus;
}
private static double GetLength(Point start, Point end) {
var dx = end.X - start.X;
var dy = end.Y - start.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
}
}
@@ -0,0 +1,173 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace PamhagenSysCtrl.Helpers.Pipeline {
internal sealed class FlowArrows {
public const double SPEED = 20;
public const double SPACING = 15;
public const double LENGTH = 7;
public const double WIDTH = 7;
private static readonly Stopwatch Clock = Stopwatch.StartNew();
private readonly Canvas _layer;
private readonly Point[] _path;
private Point[] _points = [];
private double _length;
private double _pathOffset;
private bool _isActive;
public double Length => GetLength(_path[0], _path[1]) + GetLength(_path[1], _path[2]);
private FlowArrows(Canvas canvas, Point[] path) {
_path = path;
_layer = new Canvas() {
IsHitTestVisible = false,
Visibility = Visibility.Collapsed,
};
_layer.Unloaded += (_, _) => Stop();
canvas.Children.Add(_layer);
}
public static FlowArrows Create(Canvas canvas, Line first, Line second) {
return new FlowArrows(canvas, [
new Point(first.X1, first.Y1),
new Point(first.X2, first.Y2),
new Point(second.X2, second.Y2),
]);
}
public static FlowArrows Create(Canvas canvas, Polyline path) {
return new FlowArrows(canvas, [.. path.Points]);
}
public void Update((bool TowardEnd, double PathOffset)? flow) {
if (flow == null) {
Stop();
return;
}
_points = flow.Value.TowardEnd ? _path : [.. _path.Reverse()];
_length = GetLength(_points[0], _points[1]) + GetLength(_points[1], _points[2]);
_pathOffset = flow.Value.PathOffset;
if (!_isActive) {
CompositionTarget.Rendering += OnRendering;
_isActive = true;
}
_layer.Visibility = Visibility.Visible;
Render();
}
private void OnRendering(object? sender, EventArgs args) {
Render();
}
private void Render() {
var distance = ((Clock.Elapsed.TotalSeconds * SPEED - _pathOffset) % SPACING + SPACING) % SPACING;
var arrowIndex = 0;
while (distance <= _length) {
var arrow = GetArrow(arrowIndex++);
SetPosition(arrow, distance);
arrow.Visibility = Visibility.Visible;
distance += SPACING;
}
while (arrowIndex < _layer.Children.Count) {
_layer.Children[arrowIndex++].Visibility = Visibility.Collapsed;
}
}
private Polygon GetArrow(int index) {
if (index < _layer.Children.Count) {
return (Polygon)_layer.Children[index];
}
var arrow = new Polygon() {
Fill = new SolidColorBrush(Color.FromArgb(0x60, 0, 0, 0)),
IsHitTestVisible = false,
Points = [
new(-LENGTH / 2, -WIDTH / 2),
new(0, -WIDTH / 2),
new(LENGTH / 2, 0),
new(0, WIDTH / 2),
new(-LENGTH / 2, WIDTH / 2),
new(0, 0),
],
RenderTransform = new MatrixTransform(Matrix.Identity),
};
_layer.Children.Add(arrow);
return arrow;
}
private void SetPosition(Polygon arrow, double distance) {
const double blendDistance = WIDTH / 2;
double firstLength = GetLength(_points[0], _points[1]);
double blendStartDistance = firstLength - blendDistance;
double blendEndDistance = firstLength + blendDistance;
Vector v1 = Normalize(_points[0], _points[1]);
Vector v2 = Normalize(_points[1], _points[2]);
Point blendStart = _points[1] - v1 * blendDistance;
Point blendEnd = _points[1] + v2 * blendDistance;
Point position;
Vector direction;
if (distance < blendStartDistance) {
position = _points[0] + v1 * distance;
direction = v1;
} else if (distance <= blendEndDistance) {
double t = (distance - blendStartDistance) / (blendEndDistance - blendStartDistance);
double u = 1.0 - t;
position = new Point(
u * u * blendStart.X +
2 * u * t * _points[1].X +
t * t * blendEnd.X,
u * u * blendStart.Y +
2 * u * t * _points[1].Y +
t * t * blendEnd.Y);
direction = new Vector(
2 * u * (_points[1].X - blendStart.X) +
2 * t * (blendEnd.X - _points[1].X),
2 * u * (_points[1].Y - blendStart.Y) +
2 * t * (blendEnd.Y - _points[1].Y));
direction.Normalize();
} else {
double d = distance - firstLength;
position = _points[1] + v2 * d;
direction = v2;
}
double ux = direction.X;
double uy = direction.Y;
(arrow.RenderTransform as MatrixTransform)?.Matrix = new Matrix(ux, uy, -uy, ux, position.X, position.Y);
}
private void Stop() {
if (_isActive) {
CompositionTarget.Rendering -= OnRendering;
_isActive = false;
}
_layer.Visibility = Visibility.Collapsed;
}
private static double GetLength(Point start, Point end) {
var dx = end.X - start.X;
var dy = end.Y - start.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
private static Vector Normalize(Point p1, Point p2) {
Vector v = p2 - p1;
if (v.Length > 0) v.Normalize();
return v;
}
}
}
+4 -4
View File
@@ -12,13 +12,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public bool Orientation { get; set; }
public Brush? Highlight { get; set; }
public (bool TowardEnd, double PathOffset)? Flow { get; set; }
public double FlowLength => _flowArrow?.Length ?? 0;
public double FlowLength => _flowArrows?.Length ?? 0;
private Line? _outer1;
private Line? _outer2;
private Line? _inner1;
private Line? _inner2;
private FlowArrow? _flowArrow;
private FlowArrows? _flowArrows;
public Inlet(INode start, ISink end, bool orientation = false) {
Start = start;
@@ -77,13 +77,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
canvas.Children.Add(_outer2);
canvas.Children.Add(_inner1);
canvas.Children.Add(_inner2);
_flowArrow = FlowArrow.Create(canvas, _inner1!, _inner2!);
_flowArrows = FlowArrows.Create(canvas, _inner1!, _inner2!);
}
public void Update() {
_inner1?.Stroke = Highlight ?? Brushes.DarkGray;
_inner2?.Stroke = Highlight ?? Brushes.DarkGray;
_flowArrow?.Update(Highlight == PamhagenBrushes.Green ? Flow : null);
_flowArrows?.Update(Flow);
}
}
}
+9 -9
View File
@@ -14,10 +14,10 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public bool Orientation { get; set; }
public Brush? Highlight { get; set; }
public (bool TowardEnd, double PathOffset)? Flow { get; set; }
public double FlowLength => _flowArrow?.Length ?? 0;
public double FlowLength => _flowArrows?.Length ?? 0;
private Polygon? _hopper;
private FlowArrow? _flowArrow;
private FlowArrows? _flowArrows;
private Line? _outer1;
private Line? _outer2;
private Line? _inner1;
@@ -49,7 +49,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
Y2 = y2,
StrokeThickness = 10,
Stroke = Brushes.Black,
StrokeStartLineCap = PenLineCap.Flat,
StrokeStartLineCap = PenLineCap.Round,
StrokeEndLineCap = PenLineCap.Round,
};
_inner1 = new Line() {
@@ -59,7 +59,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
Y2 = y2,
StrokeThickness = 6,
Stroke = Brushes.DarkGray,
StrokeStartLineCap = PenLineCap.Flat,
StrokeStartLineCap = PenLineCap.Round,
StrokeEndLineCap = PenLineCap.Round,
};
_outer2 = new Line() {
@@ -79,22 +79,22 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
Y2 = y3,
StrokeThickness = 6,
Stroke = Brushes.DarkGray,
StrokeStartLineCap = PenLineCap.Square,
StrokeEndLineCap = PenLineCap.Square,
StrokeStartLineCap = PenLineCap.Round,
StrokeEndLineCap = PenLineCap.Round,
};
canvas.Children.Add(_outer1);
canvas.Children.Add(_outer2);
canvas.Children.Add(_hopper);
canvas.Children.Add(_inner1);
canvas.Children.Add(_inner2);
_flowArrow = FlowArrow.Create(canvas, _inner1!, _inner2!);
canvas.Children.Add(_hopper);
_flowArrows = FlowArrows.Create(canvas, _inner1!, _inner2!);
}
public void Update() {
_inner1?.Stroke = Highlight ?? Brushes.DarkGray;
_inner2?.Stroke = Highlight ?? Brushes.DarkGray;
_hopper?.Fill = Highlight ?? Brushes.DarkGray;
_flowArrow?.Update(Highlight == PamhagenBrushes.Green ? Flow : null);
_flowArrows?.Update(Flow);
}
}
}
+4 -4
View File
@@ -11,11 +11,11 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public bool Orientation { get; set; }
public Brush? Highlight { get; set; }
public (bool TowardEnd, double PathOffset)? Flow { get; set; }
public double FlowLength => _flowArrow?.Length ?? 0;
public double FlowLength => _flowArrows?.Length ?? 0;
private Polyline? _outer;
private Polyline? _inner;
private FlowArrow? _flowArrow;
private FlowArrows? _flowArrows;
public Pipe(INode start, INode end, bool orientation = false, bool twoWay = false) {
Start = start;
@@ -49,12 +49,12 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
};
canvas.Children.Add(_outer);
canvas.Children.Add(_inner);
_flowArrow = FlowArrow.Create(canvas, _inner);
_flowArrows = FlowArrows.Create(canvas, _inner);
}
public void Update() {
_inner?.Stroke = Highlight ?? Brushes.DarkGray;
_flowArrow?.Update(Highlight == PamhagenBrushes.Green ? Flow : null);
_flowArrows?.Update(Flow);
}
}
}
+20 -2
View File
@@ -15,14 +15,26 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public Brush? Highlight { get; set; }
public bool IsActive => CallbackActive();
public bool HasClearance => CallbackClearance();
public bool IsSelected => CallbackSelected(this);
protected Func<bool> CallbackActive;
protected Func<bool> CallbackClearance;
protected Func<Pump, bool> CallbackSelected;
private Shape? _circle;
private Shape? _triangle;
private TextBlock? _text;
public Pump(string label, double x, double y) {
public Pump(string label, double x, double y, Func<bool> cbActive, Func<bool> cbClearance, Func<Pump, bool> cbSelected) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
CallbackClearance = cbClearance;
CallbackSelected = cbSelected;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -63,7 +75,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPresed) {
_circle?.Fill = isHovering ? Brushes.LightGray : Brushes.WhiteSmoke;
_circle?.Fill = Highlight ?? (
IsActive && isHovering ? PamhagenBrushes.Red :
IsActive ? PamhagenBrushes.Green :
HasClearance && IsSelected && isHovering ? PamhagenBrushes.Green :
HasClearance && IsSelected ? PamhagenBrushes.Yellow :
IsSelected ? PamhagenBrushes.Red :
isHovering ? Brushes.LightGray : Brushes.WhiteSmoke);
}
}
}
+5 -2
View File
@@ -15,7 +15,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive { get; set; }
public bool IsActive => CallbackActive();
protected Func<bool> CallbackActive;
private TextBlock? _text;
private Shape? _rect;
@@ -24,10 +26,11 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
private Shape? _bottomInner;
private Shape? _bottomOuter;
public Rebler(string label, double x, double y) {
public Rebler(string label, double x, double y, Func<bool> cbActive) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -0,0 +1,87 @@
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace PamhagenSysCtrl.Helpers.Pipeline {
public class Switcher : INode {
public const double WIDTH = 100;
public const double HEIGHT = 50;
public double CenterX { get; set; }
public double CenterY { get; set; }
public string Label { get; set; }
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
private Line? _main;
private Line? _shadow;
private RotateTransform? _mainTransform;
private RotateTransform? _shadowTransform;
protected Func<int> CallbackIsPosition;
protected Func<int> CallbackWantPosition;
public Switcher(string label, double x, double y, Func<int> cbIsPosition, Func<int> cbWantPosition) {
CenterX = x;
CenterY = y;
Label = label;
CallbackIsPosition = cbIsPosition;
CallbackWantPosition = cbWantPosition;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
public void Draw(Canvas canvas) {
_mainTransform = new RotateTransform(0, CenterX, CenterY);
_shadowTransform = new RotateTransform(0, CenterX, CenterY);
_main = new Line() {
X1 = CenterX - WIDTH / 2, Y1 = CenterY,
X2 = CenterX + WIDTH / 2, Y2 = CenterY,
StrokeThickness = 5,
Stroke = Brushes.Black,
StrokeStartLineCap = PenLineCap.Square,
StrokeEndLineCap = PenLineCap.Square,
RenderTransform = _mainTransform,
};
_shadow = new Line() {
X1 = CenterX - WIDTH / 2, Y1 = CenterY,
X2 = CenterX + WIDTH / 2, Y2 = CenterY,
StrokeThickness = 5,
Stroke = Brushes.DarkGray,
StrokeStartLineCap = PenLineCap.Square,
StrokeEndLineCap = PenLineCap.Square,
RenderTransform = _shadowTransform,
};
canvas.Children.Add(_shadow);
canvas.Children.Add(_main);
}
public bool IsInside(double x, double y) {
return Math.Abs(x - CenterX) <= WIDTH / 2 && Math.Abs(y - CenterY) <= HEIGHT / 2;
}
public void Update(bool isHovering, bool isPressed) {
var isPos = CallbackIsPosition();
var wantPos = CallbackWantPosition();
if (isHovering && wantPos == isPos) wantPos = wantPos == 1 ? 2 : 1;
var target1 = isPos == 0 ? 0 : isPos == 1 ? 15 : -15;
var target2 = wantPos == 0 ? 0 : wantPos == 1 ? 15 : -15;
_mainTransform?.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation {
From = _mainTransform.Angle,
To = target1,
Duration = TimeSpan.FromSeconds(Math.Abs(_mainTransform.Angle - target1) / 120.0)
});
_shadowTransform?.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation {
From = _shadowTransform.Angle,
To = target2,
Duration = TimeSpan.FromSeconds(Math.Abs(_shadowTransform.Angle - target2) / 120.0)
});
}
}
}
+2 -1
View File
@@ -7,10 +7,11 @@
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>App.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.IO.Ports" Version="10.0.9" />
<PackageReference Include="System.IO.Ports" Version="10.0.9" />
</ItemGroup>
</Project>
+8 -8
View File
@@ -61,31 +61,31 @@
Margin="135,115,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="GradationPumpButton_Click"/>
<Button x:Name="MP1ForwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
<Button x:Name="MP1BackwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP1ForwardButton_Click"/>
Click="MP1BackwardButton_Click"/>
<Button x:Name="MP1HaltButton" Content="MP1" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="350,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP1HaltButton_Click"/>
<Button x:Name="MP1BackwardButton" Content="Vor" Padding="2" Height="30" Width="60"
<Button x:Name="MP1ForwardButton" Content="Vor" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="410,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP1BackwardButton_Click"/>
Click="MP1ForwardButton_Click"/>
<Button x:Name="MP2ForwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
<Button x:Name="MP2BackwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP2ForwardButton_Click"/>
Click="MP2BackwardButton_Click"/>
<Button x:Name="MP2HaltButton" Content="MP2" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="350,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP2HaltButton_Click"/>
<Button x:Name="MP2BackwardButton" Content="Vor" Padding="2" Height="30" Width="60"
<Button x:Name="MP2ForwardButton" Content="Vor" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="410,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP2BackwardButton_Click"/>
Click="MP2ForwardButton_Click"/>
<Button x:Name="P12Button" Content="Pumpe 1/2" Padding="2" Height="30" Width="180"
FontSize="14" BorderThickness="2" FontWeight="Bold"
+7 -17
View File
@@ -28,14 +28,19 @@ namespace PamhagenSysCtrl {
b.Click += (sender, evt) => {
if (App.Plant == null || sender is not Button b) return;
var i = int.Parse($"{b.Content}"[1..]);
if (i > 57) {
if (i == 58) {
if (App.Plant.WantA1Selected) {
App.Plant.SelectA2();
} else {
App.Plant.SelectA1();
}
} else if (i > 57) {
return;
} else if (App.Plant.WantValveOpen(i)) {
App.Plant.CloseV(i);
} else {
App.Plant.OpenV(i);
}
App.Plant.CommitChanges();
};
ValvePanel.Children.Add(b);
}
@@ -155,7 +160,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartTroughAuger();
}
App.Plant.CommitChanges();
}
private void ReblerButton_Click(object? sender, RoutedEventArgs? evt) {
@@ -165,7 +169,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartRebler();
}
App.Plant.CommitChanges();
}
private void StirrerA1Button_Click(object? sender, RoutedEventArgs? evt) {
@@ -175,7 +178,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartStirrerA1();
}
App.Plant.CommitChanges();
}
private void StirrerA2Button_Click(object? sender, RoutedEventArgs? evt) {
@@ -185,7 +187,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartStirrerA2();
}
App.Plant.CommitChanges();
}
private void BeltButton_Click(object? sender, RoutedEventArgs? evt) {
@@ -195,7 +196,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartBelt();
}
App.Plant.CommitChanges();
}
private void Auger1Button_Click(object? sender, RoutedEventArgs? evt) {
@@ -205,7 +205,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartAuger1();
}
App.Plant.CommitChanges();
}
private void Auger2Button_Click(object? sender, RoutedEventArgs? evt) {
@@ -215,7 +214,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartAuger2();
}
App.Plant.CommitChanges();
}
private void GradationPumpButton_Click(object? sender, RoutedEventArgs? evt) {
@@ -225,44 +223,37 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartGradationPump();
}
App.Plant.CommitChanges();
}
private void MP1BackwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP1Backward();
App.Plant.CommitChanges();
}
private void MP1HaltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StopMP1();
App.Plant.CommitChanges();
}
private void MP1ForwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP1Forward();
App.Plant.CommitChanges();
}
private void MP2BackwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP2Backward();
App.Plant.CommitChanges();
}
private void MP2HaltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StopMP2();
App.Plant.CommitChanges();
}
private void MP2ForwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP2Forward();
App.Plant.CommitChanges();
}
private void P12Button_Click(object? sender, RoutedEventArgs? evt) {
@@ -272,7 +263,6 @@ namespace PamhagenSysCtrl {
} else {
App.Plant.StartP12();
}
App.Plant.CommitChanges();
}
}
}
+117 -22
View File
@@ -11,6 +11,8 @@ namespace PamhagenSysCtrl.Windows {
private ISource? _lastSource;
private List<INode> _path = [];
private ISet<INode>? _lastSelected;
private ISet<INode>? _hover;
private bool _mouseDown;
public PlantSchemeWindow() {
InitializeComponent();
@@ -39,7 +41,9 @@ namespace PamhagenSysCtrl.Windows {
foreach (var c in clicked) {
if (_lastSource == null && Graph.SelectedPaths.Any(p => p.Start == c)) {
var path = Graph.SelectedPaths.First(p => p.Start == c);
Graph.RemovePath(path);
if (!path.Hops.Any(h => (h.Node as Pump)?.IsActive ?? false)) {
Graph.RemovePath(path);
}
} else if (_lastSource != null && c is ISink sink) {
var res = Graph.GetPath([_lastSource, .._path, sink], (n) => n is not ISink && (n is not Valve v || !v.IsLocked));
if (res is Path path) {
@@ -57,14 +61,92 @@ namespace PamhagenSysCtrl.Windows {
} else {
_lastSource = null;
}
if (c is EntryTrough trough) {
trough.IsActive = !trough.IsActive;
} else if (c is Rebler rebler) {
rebler.IsActive = !rebler.IsActive;
} else if (c is EncasedAuger auger) {
auger.IsActive = !auger.IsActive;
} else if (c is ConveyorBelt belt) {
belt.IsActive = !belt.IsActive;
try {
if (c is EntryTrough trough) {
if (trough.IsActive) {
App.Plant?.StopTroughAuger();
} else {
App.Plant?.StartTroughAuger();
}
} else if (c is Rebler rebler) {
if (rebler.IsActive) {
App.Plant?.StopRebler();
} else {
App.Plant?.StartRebler();
}
} else if (c is Switcher switcher) {
if (App.Plant?.WantA1Selected ?? false) {
App.Plant?.SelectA2();
} else {
App.Plant?.SelectA1();
}
} else if (c is EncasedAuger auger) {
if (auger == Graph.Auger1) {
if (auger.IsActive) {
App.Plant?.StopAuger1();
} else {
App.Plant?.StartAuger1();
}
} else if (auger == Graph.Auger2) {
if (auger.IsActive) {
App.Plant?.StopAuger2();
} else {
App.Plant?.StartAuger2();
}
}
} else if (c is ConveyorBelt belt) {
if (belt.IsActive) {
App.Plant?.StopBelt();
} else {
App.Plant?.StartBelt();
}
} else if (c is Pump pump) {
if (pump == Graph.MP1) {
if (pump.IsActive) {
App.Plant?.StopMP1();
} else {
App.Plant?.StartMP1Forward();
}
} else if (pump == Graph.MP2) {
if (pump.IsActive) {
App.Plant?.StopMP2();
} else {
App.Plant?.StartMP2Forward();
}
} else if (pump == Graph.P12) {
if (pump.IsActive) {
App.Plant?.StopP12();
} else {
App.Plant?.StartP12();
}
} else if (pump == Graph.P3) {
if (pump.IsActive) {
App.Plant?.StopP3();
} else {
App.Plant?.StartP3();
}
} else if (pump == Graph.P4) {
if (pump.IsActive) {
App.Plant?.StopP4();
} else {
App.Plant?.StartP4();
}
} else if (pump == Graph.P5) {
if (pump.IsActive) {
App.Plant?.StopP5();
} else {
App.Plant?.StartP5();
}
} else if (pump == Graph.P6) {
if (pump.IsActive) {
App.Plant?.StopP6();
} else {
App.Plant?.StartP6();
}
}
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
UpdateScheme(pos, evt.LeftButton == MouseButtonState.Pressed);
@@ -75,37 +157,50 @@ namespace PamhagenSysCtrl.Windows {
e.Highlight = null;
e.Flow = null;
}
foreach (var p in Graph.SelectedPaths) {
Graph.ColorPipesAdjacientToPath(p, PamhagenBrushes.Green, PamhagenBrushes.DimOrange);
foreach (var n in Graph.Nodes) {
if (n is Pump p) {
p.Highlight = null;
}
}
var hover = Graph.GetHover(pos.X, pos.Y);
if (_lastSource != null && (hover.Count > 0 || _path.Count > 0)) {
foreach (var p in Graph.SelectedPaths) {
Graph.ColorPipesAdjacientToPath(p, PamhagenBrushes.Green, p.Hops.Any(h => (h.Node as Pump)?.IsActive ?? false), PamhagenBrushes.DimOrange);
}
_hover = Graph.GetHover(pos.X, pos.Y);
_mouseDown = down;
if (_lastSource != null && (_hover.Count > 0 || _path.Count > 0)) {
List<INode> points = [_lastSource, .. _path];
if (hover.Count > 0 && !points.Contains(hover.First())) {
points.Add(hover.First());
if (_hover.Count > 0 && !points.Contains(_hover.First())) {
points.Add(_hover.First());
}
if (points.Count >= 2) {
var res = Graph.GetPath(points, (n) => n is not ISink && (n is not Valve v || !v.IsLocked));
if (res is Path path) {
Graph.ColorPipesAdjacientToPath(path, PamhagenBrushes.Green, PamhagenBrushes.DimOrange);
Graph.ColorPipesAdjacientToPath(path, PamhagenBrushes.Green, false, PamhagenBrushes.DimOrange);
}
}
} else if (_lastSource == null && hover.Count > 0 && Graph.SelectedPaths.Any(p => p.Start == hover.First())) {
var path = Graph.SelectedPaths.First(p => p.Start == hover.First());
Graph.ColorPipesAdjacientToPath(path, PamhagenBrushes.Red, null);
} else if (_lastSource == null && _hover.Count > 0 && Graph.SelectedPaths.Any(p => p.Start == _hover.First())) {
var path = Graph.SelectedPaths.First(p => p.Start == _hover.First());
var pumpActive = path.Hops.Any(h => (h.Node as Pump)?.IsActive ?? false);
if (pumpActive) {
foreach (var pump in path.Hops.Select(h => h.Node as Pump).Where(p => p != null)) {
pump?.Highlight = PamhagenBrushes.Red;
}
} else {
Graph.ColorPipesAdjacientToPath(path, PamhagenBrushes.Red, false, null);
}
}
if (_lastSource != null) {
foreach (var edge in _lastSource.Outputs) {
edge.Highlight = PamhagenBrushes.Green;
edge.Flow = (true, 0);
}
}
Graph.Update(hover, down);
return hover;
Graph.Update(_hover, down);
return _hover;
}
public void OnUpdate(object? sender, PlantEventArgs evt) {
if (sender is not PamhagenPlant plant) return;
UpdateScheme(Mouse.GetPosition(SchemeCanvas), Mouse.LeftButton == MouseButtonState.Pressed);
}
}
}