agrobot_base/AgroBase/OperationControl/Controls/Pulverizador/BicoLequeIndicator.xaml.cs

244 lines
8.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
using Brush = System.Windows.Media.Brush;
using Point = System.Windows.Point;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace OperationControl.Controls.Pulverizador
{
/// <summary>
/// Interaction logic for BicoControl.xaml
/// </summary>
public partial class BicoLequeIndicator : UserControl
{
public BicoLequeIndicator()
{
InitializeComponent();
Loaded += (s, e) => UpdateGeometry();
}
#region DependencyProperties básicas
// Comando enviado para a solenoide
public bool IsCommandOn
{
get => (bool)GetValue(IsCommandOnProperty);
set => SetValue(IsCommandOnProperty, value);
}
public static readonly DependencyProperty IsCommandOnProperty = DependencyProperty.Register(nameof(IsCommandOn), typeof(bool), typeof(BicoLequeIndicator), new PropertyMetadata(false, OnVisualPropertyChanged));
// Leitura de ligado (se está realmente pulverizando)
public bool IsSpraying
{
get => (bool)GetValue(IsSprayingProperty);
set => SetValue(IsSprayingProperty, value);
}
public static readonly DependencyProperty IsSprayingProperty = DependencyProperty.Register(nameof(IsSpraying), typeof(bool), typeof(BicoLequeIndicator), new PropertyMetadata(false, OnVisualPropertyChanged));
// Ângulo central do jato (0 = vertical; positivo gira p/ esquerda, negativo p/ direita)
public double AnguloControle
{
get => (double)GetValue(AnguloControleProperty);
set => SetValue(AnguloControleProperty, value);
}
public static readonly DependencyProperty AnguloControleProperty = DependencyProperty.Register(nameof(AnguloControle), typeof(double), typeof(BicoLequeIndicator), new PropertyMetadata(0.0, OnGeometryPropertyChanged));
// Abertura total do leque (em graus) – ex: 110°
public double OpeningAngle
{
get => (double)GetValue(OpeningAngleProperty);
set => SetValue(OpeningAngleProperty, value);
}
public static readonly DependencyProperty OpeningAngleProperty = DependencyProperty.Register(nameof(OpeningAngle), typeof(double), typeof(BicoLequeIndicator), new PropertyMetadata(110.0, OnGeometryPropertyChanged));
// Vazao instantanea (mL/s)
public double Vazao
{
get => (double)GetValue(VazaoProperty);
set => SetValue(VazaoProperty, value);
}
public static readonly DependencyProperty VazaoProperty = DependencyProperty.Register(nameof(Vazao), typeof(double), typeof(BicoLequeIndicator), new PropertyMetadata(0.0, OnGeometryPropertyChanged));
// Tempo atuado (s)
public double TempoAtuado
{
get => (double)GetValue(TempoAtuadoProperty);
set => SetValue(TempoAtuadoProperty, value);
}
public static readonly DependencyProperty TempoAtuadoProperty = DependencyProperty.Register(nameof(TempoAtuado), typeof(double), typeof(BicoLequeIndicator), new PropertyMetadata(0.0, OnGeometryPropertyChanged));
// Atuacoes
public int Atuacoes
{
get => (int)GetValue(AtuacoesProperty);
set => SetValue(AtuacoesProperty, value);
}
public static readonly DependencyProperty AtuacoesProperty = DependencyProperty.Register(nameof(Atuacoes), typeof(int), typeof(BicoLequeIndicator), new PropertyMetadata(0, OnGeometryPropertyChanged));
#endregion
private static void OnGeometryPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctrl = (BicoLequeIndicator)d;
ctrl.UpdateGeometry();
}
private static void OnVisualPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctrl = (BicoLequeIndicator)d;
ctrl.UpdateVisualState();
}
/// <summary>
/// Atualiza cor da solenoide e visibilidade do leque.
/// </summary>
private void UpdateVisualState()
{
if (SolenoidRect == null || SprayPolygon == null)
return;
var onBrush = (Brush)FindResource("CommandOnBrush");
var offBrush = (Brush)FindResource("CommandOffBrush");
SolenoidRect.Stroke = IsCommandOn ? onBrush : offBrush;
SprayPolygon.Visibility = IsSpraying && OpeningAngle > 0 ? Visibility.Visible : Visibility.Collapsed;
CenterLine.Visibility = IsSpraying ? Visibility.Visible : Visibility.Collapsed;
}
/// <summary>
/// Recalcula geometria do leque e da linha central a partir do ângulo central e abertura.
/// </summary>
private void UpdateGeometry()
{
if (DrawCanvas == null || SprayPolygon == null || CenterLine == null)
return;
double width = DrawCanvas.ActualWidth;
double height = DrawCanvas.ActualHeight;
if (width <= 0) width = 120;
if (height <= 0) height = 80;
// Origem do bico (ponto da solenoide)
double originX = width / 2.0;
double originY = 10.0; // um pouco abaixo do topo
double length = height - 10.0; // comprimento do jato até próximo do solo
// Metade da abertura em radianos
double halfAngleRad = OpeningAngle * 0.5 * Math.PI / 180.0;
// Deslocamento horizontal na base do leque
double dx = Math.Tan(halfAngleRad) * length;
// Pontos em sistema local (0,0 = bico; y para baixo)
Point apex = new Point(0, 0);
Point leftLocal = new Point(-dx, length);
Point rightLocal = new Point(dx, length);
Point centerLocal = new Point(0, length);
// Rotação pelo ângulo central (em radianos).
double theta = AnguloControle * Math.PI / 180.0;
double cos = Math.Cos(theta);
double sin = Math.Sin(theta);
Point Rot(Point p) => new Point(
p.X * cos - p.Y * sin,
p.X * sin + p.Y * cos);
Point apexR = Rot(apex);
Point leftR = Rot(leftLocal);
Point rightR = Rot(rightLocal);
Point centerR = Rot(centerLocal);
// Translada para as coordenadas do Canvas
apexR.Offset(originX, originY);
leftR.Offset(originX, originY);
rightR.Offset(originX, originY);
centerR.Offset(originX, originY);
// Atualiza Polygon do leque
var pts = new PointCollection { leftR, apexR, rightR };
SprayPolygon.Points = pts;
// Atualiza linha central do jato
CenterLine.X1 = apexR.X;
CenterLine.Y1 = apexR.Y;
CenterLine.X2 = centerR.X;
CenterLine.Y2 = centerR.Y;
// Reposiciona a solenoide exatamente na origem
Canvas.SetLeft(SolenoidRect, originX - SolenoidRect.Width / 2.0);
Canvas.SetTop(SolenoidRect, originY - SolenoidRect.Height / 2.0);
}
}
public class BicoModel : INotifyPropertyChanged
{
private int _index;
public int Index
{
get => _index;
set { _index = value; OnPropertyChanged(); }
}
private double _anguloControle;
public double AnguloControle
{
get => _anguloControle;
set { _anguloControle = value; OnPropertyChanged(); }
}
private double _openingAngle = 110;
public double OpeningAngle
{
get => _openingAngle;
set { _openingAngle = value; OnPropertyChanged(); }
}
private bool _isCommandOn;
public bool IsCommandOn
{
get => _isCommandOn;
set { _isCommandOn = value; OnPropertyChanged(); }
}
private bool _isSpraying;
public bool IsSpraying
{
get => _isSpraying;
set { _isSpraying = value; OnPropertyChanged(); }
}
private double _vazao;
public double Vazao
{
get => _vazao;
set { _vazao = value; OnPropertyChanged(); }
}
private double _tempoAtuado;
public double TempoAtuado
{
get => _tempoAtuado;
set { _tempoAtuado = value; OnPropertyChanged(); }
}
private int _atuacoes;
public int Atuacoes
{
get => _atuacoes;
set { _atuacoes = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}