Add switcher

This commit is contained in:
2026-08-04 23:56:32 +02:00
parent ec07d91631
commit d9c1b79563
7 changed files with 143 additions and 36 deletions
+9 -5
View File
@@ -16,6 +16,8 @@ namespace PamhagenSysCtrl.Helpers {
public readonly Pump P4; public readonly Pump P4;
public readonly Pump P5; public readonly Pump P5;
public readonly Pump P6; public readonly Pump P6;
public readonly EncasedAuger Auger1;
public readonly EncasedAuger Auger2;
public PamhagenGraph() { public PamhagenGraph() {
double mw2X = 180; double mw2X = 180;
@@ -48,16 +50,18 @@ namespace PamhagenSysCtrl.Helpers {
var trough = new EntryTrough("Auffangwanne", mw1X + 70, 100, () => App.Plant?.IsTroughAugerActive ?? false); var trough = new EntryTrough("Auffangwanne", mw1X + 70, 100, () => App.Plant?.IsTroughAugerActive ?? false);
Nodes.Add(trough); Nodes.Add(trough);
var auger1 = new EncasedAuger("", (mw1X + mw2X) / 2 - 100, 200, () => App.Plant?.IsAuger1Active ?? false); Auger1 = new EncasedAuger("", (mw1X + mw2X) / 2 - 100, 200, () => App.Plant?.IsAuger1Active ?? false);
var auger2 = new EncasedAuger("Pressen-\nQuerschnecke", 40, 200, () => App.Plant?.IsPresseQuerSchneckeActive ?? false, 180); var auger3 = new EncasedAuger("Pressen-\nQuerschnecke", 40, 200, () => App.Plant?.IsPresseQuerSchneckeActive ?? false, 180, clickable: false);
var auger3 = new EncasedAuger("", 120, 80, () => App.Plant?.IsAuger2Active ?? false, 135); Auger2 = new EncasedAuger("", 120, 80, () => App.Plant?.IsAuger2Active ?? false, 135);
var belt = new ConveyorBelt("", 90, 160, () => App.Plant?.IsBeltActive ?? false); var belt = new ConveyorBelt("", 90, 160, () => App.Plant?.IsBeltActive ?? false);
Nodes.Add(belt); Nodes.Add(belt);
Nodes.Add(auger1); Nodes.Add(Auger1);
Nodes.Add(auger2);
Nodes.Add(auger3); Nodes.Add(auger3);
Nodes.Add(Auger2);
var rebler = new Rebler("Rebler", (mw1X + mw2X) / 2, 200, () => App.Plant?.IsReblerActive ?? false); var rebler = new Rebler("Rebler", (mw1X + mw2X) / 2, 200, () => App.Plant?.IsReblerActive ?? false);
Nodes.Add(rebler); 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); MW1 = new Trough("MW1", mw1X, mpY - 70, () => App.Plant?.FillLevelA1 ?? FillState.Unknown);
MW2 = new Trough("MW2", mw2X, mpY - 70, () => App.Plant?.FillLevelA2 ?? FillState.Unknown); MW2 = new Trough("MW2", mw2X, mpY - 70, () => App.Plant?.FillLevelA2 ?? FillState.Unknown);
+10 -14
View File
@@ -25,6 +25,7 @@ namespace PamhagenSysCtrl.Helpers {
public bool AreValvesOpen(params int[] ns) => ns.All(IsValveOpen); public bool AreValvesOpen(params int[] ns) => ns.All(IsValveOpen);
public bool AreValvesClosed(params int[] ns) => ns.All(IsValveClosed); public bool AreValvesClosed(params int[] ns) => ns.All(IsValveClosed);
public int TroughSelector => Sensors.TroughSelector;
public bool IsA1Selected => Sensors.TroughSelector == 1; public bool IsA1Selected => Sensors.TroughSelector == 1;
public bool IsA2Selected => Sensors.TroughSelector == 2; public bool IsA2Selected => Sensors.TroughSelector == 2;
public FillState FillLevelA1 => Sensors.FillingLevels.A1; public FillState FillLevelA1 => Sensors.FillingLevels.A1;
@@ -329,7 +330,7 @@ namespace PamhagenSysCtrl.Helpers {
set => Actuators.P4 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P4") : value; set => Actuators.P4 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P4") : value;
} }
public bool P5HasClearance => FillLevelT4 != FillState.Empty && ( public bool P5HasClearance => FillLevelT5 != FillState.Empty && (
(P5HasClearancePress1 && FillLevelPress1 != FillState.Full) || (P5HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P5HasClearancePress2 && FillLevelPress2 != FillState.Full) || (P5HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P5HasClearanceTanksB) && FillLevelT1 != FillState.Full) || (HasClearanceTank1(false, P5HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
@@ -383,7 +384,7 @@ namespace PamhagenSysCtrl.Helpers {
} }
public void StartTroughAuger() { public void StartTroughAuger() {
if (!IsReblerActive || !((IsA1Selected && FillLevelA1 != FillState.Full) || (IsA2Selected && FillLevelA2 != FillState.Full))) if (!IsReblerActive || (IsA1Selected && FillLevelA1 == FillState.Full) || (IsA2Selected && FillLevelA2 == FillState.Full))
throw new NoClearanceException("Schnecke Auffangwanne hat keine Freigabe"); throw new NoClearanceException("Schnecke Auffangwanne hat keine Freigabe");
Actuators.TroughAuger = true; Actuators.TroughAuger = true;
ActuatorsChanged = true; ActuatorsChanged = true;
@@ -396,6 +397,7 @@ namespace PamhagenSysCtrl.Helpers {
public void StartRebler() { public void StartRebler() {
Actuators.Rebler = true; Actuators.Rebler = true;
StartAuger1();
ActuatorsChanged = true; ActuatorsChanged = true;
} }
@@ -427,20 +429,25 @@ namespace PamhagenSysCtrl.Helpers {
public void StartBelt() { public void StartBelt() {
Actuators.Belt = true; Actuators.Belt = true;
StartAuger2();
ActuatorsChanged = true; ActuatorsChanged = true;
} }
public void StopBelt() { public void StopBelt() {
if (IsPresseQuerSchneckeActive) throw new NoClearanceException("Presse-Querschnecke aktiv");
if (IsAuger1Active) throw new NoClearanceException("Förderschnecke 1 aktiv");
Actuators.Belt = false; Actuators.Belt = false;
ActuatorsChanged = true; ActuatorsChanged = true;
} }
public void StartAuger1() { public void StartAuger1() {
Actuators.Auger1 = true; Actuators.Auger1 = true;
StartBelt();
ActuatorsChanged = true; ActuatorsChanged = true;
} }
public void StopAuger1() { public void StopAuger1() {
if (IsReblerActive) throw new NoClearanceException("Rebler aktiv");
Actuators.Auger1 = false; Actuators.Auger1 = false;
ActuatorsChanged = true; ActuatorsChanged = true;
} }
@@ -451,22 +458,11 @@ namespace PamhagenSysCtrl.Helpers {
} }
public void StopAuger2() { public void StopAuger2() {
if (IsBeltActive) throw new NoClearanceException("Förderband aktiv");
Actuators.Auger2 = false; Actuators.Auger2 = false;
ActuatorsChanged = true; ActuatorsChanged = true;
} }
public void StartWasteDisposal() {
StartBelt();
StartAuger1();
StartAuger2();
}
public void StopWasteDisposal() {
StopBelt();
StopAuger1();
StopAuger2();
}
public void StartGradationPump() { public void StartGradationPump() {
Actuators.GradationPump = true; Actuators.GradationPump = true;
ActuatorsChanged = true; ActuatorsChanged = true;
@@ -2,13 +2,12 @@
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.Windows.Shapes; using System.Windows.Shapes;
namespace PamhagenSysCtrl.Helpers.Pipeline { namespace PamhagenSysCtrl.Helpers.Pipeline {
public class ConveyorBelt : INode { public class ConveyorBelt : INode {
public const double WIDTH = 35; public const double WIDTH = 30;
public const double HEIGHT = 120; public const double HEIGHT = 120;
public double CenterX { get; set; } public double CenterX { get; set; }
@@ -58,7 +57,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
_rect.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2); _rect.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2);
_rect.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2); _rect.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2);
var d = 20; var d = 15;
int n = (int)(HEIGHT / d) + 2; int n = (int)(HEIGHT / d) + 2;
_polyline = new Polyline() { _polyline = new Polyline() {
Points = [.. Enumerable.Range(0, n).SelectMany(i => new List<Point>() { Points = [.. Enumerable.Range(0, n).SelectMany(i => new List<Point>() {
@@ -81,12 +80,12 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
Storyboard.SetTarget(slideUp, _polyline); Storyboard.SetTarget(slideUp, _polyline);
Storyboard.SetTargetProperty(slideUp, new PropertyPath(Canvas.TopProperty)); Storyboard.SetTargetProperty(slideUp, new PropertyPath(Canvas.TopProperty));
var clipCanvas = new Canvas() { var clipCanvas = new Canvas() {
Width = WIDTH - 20, Width = WIDTH - 15,
Height = HEIGHT - 2, Height = HEIGHT - 8,
ClipToBounds = true, ClipToBounds = true,
}; };
clipCanvas.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2 + 2); clipCanvas.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2 + 4);
clipCanvas.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2 + 10); clipCanvas.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2 + 7.5);
clipCanvas.Children.Add(_polyline); clipCanvas.Children.Add(_polyline);
canvas.Children.Add(_rect); canvas.Children.Add(_rect);
@@ -16,6 +16,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; } public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; } public ISet<IEdge> Outputs { get; init; }
public bool IsClickable { get; private set; }
public bool IsActive => CallbackActive(); public bool IsActive => CallbackActive();
public bool IsAnimationActive { public bool IsAnimationActive {
get => _animationActive; get => _animationActive;
@@ -33,12 +34,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
private Auger? _auger; private Auger? _auger;
private TextBlock? _text; private TextBlock? _text;
public EncasedAuger(string label, double x, double y, Func<bool> cbActive, double angle = 0) { public EncasedAuger(string label, double x, double y, Func<bool> cbActive, double angle = 0, bool clickable = true) {
CenterX = x; CenterX = x;
CenterY = y; CenterY = y;
Label = label; Label = label;
Angle = angle; Angle = angle;
CallbackActive = cbActive; CallbackActive = cbActive;
IsClickable = clickable;
Inputs = new HashSet<IEdge>(); Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>(); Outputs = new HashSet<IEdge>();
} }
@@ -84,6 +86,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
} }
public void Update(bool isHovering, bool isPressed) { public void Update(bool isHovering, bool isPressed) {
isHovering = isHovering && IsClickable;
IsAnimationActive = IsActive; IsAnimationActive = IsActive;
_inner?.Fill = _inner?.Fill =
IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red : IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red :
@@ -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)
});
}
}
}
+8 -8
View File
@@ -61,31 +61,31 @@
Margin="135,115,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="135,115,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="GradationPumpButton_Click"/> 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" FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" 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" <Button x:Name="MP1HaltButton" Content="MP1" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold" FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="350,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="350,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP1HaltButton_Click"/> 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" FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="410,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" 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" FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" 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" <Button x:Name="MP2HaltButton" Content="MP2" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold" FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="350,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="350,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP2HaltButton_Click"/> 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" FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="410,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" 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" <Button x:Name="P12Button" Content="Pumpe 1/2" Padding="2" Height="30" Width="180"
FontSize="14" BorderThickness="2" FontWeight="Bold" FontSize="14" BorderThickness="2" FontWeight="Bold"
@@ -74,8 +74,26 @@ namespace PamhagenSysCtrl.Windows {
} else { } else {
App.Plant?.StartRebler(); 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) { } 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) { } else if (c is ConveyorBelt belt) {
if (belt.IsActive) { if (belt.IsActive) {
App.Plant?.StopBelt(); App.Plant?.StopBelt();