2025-11-12 11:15:07 +00:00
using System.Windows ;
using ScottPlot ; // Plot
using ScottPlot.Plottables ; // ISignal / IScatter
using System.Timers ;
using Colors = ScottPlot . Colors ; // Timer
using System.Windows.Threading ;
using OperationControl.Controls ;
2025-11-14 17:11:58 +00:00
using System.Diagnostics ;
using OperationControl.Models ;
using AgroBase.Models.Components ;
using OperationControl.Services ;
using System.Windows.Controls ;
using System.Runtime.CompilerServices ;
using System.Windows.Media ;
2025-11-12 11:15:07 +00:00
namespace OperationControl.Windows
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// buffers (X = tempo em segundos)
private readonly List < double > xs = new ( ) ;
private readonly List < double > ysCorr = new ( ) ; // Corrente (A)
private readonly List < double > ysVolt = new ( ) ; // Tensão (V)
private readonly List < double > ysTemp = new ( ) ; // Temperatura (°C)
private readonly List < double > ysRpm = new ( ) ; // RPM
private readonly System . Timers . Timer tmr = new ( 1000 ) { AutoReset = true } ; // 10 Hz
private double t = 0 ;
private readonly Random rng = new ( ) ;
DispatcherTimer _clock = new DispatcherTimer ( ) ;
Random _rand = new Random ( ) ;
public MainWindow ( )
{
InitializeComponent ( ) ;
2025-11-14 17:11:58 +00:00
AtualizarListaDispositivos ( new List < string > ( ) { VariaveisControleOperacao . SelectedRoverId } ) ;
2025-11-12 11:15:07 +00:00
// Título / eixos
Plot . Plot . Title ( "MOV ET – Corrente / Tensão / Temp / RPM (últimos 60s)" ) ;
Plot . Plot . Axes . Bottom . Label . Text = "Tempo (s)" ;
Plot . Plot . Axes . Left . Label . Text = "Unidades (A, V, °C, RPM)" ;
// inicializa com um ponto para cada série
PushSample ( initial : true ) ;
// legenda
Plot . Plot . ShowLegend ( Alignment . UpperRight ) ;
// loop
tmr . Elapsed + = ( _ , __ ) = > Dispatcher . Invoke ( ( ) = > PushSample ( ) ) ;
tmr . Start ( ) ;
DataContext = this ;
// atualizar as caixas
2025-11-14 17:11:58 +00:00
//BBoxes3D.SetBboxes(new[]
//{
// new AgroBase.Models.LivoxBboxModel{ cx=1.2, cy=0.5, cz=0.4, d=0.6, w=0.4, h=0.8 },
// new AgroBase.Models.LivoxBboxModel{ cx=3.0, cy=-0.7, cz=0.6, d=0.8, w=0.5, h=1.2 },
//});
2025-11-12 11:15:07 +00:00
}
private void PushSample ( bool initial = false )
{
// avança tempo
if ( ! initial ) t + = 1 ; // 10 Hz
xs . Add ( t ) ;
// ------- MOCK de dados plausíveis -------
// Corrente (A): 3– 12 A com ruído
double corr = 8 + 2 * Math . Sin ( t * 0.7 ) + ( rng . NextDouble ( ) - 0.5 ) ;
corr = Math . Clamp ( corr , 0 , 30 ) ;
// Tensão (V): 36– 42 V, ripple leve e queda lenta
double volt = 40.5 + 0.6 * Math . Sin ( t * 0.15 ) - 0.002 * t ;
volt = Math . Clamp ( volt , 30 , 42 ) ;
// Temperatura (°C): sobe devagar
double temp = 38 + 4 * Math . Sin ( t * 0.05 ) + 0.01 * t ;
temp = Math . Clamp ( temp , 20 , 85 ) ;
// RPM: 0– 1500 com variação
double rpm = 1100 + 200 * Math . Sin ( t * 0.9 ) + 80 * ( rng . NextDouble ( ) - 0.5 ) ;
rpm = Math . Clamp ( rpm , 0 , 2000 ) ;
ysCorr . Add ( corr ) ;
ysVolt . Add ( volt ) ;
ysTemp . Add ( temp ) ;
ysRpm . Add ( rpm ) ;
// mantém só últimos 60 s
while ( xs . Count > 0 & & xs [ ^ 1 ] - xs [ 0 ] > 60.0 )
{
xs . RemoveAt ( 0 ) ;
ysCorr . RemoveAt ( 0 ) ;
ysVolt . RemoveAt ( 0 ) ;
ysTemp . RemoveAt ( 0 ) ;
ysRpm . RemoveAt ( 0 ) ;
}
// redesenha (v5: passe arrays diretamente)
Plot . Plot . Clear ( ) ;
// Corrente (A)
var scCorr = Plot . Plot . Add . Scatter ( xs . ToArray ( ) , ysCorr . ToArray ( ) ) ;
scCorr . Label = "Corrente (A)" ;
scCorr . Color = ScottPlot . Colors . Cyan ;
scCorr . LineWidth = 2 ;
// Tensão (V)
var scVolt = Plot . Plot . Add . Scatter ( xs . ToArray ( ) , ysVolt . ToArray ( ) ) ;
scVolt . Label = "Tensão (V)" ;
scVolt . Color = ScottPlot . Colors . Lime ;
scVolt . LineWidth = 2 ;
// Temperatura (°C)
var scTemp = Plot . Plot . Add . Scatter ( xs . ToArray ( ) , ysTemp . ToArray ( ) ) ;
scTemp . Label = "Temp (°C)" ;
scTemp . Color = ScottPlot . Colors . Magenta ;
scTemp . LineWidth = 2 ;
// RPM
var scRpm = Plot . Plot . Add . Scatter ( xs . ToArray ( ) , ysRpm . ToArray ( ) ) ;
scRpm . Label = "RPM" ;
scRpm . Color = ScottPlot . Colors . Orange ;
scRpm . LineWidth = 2 ;
// janela de 60 s rolando
double xEnd = xs [ ^ 1 ] ;
double xStart = Math . Max ( 0 , xEnd - 60.0 ) ;
Plot . Plot . Axes . SetLimitsX ( xStart , xEnd ) ;
Plot . Plot . Axes . AutoScaleY ( ) ; // ajusta Y automaticamente para caber tudo
Plot . Refresh ( ) ;
}
2025-11-14 17:11:58 +00:00
#region DISPOSITIVOS
public void AtualizarListaDispositivos ( List < string > dispositivos )
{
cmbDispositivo . Items . Clear ( ) ;
foreach ( var d in dispositivos )
{
cmbDispositivo . Items . Add ( d ) ;
if ( ! MAP . markers . Added ( d ) )
{
if ( d = = VariaveisControleOperacao . BaseMarkerID )
{
MAP . markers . AddMarker (
d ,
Variaveis . GpsService ? . UltimaLeitura ? . Latitude ? ? 0 ,
Variaveis . GpsService ? . UltimaLeitura ? . Longitude ? ? 0 ,
Variaveis . GpsService ? . UltimaLeitura ? . OrientacaoReal ? ? 0 ,
MAP . markers . GetColorForMarker ( d , isBase : true ) ,
"Base"
) ;
}
else
{
var rover = VariaveisControleOperacao . RoversNaRede . FirstOrDefault ( x = > x . Key = = d ) ;
if ( rover . Value ! = null )
{
MAP . markers . AddMarker (
d ,
rover . Value . Gps ? . Latitude ? ? 0 ,
rover . Value . Gps ? . Longitude ? ? 0 ,
rover . Value . Gps ? . AnguloCarroDefinido ? ? 0 ,
MAP . markers . GetColorForMarker ( d , isBase : false ) ,
rover . Key
) ;
}
}
}
}
int idx_selected = dispositivos . IndexOf ( VariaveisControleOperacao . SelectedRoverId ) ;
if ( idx_selected > - 1 )
cmbDispositivo . SelectedIndex = idx_selected ;
}
private void cmbDispositivo_SelectionChanged ( object sender , System . Windows . Controls . SelectionChangedEventArgs e )
{
AtualizarDadosTela_Telemetria ( ( ( ComboBox ) sender ) . SelectedValue . ToString ( ) ) ;
}
public void LimparDadosTela_Telemetria ( )
{
VariaveisControleOperacao . SelectedRoverId = "" ;
}
public void AtualizarDadosTela_Telemetria ( string rover_id )
{
if ( rover_id ! = VariaveisControleOperacao . SelectedRoverId ) return ;
if ( rover_id = = VariaveisControleOperacao . BaseMarkerID )
{
Variaveis . MostrarLog ( $"Atualizando dados da tela para a base" ) ;
AtualizarDadosTela_GNSS ( Variaveis . GpsService ? . UltimaLeitura ? ? new AgroBase . Models . GPSModel ( ) ) ;
AtualizarDadosTela_Heading ( Variaveis . GpsService ? . UltimaLeitura ? . AnguloCarroDefinido ? ? 0 ) ;
}
else
{
var rover = VariaveisControleOperacao . RoversNaRede . FirstOrDefault ( x = > x . Key = = rover_id ) ;
if ( rover . Value = = null ) return ;
Variaveis . MostrarLog ( $"Atualizando dados da tela para o dispositivo {rover_id}" ) ;
AtualizarDadosTela_GNSS ( rover . Value . Gps ) ;
AtualizarDadosTela_Heading ( rover . Value . Gps . AnguloCarroDefinido , rover . Value . Modo = = AgroBase . Models . Enums . ModoOperacao . Manual ? double . NaN : rover . Value . Trajetoria . AnguloCaminho ) ;
AtualizarDadosTela_IMU ( rover . Value . IMU . InclinacaoLateral , rover . Value . IMU . InclinacaoFrontal ) ;
AtualizarDadostela_LIDAR ( rover . Value . LivoxLidar . bboxes ) ;
}
}
#endregion
#region IMU
public void AtualizarDadosTela_IMU ( double roll , double pitch )
{
IMU . RollDeg = roll ;
IMU . PitchDeg = pitch ;
}
#endregion
#region HEADING
public void AtualizarDadosTela_Heading ( double headingRover , double headingCourse = double . NaN )
{
HDG . Heading = headingRover ;
HDG . CourseHeading = headingCourse ;
}
#endregion
#region MAPA
private void MAP_MarkerClicked ( object? sender , MapMarkerManager . MarkerClickedEventArgs e )
{
Variaveis . MostrarLog ( $"Rover em foco: {e.MarkerId}" ) ;
if ( string . IsNullOrEmpty ( e . MarkerId ) )
{
LimparDadosTela_Telemetria ( ) ;
}
else
{
VariaveisControleOperacao . SelectedRoverId = e . MarkerId ;
AtualizarDadosTela_Telemetria ( e . MarkerId ) ;
}
}
private void MAP_StreetMapClicked ( object? sender , MapViewControl . StreetMapClickedEventArgs e )
{
Variaveis . MostrarLog ( $"Rua clicada: {e.StreetId}. Ruas selecionadas: {string.Join(" , ", e.SelectedStreetsIds)}" ) ;
}
#endregion
#region PULVERIZADOR
private void btnB0_Click ( object sender , RoutedEventArgs e )
{
btnB0 . Content = ( btnB0 . Content . ToString ( ) = = "Ligar" ) ? "Desligar" : "Ligar" ;
}
#endregion
#region POSICAO
public void AtualizarDadosTela_GNSS ( AgroBase . Models . GPSModel dados , string marker_id = null , double progresso = double . NaN )
{
lblGNSS_Posicao . Foreground = dados . Inicializado ? new SolidColorBrush ( System . Windows . Media . Colors . Green ) : new SolidColorBrush ( System . Windows . Media . Colors . Red ) ;
lblGNSS_Correcao . Content = $"Correção {dados.QualidadeFix} " +
( dados . QualidadeFix = = AgroBase . Models . Enums . TiposCorrecaoGPS . BaseFix ?
( dados . OrientacaoReal . ToString ( "0.00" ) + "°" ) :
( ( dados . Ntrip_ativado ? "N" : "B" ) + $" {dados.IdadeCorrecao.ToString(" 0.0 ")} s" ) ) ;
lblGNSS_Satelites . Content = $"Satélites {dados.NumeroSatelites} ({dados.PrecisaoCm.ToString(" 0.00 ")} cm)" ;
lblGNSS_Altitude . Content = $"Altitude {dados.Altitude.ToString(" 0.00 ")} m" ;
if ( double . IsNaN ( progresso ) )
{
lblGNSS_Progresso . Visibility = Visibility . Hidden ;
btnGNSS_FixarBase . Visibility = Visibility . Hidden ;
}
else
{
lblGNSS_Progresso . Visibility = Visibility . Visible ;
btnGNSS_FixarBase . Visibility = Visibility . Visible ;
lblGNSS_Progresso . Content = $"{progresso.ToString(" 0.00 ")}%" ;
if ( ( Variaveis . GpsService ? . BaseFix ? . CorrecaoAbsoluta ? ? false ) & & Variaveis . GpsService . BaseFix . FixLiberado & & btnGNSS_FixarBase . Content . ToString ( ) = = "Parar" )
{
Variaveis . GpsService . BaseFix . FixLiberado = false ;
btnGNSS_FixarBase . Content = "Fixar" ;
}
}
if ( ! string . IsNullOrEmpty ( marker_id ) )
MAP . markers . UpdateMarkerPosition ( marker_id , dados . Latitude , dados . Longitude , dados . OrientacaoReal ) ;
}
private void btnGNSS_FixarBase_Click ( object sender , RoutedEventArgs e )
{
if ( ! Variaveis . GpsService . BaseFix . FixLiberado )
{
if ( Variaveis . GpsService . BaseFix . CorrecaoAbsoluta )
{
var res = MessageBox . Show ( "Mudar posição da base?" , "Tem certeza que deseja fixar a posição da base novamente?" , MessageBoxButton . YesNo , MessageBoxImage . Question ) ;
if ( res = = MessageBoxResult . Yes )
{
btnGNSS_FixarBase . Content = "Parar" ;
Variaveis . GpsService . BaseFix . FixLiberado = true ;
Task . Run ( async ( ) = > await Variaveis . GpsService . ConfigurarModulo ( ) ) ;
}
}
else
{
btnGNSS_FixarBase . Content = "Parar" ;
Variaveis . GpsService . BaseFix . FixLiberado = true ;
}
}
else
{
btnGNSS_FixarBase . Content = "Fixar" ;
Variaveis . GpsService . BaseFix . FixLiberado = false ;
}
}
#endregion
#region LIDAR
public void AtualizarDadostela_LIDAR ( List < AgroBase . Models . LivoxBboxModel > bboxes )
{
BBoxes3D . SetBboxes ( bboxes ) ;
}
#endregion
2025-11-12 11:15:07 +00:00
}
}