agrobot_base/AgroBase/AgroBase/Forms/IHM/frmDialogoMapa.cs

926 lines
41 KiB
C#

using AgroBase.Models;
using AgroBase.Models.Components;
using AgroBase.Models.Operadores;
using AgroBase.Services;
using AgroBase.Services.Operadores;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using static AgroBase.Models.Enums;
namespace AgroBase.Forms.IHM
{
public partial class frmDialogoMapa : Form
{
AsyncTaskTimerModel tmrLeitura;
MapaDinamicoModel MapaDinamico;
private ulong CodigoFalha = 0;
private bool ReqFrameCam = false;
private bool ReqFrameSnr = false;
private bool _inRefresh;
private List<ModuloUIItem> _modulosUI = new List<ModuloUIItem>();
public frmDialogoMapa()
{
InitializeComponent();
// Ativa o double buffering
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
pnlJoystick.GetType().GetMethod("SetStyle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(pnlJoystick, new object[] { ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true });
pnlFreio.GetType().GetMethod("SetStyle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(pnlFreio, new object[] { ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true });
pnlCameraSolo0.GetType().GetMethod("SetStyle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(pnlCameraSolo0, new object[] { ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true });
pnlCameraCaminho.GetType().GetMethod("SetStyle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(pnlCameraCaminho, new object[] { ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true });
pnlCameraCaminhoSeg.GetType().GetMethod("SetStyle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(pnlCameraCaminhoSeg, new object[] { ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true });
cmbModoControle.Items.Clear();
cmbModoControle.Items.AddRange(Enum.GetNames(typeof(Enums.TipoMovimentoDirecional)));
cmbModoControle.SelectedIndexChanged += CmbModoControle_SelectedIndexChanged;
pnlCameraSolo0.BackgroundImageLayout = ImageLayout.Zoom;
pnlCameraCaminho.BackgroundImageLayout = ImageLayout.Zoom;
pnlCameraCaminhoSeg.BackgroundImageLayout = ImageLayout.Zoom;
clbModulos.DrawMode = DrawMode.OwnerDrawFixed; // habilita owner-draw
clbModulos.ItemHeight = Math.Max(clbModulos.ItemHeight, 20);
clbModulos.DrawItem += clbModulos_DrawItem;
clbModulos.ItemCheck += clbModulos_ItemCheck;
clbModulos.SelectedIndexChanged += clbModulos_SelectedIndexChanged;
AtualizarElementosModoManual();
MapaDinamico = new MapaDinamicoModel(this, pnlMapaDinamico);
FuncoesGlobais.DefinirEventosPicBtn(picFechar, "", async () =>
{
if (Variaveis.OperacaoEmAndamento.Iniciado && !Variaveis.OperacaoEmAndamento.Finalizando)
{
var res = CustomDialog.ShowDialog(
"Interromper Operação",
"Tem certeza que deseja interromper a operação em andamento?",
MessageBoxIcon.Question,
new Dictionary<(string, DialogResult?), Action>()
{
{ ("Sim", DialogResult.Yes), () => { } },
{ ("Não", DialogResult.No), () => { } },
}
);
if (res == DialogResult.Yes)
{
Task.Run(async () => await Variaveis.OperacaoEmAndamento.FinalizarOperacao());
if (Variaveis.OperacaoEmAndamento.Parametros?.Modo == Enums.ModoOperacao.Manual)
{
this.Close();
}
}
}
else
{
if (Variaveis.OperacaoEmAndamento.StatusAtual == Enums.StatusOperacao.Parametrizando)
{
this.Hide();
}
else
{
this.Close();
}
}
});
}
private void frmDialogoMapa_Load(object sender, EventArgs e)
{
tmrLeitura?.Dispose();
tmrLeitura = new AsyncTaskTimerModel("tmrLeitura", tmrLeitura_Tick, 500, this);
tmrLeitura.Start();
if (Variaveis.OperacaoEmAndamento.Mapa.pnlMapa == null)
{
Variaveis.OperacaoEmAndamento.Mapa = new MapasModel()
{
pnlMapa = pnlMapa,
lblMapa = lblMapaCarregado
};
Variaveis.OperacaoEmAndamento.Mapa.CarregarMapaGPS();
}
}
private void frmDialogoMapa_FormClosing(object sender, FormClosingEventArgs e)
{
tmrLeitura?.Dispose();
}
public async Task AtualizarRuasSelecionadas(List<string> ruasSelecionadas)
{
await Task.Delay(1000);
GPSService.AtualizarRuasSelecionadas(ruasSelecionadas);
}
public void IniciarOperacao()
{
Task.Run(async () => {
await Variaveis.OperacaoEmAndamento.IniciarOperacao();
//InicializarModoManual();
});
}
public void AtualizarMapaDinamico()
{
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria;
if (_Trajetoria != null && _Trajetoria.CorredorAtual != null)
{
MapaDinamico.AtualizarDados(
null,
(float)_Trajetoria.AnguloCaminho,
(float)_Sensoriamento.Gps.AnguloCarroDefinido,
_Sensoriamento.Gps,
_Trajetoria._TrajetoriaDinamica,
_Trajetoria.CorredorAtual.Pontos,
Variaveis.OperacaoEmAndamento.GPSTrajetoria,
_Trajetoria.RuasPlantacao,
_Sensoriamento.Controle.SimulacaoMPC
);
}
}
private async Task tmrLeitura_Tick()
{
pnlOrientacao.Invalidate();
pnlInclinacao.Invalidate();
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
lblUltimaLeituraSolo.Text = "Última Leitura Solo: " + _Sensoriamento.OperadorErvas.UltimaMensagem.ToString("HH:mm:ss.fff");
lblUltimaLeituraCaminho.Text = "Última Leitura Caminho: " + _Sensoriamento.OperadorVisual.UltimaMensagem.ToString("HH:mm:ss.fff");
lblPerformance.Text = _Sensoriamento.DadosPerformance.PerformanceStr;
lblMapaCarregado.Text = "Operação: " + Variaveis.OperacaoEmAndamento.Descricao;
txtModoOperacao.Text = (Variaveis.OperacaoEmAndamento.Parametros?.Modo ?? ModoOperacao.NaoDefinido).ToString();
bool opLiberada = _Sensoriamento.OperacaoLiberada;
txtOperacaoLiberada.Text = opLiberada ? "Sim" : "Não";
txtOperacaoLiberada.ForeColor = opLiberada ? Color.Black : Color.Red;
btnCodFalha.Text = CodigoFalha.ToString("0.000");
txtStatusAtual.Text = _Sensoriamento.StatusOperacao.ToString();
txtIniciadoEm.Text = _Sensoriamento.DataInicio == DateTime.MinValue ? "Aguardando" : _Sensoriamento.DataInicio.ToString("dd/MM HH:mm:ss");
txtConcluidoEm.Text = _Sensoriamento.DataFim == DateTime.MinValue ? "-" : _Sensoriamento.DataFim.ToString("dd/MM HH:mm:ss");
txtDistanciaPercorrida.Text = _Sensoriamento.Trajetoria.DistanciaPercorrida.ToString("0.00") + " m";
txtTempoOperacao.Text = _Sensoriamento.TempoDecorrido.ToString("HH:mm:ss");
txtLatenciaControle.Text = _Sensoriamento.Controle.Latencia.ToString();
txtHerbicidaAplicado.Text = _Sensoriamento.Atuador.HerbicidaConsumido.ToString("0.000") + " L";
txtBateriaConsumida.Text = _Sensoriamento.Bateria.PercentualBateriaConsumida.ToString("0.00") + " %";
FuncoesGlobais.PreencheValorProgressBar(pgbReservatorio, _Sensoriamento.Atuador.PercentualReservatorio);
lblReservatorio.Text = "Reservatório: " + _Sensoriamento.Atuador.VolumeReservatorio.ToString("0.00") + " l " + _Sensoriamento.Atuador.PercentualReservatorio.ToString("0.00") + "%";
FuncoesGlobais.PreencheValorProgressBar(pgbBateria, _Sensoriamento.Bateria.PercentualBateria);
lblBateria.Text = "Bateria: " + _Sensoriamento.Bateria.TensaoInstantanea.ToString("0.00") + "v " + _Sensoriamento.Bateria.PercentualBateria.ToString("0.00") + "%";
FuncoesGlobais.PreencheValorProgressBar(pgbOperacao, _Sensoriamento.Trajetoria.ProgressoTrajeto);
lblOperacao.Text = "Operação: " + _Sensoriamento.Trajetoria.ProgressoTrajeto.ToString("0.00") + "%";
FuncoesGlobais.PreencheValorProgressBar(pgbRuaAtual, _Sensoriamento.Trajetoria.CorredorAtual.Progresso);
lblRuaAtual.Text = "Rua Atual: " + _Sensoriamento.Trajetoria.CorredorAtual.Progresso.ToString("0.00") + "%";
lblCorrecaoGPS.Text = (_Sensoriamento.Gps.Ntrip_ativado ? "N " : "B ") + _Sensoriamento.Gps.IdadeCorrecao + ": " + _Sensoriamento.Gps.QualidadeFix.ToString();
lblPrecisaoGPS.Text = $"Precisão: {_Sensoriamento.Gps.PrecisaoCm.ToString("0.00")} cm";
bool automatico = Variaveis.OperacaoEmAndamento.Parametros?.ControleAutomatico ?? false;
cmbModoControle.Enabled = !automatico;
tkbVelocidade.Enabled = !automatico;
tkbAnguloDirecional.Enabled = !automatico;
pnlFreio.Enabled = !automatico;
if (automatico)
{
cmbModoControle.SelectedIndex = (int)_Sensoriamento.Controle.TipoMovimento;
tkbVelocidade.Value = Convert.ToInt32(_Sensoriamento.Controle.PercentualVelocidadeSP);
tkbAnguloDirecional.Minimum = 0;
tkbAnguloDirecional.Maximum = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo);
tkbAnguloDirecional.Value = Math.Abs(Convert.ToInt32(_Sensoriamento.Controle.Angulo));
}
txtDistanciasEsqDir.Text = _Sensoriamento.Trajetoria.DistanciaEsquerda.ToString("0.00") + " / " + _Sensoriamento.Trajetoria.DistanciaDireita.ToString("0.00") + " (" + _Sensoriamento.Controle.ErroLateral.ToString("0.00" + ")");
txtDentroCorredor.Text = _Sensoriamento.Trajetoria.CorredorAtual.Dentro ? "Sim" : "Não";
txtMargemCorredor.Text = _Sensoriamento.Trajetoria.NaMargemDoCorredor ? "Sim" : "Não";
txtStatusCarro.Text = _Sensoriamento.Trajetoria.StatusCarro.ToString();
txtInclinacao.Text = _Sensoriamento.IMU.RollSeguro.ToString("0.00") + "/" + _Sensoriamento.IMU.PitchSeguro.ToString("0.00");
var ModET = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.Modulo_ID == "ET");
txtET.Text = (ModET?.MovMotor?.Corrente_Motor ?? 0).ToString("0.00");
lblET.ForeColor = (ModET?.Conectado ?? false) ? Color.Green : Color.Red;
var ModDT = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.Modulo_ID == "DT");
txtDT.Text = (ModDT?.MovMotor?.Corrente_Motor ?? 0).ToString("0.00");
lblDT.ForeColor = (ModDT?.Conectado ?? false) ? Color.Green : Color.Red;
var ModEF = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.Modulo_ID == "EF");
txtEF.Text = (ModEF?.MovMotor?.Corrente_Motor ?? 0).ToString("0.00");
lblEF.ForeColor = (ModEF?.Conectado ?? false) ? Color.Green : Color.Red;
var ModDF = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.Modulo_ID == "DF");
txtDF.Text = (ModDF?.MovMotor?.Corrente_Motor ?? 0).ToString("0.00");
lblDF.ForeColor = (ModDF?.Conectado ?? false) ? Color.Green : Color.Red;
if (!Variaveis.Producao)
{
AtualizarMapaDinamico();
}
if (!ReqFrameCam)
_ = AtualizarCameraSolo();
if (!ReqFrameSnr)
_ = AtualizarCameraCaminho();
AtualizarListaModulos();
}
private async Task AtualizarCameraSolo()
{
ReqFrameCam = true;
try
{
var frame = await WeedWorkerService.GetCameraFrame(TipoFrameCamera.Rgb);
AtualizarImagemPainel(pnlCameraSolo0, frame?.image());
}
finally
{
ReqFrameCam = false;
}
}
private async Task AtualizarCameraCaminho()
{
ReqFrameSnr = true;
try
{
var frameRgb = await VisualWorkerService.GetCameraFrame(TipoFrameCamera.Rgb);
AtualizarImagemPainel(pnlCameraCaminho, frameRgb?.image());
var frameSeg = await VisualWorkerService.GetCameraFrame(TipoFrameCamera.Segmentacao);
AtualizarImagemPainel(pnlCameraCaminhoSeg, frameSeg?.image());
}
finally
{
ReqFrameSnr = false;
}
}
private void AtualizarImagemPainel(Panel panel, Image novaImagem)
{
if (panel.InvokeRequired)
{
panel.BeginInvoke(new Action(() => AtualizarImagemPainel(panel, novaImagem)));
return;
}
panel.BackgroundImage?.Dispose();
panel.BackgroundImage = novaImagem;
}
private void pnlOrientacao_Paint(object sender, PaintEventArgs e)
{
try
{
double angulo = Variaveis.OperacaoEmAndamento.Sensoriamento?.Gps?.AnguloCarroDefinido ?? 0;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)(Variaveis.OperacaoEmAndamento.Sensoriamento?.Trajetoria?.AnguloCaminho ?? 0));
}
catch { }
}
private void pnlInclinacao_Paint(object sender, PaintEventArgs e)
{
try
{
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)(Variaveis.OperacaoEmAndamento.Controle.Angulo), 90);
}
catch { }
}
#region MODO MANUAL
private Point joystickCenter;
private bool isDragging = false;
private Keys prevMovKey = Keys.None;
private Keys prevDirKey = Keys.None;
private int joystickRadius;
private Point joystickPosition;
private Point freioPosition;
private Point freioStartPosition;
private bool isDraggingFreio = false;
private bool isBrakeLocked = false;
private void AtualizarElementosModoManual()
{
cmbModoControle.Enabled = false;
tkbAnguloDirecional.Enabled = false;
tkbVelocidade.Enabled = false;
pnlJoystick.Visible = false;
tabControl1.TabPages.Remove(tabControle);
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
cmbModoControle.SelectedIndex = (int)_Controle.TipoMovimento;
chbFrenagemAutomatica.Checked = pControle.FrenagemAutomaticaAoParar;
nudVelSemErvas.Value = (int)pControle.MovVelocidadeSErvasPercent;
nudVelComErvas.Value = (int)pControle.MovVelocidadeCErvasPercent;
chbPulverizadorAutomatico.Checked = pControle.PulverizadorAutomatico;
nudPercentualAtuacaoBico.Value = (int)pControle.AtuPercentualInicioPulverizacao;
nudPressaoLinha.Value = (int)pControle.AtuPressaoLinha;
FuncoesGlobais.PreencheValorTrackBar(tkbAnguloDirecional, _Controle.Angulo);
FuncoesGlobais.PreencheValorTrackBar(tkbVelocidade, _Controle.PercentualVelocidadeSP);
string pesosMpcStr = RedisService.Get(CtxKey.DadosPesosMPC);
var pesos = JsonConvert.DeserializeObject<MPCPesosModel>(pesosMpcStr);
txtPesoPosicao.Text = pesos.posicao.ToString();
txtPesoOrientacao.Text = pesos.orientacao.ToString();
txtPesoSuavidadeMin.Text = pesos.suavidade_min.ToString();
txtPesoSuavidadeMax.Text = pesos.suavidade_max.ToString();
txtPesoFatorRe.Text = pesos.fator_re.ToString();
txtPesoIdeal.Text = pesos.ideal.ToString();
txtPesoLateralMin.Text = pesos.lateral_min.ToString();
txtPesoLateralMax.Text = pesos.lateral_max.ToString();
tkbVelocidade_Scroll(null, null);
tkbAnguloDirecional_Scroll(null, null);
}
public void InicializarModoManual()
{
AtualizarElementosModoManual();
cmbModoControle.Enabled = true;
tkbVelocidade.Enabled = true;
tkbAnguloDirecional.Enabled = true;
tabControl1.TabPages.Insert(1, tabControle);
tabControl1.TabPages.Remove(tabMapa);
pnlJoystick.Visible = true;
pnlFreio.Visible = true;
// Configurar o painel do joystick
pnlJoystick.BackColor = Color.LightGray; // Fundo semitransparente
// Definir região circular para o painel
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddEllipse(0, 0, pnlJoystick.Width, pnlJoystick.Height);
pnlJoystick.Region = new Region(path);
// Calcular o centro do joystick
joystickCenter = new Point(pnlJoystick.Width / 2, pnlJoystick.Height / 2);
// Definir o raio do joystick
joystickRadius = pnlJoystick.Width / 4;
joystickPosition = joystickCenter;
// Evento de pintura do painel
pnlJoystick.Paint -= PanelJoystickBack_Paint;
pnlJoystick.Paint += PanelJoystickBack_Paint;
// Eventos de toque/mouse
pnlJoystick.MouseDown -= PanelJoystickBack_MouseDown;
pnlJoystick.MouseDown += PanelJoystickBack_MouseDown;
pnlJoystick.MouseMove -= PanelJoystickBack_MouseMove;
pnlJoystick.MouseMove += PanelJoystickBack_MouseMove;
pnlJoystick.MouseUp -= PanelJoystickBack_MouseUp;
pnlJoystick.MouseUp += PanelJoystickBack_MouseUp;
pnlFreio.BackColor = Color.LightGray;
pnlFreio.BorderStyle = BorderStyle.FixedSingle;
// Eventos de toque/pressão
pnlFreio.Paint -= BrakePanel_Paint;
pnlFreio.Paint += BrakePanel_Paint;
pnlFreio.MouseDown -= BrakePanel_MouseDown;
pnlFreio.MouseDown += BrakePanel_MouseDown;
pnlFreio.MouseMove -= BrakePanel_MouseMove;
pnlFreio.MouseMove += BrakePanel_MouseMove;
pnlFreio.MouseUp -= BrakePanel_MouseUp;
pnlFreio.MouseUp += BrakePanel_MouseUp;
// Configuração inicial do freio
freioStartPosition = new Point(pnlFreio.Width / 2 - 20, 10);
freioPosition = freioStartPosition;
IniciarOperacao();
}
#region JOYSTICK
private void PanelJoystickBack_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.FillEllipse(Brushes.Red, joystickPosition.X - joystickRadius, joystickPosition.Y - joystickRadius, joystickRadius * 2, joystickRadius * 2);
}
private void PanelJoystickBack_MouseDown(object sender, MouseEventArgs e)
{
isDragging = true;
}
private void PanelJoystickBack_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
// Calcula a nova posição do joystick
var mouseX = e.X;
var mouseY = e.Y;
var deltaX = mouseX - joystickCenter.X;
var deltaY = mouseY - joystickCenter.Y;
// Limitar o movimento do joystick ao círculo do painel
var distance = Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
var maxDistance = pnlJoystick.Width / 2;
if (distance > maxDistance)
{
deltaX = (int)(deltaX / distance * maxDistance);
deltaY = (int)(deltaY / distance * maxDistance);
}
joystickPosition = new Point(joystickCenter.X + deltaX, joystickCenter.Y + deltaY);
pnlJoystick.Invalidate(); // Redesenha o painel
// Enviar comandos de movimento ao robô
SendMovementCommand(deltaX, deltaY);
}
}
private void PanelJoystickBack_MouseUp(object sender, MouseEventArgs e)
{
isDragging = false;
// Retorna o joystick ao centro
joystickPosition = joystickCenter;
pnlJoystick.Invalidate(); // Redesenha o painel
// Enviar comando de parada ao robô
SendMovementCommand(0, 0);
}
private void SendMovementCommand(int deltaX, int deltaY)
{
Keys MovKey = Keys.Escape;
if (deltaY < -10) MovKey = Keys.Up;
else if (deltaY > 10) MovKey = Keys.Down;
Keys DirKey = Keys.Escape;
if (deltaX < -10) DirKey = Keys.Left;
else if (deltaX > 10) DirKey = Keys.Right;
// Verifica se o estado da tecla de movimento mudou
if (MovKey != prevMovKey)
{
// Lógica para enviar comando ao robô baseado em MovKey
Console.WriteLine($"Movimento: MovKey={MovKey}");
//GeneralJoystick.EnviaComandoMotor(MovKey, Enums.T_Code.Mov);
var comando = GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.key == MovKey);
GeneralJoystick.ProcessarDadosControle(comando.botaoJoy, false, valorDesejado: Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeCErvasPercent);
prevMovKey = MovKey; // Atualiza o estado anterior
}
// Verifica se o estado da tecla de direção mudou
if (DirKey != prevDirKey)
{
// Lógica para enviar comando ao robô baseado em DirKey
Console.WriteLine($"Direção: DirKey={DirKey}");
//GeneralJoystick.EnviaComandoMotor(DirKey, Enums.T_Code.Dir);
var comando = GeneralJoystick.DeParaComandos.FirstOrDefault(x => x.key == DirKey);
GeneralJoystick.ProcessarDadosControle(comando.botaoJoy, false, valorDesejado: Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo);
prevDirKey = DirKey; // Atualiza o estado anterior
}
}
#endregion
#region FREIO
// Desenho do trilho e trava no painel do freio
private void BrakePanel_Paint(object sender, PaintEventArgs e)
{
Panel panel = sender as Panel;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// Desenhar trilha do freio (trajetória vertical)
e.Graphics.DrawLine(new Pen(Color.Black, 5), panel.Width / 2, 10, panel.Width / 2, panel.Height - 50);
// Desenhar a área de trava (na lateral direita)
e.Graphics.DrawRectangle(new Pen(Color.Blue, 3), panel.Width - 30, panel.Height - 60, 20, 40);
// Desenhar o botão de freio atual
e.Graphics.FillEllipse(Brushes.Red, freioPosition.X, freioPosition.Y, 40, 40);
}
// Iniciar o arraste
private void BrakePanel_MouseDown(object sender, MouseEventArgs e)
{
if (Variaveis.OperacaoEmAndamento.Parametros?.Modo != Enums.ModoOperacao.Manual)
{
return;
}
if (new Rectangle(freioPosition.X, freioPosition.Y, 40, 40).Contains(e.Location))
{
isDraggingFreio = true;
}
}
// Movimentar o botão de freio
private void BrakePanel_MouseMove(object sender, MouseEventArgs e)
{
if (Variaveis.OperacaoEmAndamento.Parametros?.Modo != Enums.ModoOperacao.Manual)
{
return;
}
if (isDraggingFreio)
{
// Calcula a posição ao arrastar
int deltaY = e.Y - freioPosition.Y;
int newPosX = freioPosition.X;
int newPosY = freioPosition.Y + deltaY;
// Limitar o movimento do freio ao trilho e destravar se o usuário mover para fora da trava
if (!isBrakeLocked || (isBrakeLocked && e.X < pnlFreio.Width - 30))
{
isBrakeLocked = false; // Destrava o freio se mover para fora
// Restringe o movimento vertical dentro da área do trilho
if (newPosY >= 10 && newPosY <= pnlFreio.Height - 50)
{
freioPosition = new Point(newPosX, newPosY);
pnlFreio.Invalidate(); // Redesenha o painel
// Enviar comando de freio
//GeneralJoystick.EnviaComandoMotor(Keys.Space, Enums.T_Code.Mov);
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.Bolinha, false);
}
}
// Verifica se o usuário está na área de trava
if (freioPosition.Y >= pnlFreio.Height - 90 && e.X >= pnlFreio.Width - 30)
{
isBrakeLocked = true; // Freio travado
freioPosition = new Point(pnlFreio.Width - 40, pnlFreio.Height - 60); // Posiciona o freio na trava
pnlFreio.Invalidate();
}
}
}
// Soltar o botão de freio
private void BrakePanel_MouseUp(object sender, MouseEventArgs e)
{
if (Variaveis.OperacaoEmAndamento.Parametros?.Modo != Enums.ModoOperacao.Manual)
{
return;
}
isDraggingFreio = false;
if (!isBrakeLocked)
{
// Se o freio não estiver travado, retorna à posição inicial
freioPosition = freioStartPosition;
pnlFreio.Invalidate(); // Redesenha o painel
// Enviar comando para desativar o freio
//GeneralJoystick.EnviaComandoMotor(Keys.Escape, Enums.T_Code.Mov);
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.Bolinha, true);
}
else
{
// Freio travado, mantém travado
//GeneralJoystick.EnviaComandoMotor(Keys.Space, Enums.T_Code.Mov);
GeneralJoystick.ProcessarDadosControle(BotoesJoystick.Bolinha, false);
}
}
#endregion
private void CmbModoControle_SelectedIndexChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = (Enums.TipoMovimentoDirecional)cmbModoControle.SelectedIndex;
}
private void tkbVelocidade_Scroll(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP = tkbVelocidade.Value;
double Velocidade = FuncoesMatematicas.ConverteMsParaKmh(FuncoesMatematicas.CalculaVelocidadeMsPercentual(tkbVelocidade.Value));
lblVelocidade.Text = $"Velocidade: {tkbVelocidade.Value}% {Velocidade.ToString("0.00")} km/h";
}
private void tkbAnguloDirecional_Scroll(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.Angulo = tkbAnguloDirecional.Value;
lblAnguloDirecional.Text = $"Ângulo Direcional: {tkbAnguloDirecional.Value}°";
}
#endregion
private void btnCodFalha_Click(object sender, EventArgs e)
{
string DescricaoFalha = Variaveis.OperacaoEmAndamento.ErroOperacaoLiberada;
CustomDialog.ShowDialog(
"Código de Falha",
$"{DescricaoFalha}",
MessageBoxIcon.Question,
new Dictionary<(string, dynamic), Action>()
{
{ ("OK", null), () => { } },
}
);
}
private void chbAcompanharCarro_CheckedChanged(object sender, EventArgs e)
{
MapaDinamico.AlterarTravaRover(chbAcompanharCarro.Checked);
}
#region OPERACAO
public class ModuloUIItem
{
public T_Code Disp { get; set; }
public bool Mandatorio { get; set; }
public bool Utilizar { get; set; }
public bool Conectado { get; set; }
public StatusModulo Status { get; set; }
public double Saude { get; set; }
public string Motivo { get; set; }
public override string ToString()
=> $"{Disp}: {Status} ({Saude})";
}
private void AtualizarListaModulos(bool forceRebuild = false)
{
if (_inRefresh) return;
_inRefresh = true;
try
{
// 1) Pega o estado atual do seu sistema
var src = Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios;
var saude = HealthWorkerService.ModulosSaude;
// 2) Constrói snapshot
var novos = new List<ModuloUIItem>(src.Count);
foreach (var mod in src)
{
var saudeMod = saude.FirstOrDefault(x => x.modulo.Equals(mod.Dispositivo));
var item = new ModuloUIItem
{
Disp = mod.Dispositivo,
Mandatorio = mod.Mandatorio,
Utilizar = mod.Utilizar,
Conectado = mod.Conectado,
Status = saudeMod?.status ?? StatusModulo.Desconectado,
Saude = saudeMod?.saude ?? 0,
Motivo = saudeMod != null ? string.Join(", ", saudeMod.motivos) : "Sem dados"
};
novos.Add(item);
}
// 3) Decide se precisa rebuild (qtd mudou ou forceRebuild)
bool precisaRebuild = forceRebuild || novos.Count != _modulosUI.Count ||
!novos.Select(n => n.Disp).SequenceEqual(_modulosUI.Select(o => o.Disp));
if (precisaRebuild)
{
_modulosUI.Clear();
_modulosUI.AddRange(novos);
clbModulos.BeginUpdate();
clbModulos.Items.Clear();
foreach (var it in _modulosUI)
{
clbModulos.Items.Add(it, it.Utilizar); // check = Mandatório
}
clbModulos.EndUpdate();
}
else
{
// 4) Só atualiza conteúdo/mandatório e força redraw
for (int i = 0; i < _modulosUI.Count; i++)
{
var novo = novos[i];
var cur = _modulosUI[i];
bool textoMudou =
cur.Status != novo.Status ||
Math.Abs(cur.Saude - novo.Saude) > 0.0001 ||
cur.Motivo != novo.Motivo;
cur.Mandatorio = novo.Mandatorio; // mantemos em sincronia
cur.Utilizar = novo.Utilizar; // mantemos em sincronia
cur.Conectado = novo.Conectado;
cur.Status = novo.Status;
cur.Saude = novo.Saude;
cur.Motivo = novo.Motivo;
// sincroniza o check se mudou externamente
bool checkAtual = clbModulos.GetItemChecked(i);
if (checkAtual != cur.Utilizar)
clbModulos.SetItemChecked(i, cur.Utilizar);
if (textoMudou)
clbModulos.Invalidate(clbModulos.GetItemRectangle(i));
}
}
}
finally
{
_inRefresh = false;
}
}
private (Color back, Color fore) Cores(StatusModulo st, bool conectado)
{
if (!conectado) return (Color.Black, Color.White); // Desconectado = preto
switch (st)
{
case StatusModulo.Falha: return (Color.Red, Color.White); // Falha = vermelho
case StatusModulo.Alerta: return (Color.Yellow, Color.Black); // Alerta = amarelo
case StatusModulo.Operante: return (Color.Green, Color.White); // Operante = verde
default: return (Color.Black, Color.White);
};
}
private void clbModulos_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0 || e.Index >= _modulosUI.Count)
return;
var it = _modulosUI[e.Index];
var (back, fore) = Cores(it.Status, it.Conectado);
// base
e.DrawBackground();
using (var b = new SolidBrush(back))
e.Graphics.FillRectangle(b, e.Bounds);
// checkbox (usa estilo do sistema, mas garantindo contraste de texto)
bool isChecked = clbModulos.GetItemChecked(e.Index);
CheckBoxRenderer.DrawCheckBox(
e.Graphics,
new Point(e.Bounds.Left + 4, e.Bounds.Top + (e.Bounds.Height - 14) / 2),
isChecked ? System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal
: System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal
);
// texto
var texto = it.ToString();
var textRect = new Rectangle(e.Bounds.Left + 24, e.Bounds.Top, e.Bounds.Width - 24, e.Bounds.Height);
TextRenderer.DrawText(e.Graphics, texto, e.Font, textRect, fore, TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
// foco
e.DrawFocusRectangle();
}
private void clbModulos_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (_inRefresh) return; // evita loop quando sincronizamos via código
var idx = e.Index;
if (idx < 0 || idx >= _modulosUI.Count) return;
// novo valor escolhido pelo usuário
bool novoUtilizar = e.NewValue == CheckState.Checked;
// atualiza UI cache
_modulosUI[idx].Utilizar = novoUtilizar;
// escreve de volta na fonte oficial
var disp = _modulosUI[idx].Disp;
var alvo = Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.FirstOrDefault(m => m.Dispositivo.Equals(disp));
if (alvo != null)
{
if (alvo.Utilizar && alvo.Mandatorio && !novoUtilizar)
{
CustomDialog.ShowDialog(
"Confirmação",
"O módulo selecionado é um item mandatório para a operação atual, tem certeza que deseja desabilitar seu uso?",
MessageBoxIcon.Information,
new Dictionary<(string, dynamic), Action>()
{
{ ("Sim", null), () => { alvo.Utilizar = novoUtilizar; } },
{ ("Não", null), () => { _modulosUI[idx].Utilizar = alvo.Utilizar; } }
}
);
}
else
{
alvo.Utilizar = novoUtilizar;
}
}
// reavaliar liberação da operação
// (deixa para depois do evento terminar para não travar UI)
//this.BeginInvoke(new Action(ReavaliarLiberacaoOperacao));
}
private void clbModulos_SelectedIndexChanged(object sender, EventArgs e)
{
if (clbModulos.SelectedIndex < 0 || clbModulos.SelectedIndex >= _modulosUI.Count) return;
txtModuloMotivo.Text = _modulosUI[clbModulos.SelectedIndex].Motivo;
}
private void btnPausarOperacao_Click(object sender, EventArgs e)
{
if (!Variaveis.OperacaoEmAndamento.Pausa)
{
Variaveis.OperacaoEmAndamento.Pausa = true;
btnPausarOperacao.Text = "Retomar";
}
else
{
Variaveis.OperacaoEmAndamento.Pausa = false;
btnPausarOperacao.Text = "Pausar";
}
}
private async void btnReferenciar_Click(object sender, EventArgs e)
{
await Variaveis.OperacaoEmAndamento.RealizarCalibragemInicialAsync(true);
}
private void btnSalvarParametros_Click(object sender, EventArgs e)
{
var res = CustomDialog.ShowDialog(
"Salvar parâmetros da operação",
"Deseja aplicar os novos parâmetros para operação atual?",
MessageBoxIcon.Question,
new Dictionary<(string, DialogResult?), Action>()
{
{ ("Sim", DialogResult.Yes), () => { } },
{ ("Não", DialogResult.No), () => { } },
}
);
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
if (res == DialogResult.Yes)
{
pControle.FrenagemAutomaticaAoParar = chbFrenagemAutomatica.Checked;
pControle.MovVelocidadeSErvasPercent = (int)FuncoesMatematicas.CalculaRPMVelocidade(FuncoesMatematicas.CalculaVelocidadeMsPercentual((int)nudVelSemErvas.Value));
pControle.MovVelocidadeCErvasPercent = (int)FuncoesMatematicas.CalculaRPMVelocidade(FuncoesMatematicas.CalculaVelocidadeMsPercentual((int)nudVelComErvas.Value));
pControle.PulverizadorAutomatico = chbPulverizadorAutomatico.Checked;
pControle.AtuPercentualInicioPulverizacao = ((double)nudPercentualAtuacaoBico.Value / 100.0);
pControle.AtuPressaoLinha = (double)nudPressaoLinha.Value;
RedisService.AtualizarCampos(
CtxKey.DadosPesosMPC,
("posicao", Convert.ToDouble(txtPesoPosicao.Text)),
("orientacao", Convert.ToDouble(txtPesoOrientacao.Text)),
("suavidade_min", Convert.ToDouble(txtPesoSuavidadeMin.Text)),
("suavidade_max", Convert.ToDouble(txtPesoSuavidadeMax.Text)),
("fator_re", Convert.ToDouble(txtPesoFatorRe.Text)),
("ideal", Convert.ToDouble(txtPesoIdeal.Text)),
("lateral_min", Convert.ToDouble(txtPesoLateralMin.Text)),
("lateral_max", Convert.ToDouble(txtPesoLateralMax.Text))
);
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
}
else
{
chbFrenagemAutomatica.Checked = pControle.FrenagemAutomaticaAoParar;
nudVelSemErvas.Value = (int)pControle.MovVelocidadeSErvasPercent;
nudVelComErvas.Value = (int)pControle.MovVelocidadeCErvasPercent;
chbPulverizadorAutomatico.Checked = pControle.PulverizadorAutomatico;
nudPercentualAtuacaoBico.Value = (int)pControle.AtuPercentualInicioPulverizacao;
nudPressaoLinha.Value = (int)pControle.AtuPressaoLinha;
string pesosMpcStr = RedisService.Get(CtxKey.DadosPesosMPC);
var pesos = JsonConvert.DeserializeObject<MPCPesosModel>(pesosMpcStr);
txtPesoPosicao.Text = pesos.posicao.ToString();
txtPesoOrientacao.Text = pesos.orientacao.ToString();
txtPesoSuavidadeMin.Text = pesos.suavidade_min.ToString();
txtPesoSuavidadeMax.Text = pesos.suavidade_max.ToString();
txtPesoFatorRe.Text = pesos.fator_re.ToString();
txtPesoIdeal.Text = pesos.ideal.ToString();
txtPesoLateralMin.Text = pesos.lateral_min.ToString();
txtPesoLateralMax.Text = pesos.lateral_max.ToString();
}
}
#endregion
}
}