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
{
///
/// Interaction logic for BicoControl.xaml
///
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();
}
///
/// Atualiza cor da solenoide e visibilidade do leque.
///
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;
}
///
/// Recalcula geometria do leque e da linha central a partir do ângulo central e abertura.
///
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));
}
}