891 lines
29 KiB
C#
891 lines
29 KiB
C#
using AgroBase.Forms.IHM.Controls;
|
|
using AgroBase.Models;
|
|
using AgroBase.Models.Operadores;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace AgroBase.Forms.IHM
|
|
{
|
|
public partial class frmIHM : Form
|
|
{
|
|
private AsyncTaskTimerModel tmrDispositivos;
|
|
|
|
private Form _telaAtual;
|
|
|
|
public frmMenu frmMenu = new frmMenu();
|
|
private frmAjustes _frmAjustes;
|
|
private frmDiagnosticos _frmDiagnosticos;
|
|
private frmOperacao _frmOperacao;
|
|
//private frmTestes _frmTestes;
|
|
|
|
private StatusOperacaoControl cardBateria;
|
|
private StatusOperacaoControl cardReservatorio;
|
|
private StatusOperacaoControl cardTemperatura;
|
|
private StatusOperacaoControl cardRede;
|
|
private StatusOperacaoControl cardGnss;
|
|
private StatusOperacaoControl cardBase;
|
|
|
|
public event EventHandler PausarOperacaoSolicitado;
|
|
public event EventHandler ParadaEmergenciaSolicitada;
|
|
public event EventHandler FinalizarOperacaoSolicitado;
|
|
|
|
public frmIHM()
|
|
{
|
|
InitializeComponent();
|
|
|
|
VincularNavegacaoMenu();
|
|
|
|
CriarCardsResumo();
|
|
VincularAcoesLaterais();
|
|
}
|
|
|
|
private void VincularNavegacaoMenu()
|
|
{
|
|
frmMenu.TelaSolicitada += FrmMenu_TelaSolicitada;
|
|
}
|
|
|
|
private void TelaFilha_VoltarSolicitado(object sender, EventArgs e)
|
|
{
|
|
AbrirTela(frmMenu);
|
|
}
|
|
|
|
private void FrmMenu_TelaSolicitada(object sender, TelaSolicitadaEventArgs e)
|
|
{
|
|
switch (e.Tela)
|
|
{
|
|
case TipoTelaIHM.Operacao:
|
|
if (_frmOperacao == null || _frmOperacao.IsDisposed)
|
|
{
|
|
_frmOperacao = new frmOperacao();
|
|
_frmOperacao.VoltarSolicitado += TelaFilha_VoltarSolicitado;
|
|
}
|
|
AbrirTela(_frmOperacao);
|
|
break;
|
|
|
|
case TipoTelaIHM.Ajustes:
|
|
if (_frmAjustes == null || _frmAjustes.IsDisposed)
|
|
{
|
|
_frmAjustes = new frmAjustes();
|
|
_frmAjustes.VoltarSolicitado += TelaFilha_VoltarSolicitado;
|
|
}
|
|
AbrirTela(_frmAjustes);
|
|
break;
|
|
|
|
case TipoTelaIHM.Diagnostico:
|
|
if (_frmDiagnosticos == null || _frmDiagnosticos.IsDisposed)
|
|
{
|
|
_frmDiagnosticos = new frmDiagnosticos();
|
|
_frmDiagnosticos.VoltarSolicitado += TelaFilha_VoltarSolicitado;
|
|
}
|
|
AbrirTela(_frmDiagnosticos);
|
|
break;
|
|
|
|
case TipoTelaIHM.Testes:
|
|
//AbrirTestes();
|
|
break;
|
|
|
|
case TipoTelaIHM.Menu:
|
|
default:
|
|
AbrirTela(frmMenu);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void CriarCardsResumo()
|
|
{
|
|
cardBateria = CriarCard(
|
|
"cardBateria",
|
|
"Bateria",
|
|
"47%",
|
|
HmiTheme.Success,
|
|
Properties.Resources.bateria);
|
|
|
|
cardReservatorio = CriarCard(
|
|
"cardReservatorio",
|
|
"Reservatório",
|
|
"23%",
|
|
HmiTheme.Info,
|
|
Properties.Resources.reservatorio);
|
|
|
|
cardTemperatura = CriarCard(
|
|
"cardTemperatura",
|
|
"Temperatura",
|
|
"32°C",
|
|
HmiTheme.Warning,
|
|
Properties.Resources.temperatura);
|
|
|
|
cardRede = CriarCard(
|
|
"cardRede",
|
|
"Rede",
|
|
"100%",
|
|
HmiTheme.Success,
|
|
Properties.Resources.rede1);
|
|
|
|
cardGnss = CriarCard(
|
|
"cardGnss",
|
|
"GNSS",
|
|
"RTK Fixo 0,25 cm",
|
|
HmiTheme.Info,
|
|
Properties.Resources.gnss);
|
|
|
|
cardBase = CriarCard(
|
|
"cardBase",
|
|
"Base",
|
|
"264,7 m",
|
|
HmiTheme.Manual,
|
|
Properties.Resources._base);
|
|
|
|
fpnlResumo.SuspendLayout();
|
|
|
|
try
|
|
{
|
|
fpnlResumo.Controls.Clear();
|
|
|
|
fpnlResumo.Controls.Add(cardBateria);
|
|
fpnlResumo.Controls.Add(cardReservatorio);
|
|
fpnlResumo.Controls.Add(cardTemperatura);
|
|
fpnlResumo.Controls.Add(cardRede);
|
|
fpnlResumo.Controls.Add(cardGnss);
|
|
fpnlResumo.Controls.Add(cardBase);
|
|
}
|
|
finally
|
|
{
|
|
fpnlResumo.ResumeLayout(true);
|
|
}
|
|
|
|
AjustarLarguraCards();
|
|
}
|
|
|
|
private StatusOperacaoControl CriarCard(string nome, string titulo, string valor, Color cor, Image icon)
|
|
{
|
|
return new StatusOperacaoControl
|
|
{
|
|
Name = nome,
|
|
Titulo = titulo,
|
|
Valor = valor,
|
|
CorValor = cor,
|
|
CorDestaque = cor,
|
|
CorFundo = HmiTheme.SurfaceRaised,
|
|
CorBorda = HmiTheme.BorderSoft,
|
|
CorTitulo = HmiTheme.Text,
|
|
Icone = icon,
|
|
Height = 42,
|
|
Margin = new Padding(0, 0, 0, 5)
|
|
};
|
|
}
|
|
|
|
private void VincularAcoesLaterais()
|
|
{
|
|
btnPausarOperacao.Click += delegate
|
|
{
|
|
if (PausarOperacaoSolicitado != null)
|
|
PausarOperacaoSolicitado(this, EventArgs.Empty);
|
|
};
|
|
|
|
btnParadaEmergencia.Click += delegate
|
|
{
|
|
if (ParadaEmergenciaSolicitada != null)
|
|
ParadaEmergenciaSolicitada(this, EventArgs.Empty);
|
|
};
|
|
|
|
btnFinalizarOperacao.Click += delegate
|
|
{
|
|
if (FinalizarOperacaoSolicitado != null)
|
|
FinalizarOperacaoSolicitado(this, EventArgs.Empty);
|
|
};
|
|
}
|
|
|
|
private void frmIHM_Load(object sender, EventArgs e)
|
|
{
|
|
lblVersao.Text = "IHM Rover • v " + Variaveis.Versao;
|
|
AbrirTela(frmMenu);
|
|
|
|
if (tmrDispositivos != null)
|
|
tmrDispositivos.Dispose();
|
|
|
|
tmrDispositivos = new AsyncTaskTimerModel("tmrDispositivos", tmrDispositivos_Tick, 1000, this);
|
|
|
|
tmrDispositivos.Start();
|
|
}
|
|
|
|
private void frmIHM_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
if (tmrDispositivos == null)
|
|
return;
|
|
|
|
tmrDispositivos.Dispose();
|
|
tmrDispositivos = null;
|
|
}
|
|
|
|
private Task tmrDispositivos_Tick()
|
|
{
|
|
try
|
|
{
|
|
if (IsDisposed || Disposing || !IsHandleCreated)
|
|
return Task.CompletedTask;
|
|
|
|
if (InvokeRequired)
|
|
{
|
|
BeginInvoke(new Action(AtualizarControlesUI));
|
|
}
|
|
else
|
|
{
|
|
AtualizarControlesUI();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog("Erro no tmrDispositivos_Tick: " + ex.Message);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void AtualizarControlesUI()
|
|
{
|
|
var operacao = Variaveis.OperacaoEmAndamento;
|
|
var dadosOperacao = operacao?.Sensoriamento?.Operacao;
|
|
var saudeModulos = operacao?.Sensoriamento?.OperadorSaude?.ModulosSaude;
|
|
|
|
Enums.StatusOperacao statusOperacao = dadosOperacao?.StatusOperacaoAtual ?? Enums.StatusOperacao.NaoIniciado;
|
|
|
|
AtualizarStatusOperacao(statusOperacao, dadosOperacao?.Pausa ?? false, dadosOperacao?.Emergencia ?? false);
|
|
|
|
// =========================================================
|
|
// BATERIA
|
|
// =========================================================
|
|
double bateria = operacao?.Sensoriamento?.Bateria?.PercentualBateria ?? 0;
|
|
double bateriaSaude = ObterSaudeModulo(saudeModulos, Enums.T_Code.Bat);
|
|
Color corBateria = CorPorValorESaude(bateria, bateriaSaude);
|
|
AtualizarBateria($"{Limitar(bateria, 0, 100):0}%", corBateria);
|
|
|
|
// =========================================================
|
|
// RESERVATÓRIO
|
|
// =========================================================
|
|
double reservatorio = operacao?.Sensoriamento?.Atuador?.PercentualReservatorio ?? 0;
|
|
double atuadorSaude = ObterSaudeModulo(saudeModulos, Enums.T_Code.Atu);
|
|
Color corReservatorio = CorPorValorESaude(reservatorio, atuadorSaude);
|
|
AtualizarReservatorio($"{Limitar(reservatorio, 0, 100):0}%", corReservatorio);
|
|
|
|
// =========================================================
|
|
// TEMPERATURA
|
|
// =========================================================
|
|
double temperatura = operacao?.Sensoriamento?.CoolerControl?.Temperatura ?? 0;
|
|
double temperaturaSaude = ObterSaudeModulo(saudeModulos, Enums.T_Code.Npc);
|
|
Color corTemperatura = CorTemperatura(temperatura, temperaturaSaude);
|
|
AtualizarTemperatura($"{temperatura:0.#} °C", corTemperatura);
|
|
|
|
// =========================================================
|
|
// REDE / IPB
|
|
// =========================================================
|
|
double redeSaude = ObterSaudeModulo(saudeModulos, Enums.T_Code.Ipb);
|
|
Color corRede = CorPorPercentual(redeSaude);
|
|
AtualizarRede($"{Limitar(redeSaude, 0, 100):0}%", corRede);
|
|
|
|
// =========================================================
|
|
// GNSS
|
|
// =========================================================
|
|
var gnss = operacao?.Sensoriamento?.Gps;
|
|
double gnssSaude = ObterSaudeModulo(saudeModulos, Enums.T_Code.Gps);
|
|
bool gnssConectado = gnss != null && gnssSaude > 0;
|
|
if (!gnssConectado)
|
|
{
|
|
AtualizarGnss("Desconectado", HmiTheme.Danger);
|
|
}
|
|
else
|
|
{
|
|
Enums.TiposCorrecaoGPS qualidadeFix = gnss.QualidadeFix;
|
|
double precisaoCm = Math.Max(0, gnss.PrecisaoCm);
|
|
double notaGnss = CalcularNotaGnss(qualidadeFix, precisaoCm, gnssSaude);
|
|
Color corGnss = CorPorPercentual(notaGnss);
|
|
string textoGnss = $"{FormatarQualidadeGnss(qualidadeFix)} " + $"{precisaoCm:0.##} cm";
|
|
AtualizarGnss(textoGnss, corGnss);
|
|
}
|
|
|
|
// =========================================================
|
|
// BASE
|
|
// =========================================================
|
|
bool baseConectada = VariaveisOperacao.PosicaoBase?.Inicializado ?? false;
|
|
if (!baseConectada || gnss == null)
|
|
{
|
|
AtualizarDistanciaBase("Desconectada", HmiTheme.Danger);
|
|
}
|
|
else
|
|
{
|
|
double distanciaBase = GPSUtils.DistanciaEntrePontos(gnss, VariaveisOperacao.PosicaoBase);
|
|
Color corBase = CorDistanciaBase(distanciaBase, 1000);
|
|
string distanciaTexto = FormatarDistancia(distanciaBase);
|
|
AtualizarDistanciaBase(distanciaTexto, corBase);
|
|
}
|
|
|
|
// =========================================================
|
|
// BOTÕES DA OPERAÇÃO
|
|
// =========================================================
|
|
bool operacaoPausada = dadosOperacao?.Pausa ?? false;
|
|
bool operacaoEmergencia = dadosOperacao?.Emergencia ?? false;
|
|
bool operacaoIniciada = dadosOperacao?.OperacaoIniciada ?? false;
|
|
AtualizarAcoesOperacao(statusOperacao, operacaoIniciada, operacaoPausada, operacaoEmergencia);
|
|
|
|
// =========================================================
|
|
// FORMULÁRIO FILHO ATIVO
|
|
// =========================================================
|
|
if (_telaAtual != null && !_telaAtual.IsDisposed)
|
|
{
|
|
(_telaAtual as ITelaNavegavel).AtualizarDadosTela();
|
|
}
|
|
}
|
|
|
|
public void AbrirTela(Form tela)
|
|
{
|
|
if (tela == null)
|
|
return;
|
|
|
|
pnlConteudo.SuspendLayout();
|
|
|
|
try
|
|
{
|
|
if (_telaAtual != null && !_telaAtual.IsDisposed && _telaAtual != tela)
|
|
{
|
|
pnlConteudo.Controls.Remove(_telaAtual);
|
|
_telaAtual.Hide();
|
|
}
|
|
|
|
_telaAtual = tela;
|
|
|
|
tela.TopLevel = false;
|
|
tela.FormBorderStyle = FormBorderStyle.None;
|
|
tela.ControlBox = false;
|
|
tela.MinimizeBox = false;
|
|
tela.MaximizeBox = false;
|
|
tela.ShowInTaskbar = false;
|
|
tela.WindowState = FormWindowState.Normal;
|
|
tela.StartPosition = FormStartPosition.Manual;
|
|
tela.Dock = DockStyle.Fill;
|
|
tela.Margin = Padding.Empty;
|
|
tela.Padding = Padding.Empty;
|
|
|
|
if (!pnlConteudo.Controls.Contains(tela))
|
|
pnlConteudo.Controls.Add(tela);
|
|
|
|
tela.Show();
|
|
tela.BringToFront();
|
|
}
|
|
finally
|
|
{
|
|
pnlConteudo.ResumeLayout(true);
|
|
}
|
|
}
|
|
|
|
public void AtualizarCabecalhoOperacao(string status, string detalhes, Color corStatus)
|
|
{
|
|
ExecutarNaUI(delegate
|
|
{
|
|
lblStatusOperacao.Text = string.IsNullOrWhiteSpace(status) ? "NAODEFINIDO" : status.ToUpperInvariant();
|
|
|
|
lblStatusOperacaoDetalhes.Text = detalhes ?? string.Empty;
|
|
|
|
lblStatusOperacao.ForeColor = corStatus;
|
|
lblIndicadorStatus.ForeColor = corStatus;
|
|
|
|
pnlStatusOperacao.AccentColor = corStatus;
|
|
pnlStatusOperacao.BorderColor = MisturarCores(HmiTheme.BorderSoft, corStatus, 0.35F);
|
|
});
|
|
}
|
|
|
|
public void AtualizarBateria(string valor, Color cor)
|
|
{
|
|
AtualizarCard(cardBateria, valor, cor);
|
|
}
|
|
|
|
public void AtualizarReservatorio(string valor, Color cor)
|
|
{
|
|
AtualizarCard(cardReservatorio, valor, cor);
|
|
}
|
|
|
|
public void AtualizarTemperatura(string valor, Color cor)
|
|
{
|
|
AtualizarCard(cardTemperatura, valor, cor);
|
|
}
|
|
|
|
public void AtualizarRede(string valor, Color cor)
|
|
{
|
|
AtualizarCard(cardRede, valor, cor);
|
|
}
|
|
|
|
public void AtualizarGnss(string valor, Color cor)
|
|
{
|
|
AtualizarCard(cardGnss, valor, cor);
|
|
}
|
|
|
|
public void AtualizarDistanciaBase(string valor, Color cor)
|
|
{
|
|
AtualizarCard(cardBase, valor, cor);
|
|
}
|
|
|
|
public void DefinirOperacaoPausada(bool pausada)
|
|
{
|
|
ExecutarNaUI(delegate
|
|
{
|
|
btnPausarOperacao.Text =
|
|
pausada
|
|
? "RETOMAR OPERAÇÃO"
|
|
: "PAUSAR OPERAÇÃO";
|
|
|
|
btnPausarOperacao.IconText =
|
|
pausada
|
|
? "▶"
|
|
: "Ⅱ";
|
|
|
|
btnPausarOperacao.AccentColor =
|
|
pausada
|
|
? HmiTheme.Success
|
|
: HmiTheme.Warning;
|
|
|
|
btnPausarOperacao.BorderColor =
|
|
pausada
|
|
? HmiTheme.Success
|
|
: HmiTheme.Warning;
|
|
});
|
|
}
|
|
|
|
public void DefinirAcoesHabilitadas(bool pausar, bool emergencia, bool finalizar)
|
|
{
|
|
ExecutarNaUI(delegate
|
|
{
|
|
btnPausarOperacao.Enabled = pausar;
|
|
btnParadaEmergencia.Enabled = emergencia;
|
|
btnFinalizarOperacao.Enabled = finalizar;
|
|
});
|
|
}
|
|
|
|
private void AtualizarCard(StatusOperacaoControl card, string valor, Color cor)
|
|
{
|
|
if (card == null)
|
|
return;
|
|
|
|
if (card.Valor == valor || card.CorValor == cor)
|
|
return;
|
|
|
|
ExecutarNaUI(delegate
|
|
{
|
|
card.AtualizarStatus(valor, cor, cor);
|
|
});
|
|
}
|
|
|
|
private void AjustarLarguraCards()
|
|
{
|
|
if (fpnlResumo == null)
|
|
return;
|
|
|
|
int largura = fpnlResumo.ClientSize.Width - fpnlResumo.Padding.Horizontal;
|
|
|
|
if (fpnlResumo.VerticalScroll.Visible)
|
|
largura -= SystemInformation.VerticalScrollBarWidth;
|
|
|
|
largura = Math.Max(120, largura);
|
|
|
|
foreach (Control control in fpnlResumo.Controls)
|
|
control.Width = largura;
|
|
}
|
|
|
|
private void fpnlResumo_Resize(object sender, EventArgs e)
|
|
{
|
|
AjustarLarguraCards();
|
|
}
|
|
|
|
private void ExecutarNaUI(Action acao)
|
|
{
|
|
if (acao == null || IsDisposed || Disposing)
|
|
return;
|
|
|
|
if (InvokeRequired)
|
|
{
|
|
BeginInvoke(acao);
|
|
return;
|
|
}
|
|
|
|
acao();
|
|
}
|
|
|
|
private static Color MisturarCores(Color baseColor, Color accentColor, float pesoAccent)
|
|
{
|
|
pesoAccent = Math.Max(0F, Math.Min(1F, pesoAccent));
|
|
|
|
float pesoBase = 1F - pesoAccent;
|
|
|
|
return Color.FromArgb(
|
|
(int)(baseColor.R * pesoBase + accentColor.R * pesoAccent),
|
|
(int)(baseColor.G * pesoBase + accentColor.G * pesoAccent),
|
|
(int)(baseColor.B * pesoBase + accentColor.B * pesoAccent)
|
|
);
|
|
}
|
|
|
|
private static Color CorPorPercentual(double percentual)
|
|
{
|
|
percentual = Limitar(percentual, 0, 100);
|
|
|
|
if (percentual <= 50)
|
|
{
|
|
double fator = percentual / 50.0;
|
|
|
|
return InterpolarCor(HmiTheme.Danger, HmiTheme.Warning, fator);
|
|
}
|
|
|
|
double fatorVerde = (percentual - 50) / 50.0;
|
|
|
|
return InterpolarCor(HmiTheme.Warning, HmiTheme.Success, fatorVerde);
|
|
}
|
|
|
|
private static Color CorPorValorESaude(double valor, double saude)
|
|
{
|
|
double notaFinal = Math.Min(Limitar(valor, 0, 100), Limitar(saude, 0, 100));
|
|
|
|
return CorPorPercentual(notaFinal);
|
|
}
|
|
|
|
private static Color CorTemperatura(double temperatura, double saudeModulo)
|
|
{
|
|
Color corTemperatura;
|
|
|
|
if (temperatura <= 45)
|
|
{
|
|
corTemperatura = HmiTheme.Success;
|
|
}
|
|
else if (temperatura <= 60)
|
|
{
|
|
double fator = (temperatura - 45) / (60 - 45);
|
|
|
|
corTemperatura = InterpolarCor(HmiTheme.Success, HmiTheme.Warning, fator);
|
|
}
|
|
else if (temperatura <= 75)
|
|
{
|
|
double fator = (temperatura - 60) / (75 - 60);
|
|
|
|
corTemperatura = InterpolarCor(HmiTheme.Warning, HmiTheme.Danger, fator);
|
|
}
|
|
else
|
|
{
|
|
corTemperatura = HmiTheme.Danger;
|
|
}
|
|
|
|
Color corSaude = CorPorPercentual(saudeModulo);
|
|
|
|
/*
|
|
* Se a saúde estiver muito baixa,
|
|
* ela prevalece sobre a temperatura.
|
|
*/
|
|
if (saudeModulo < 40)
|
|
return corSaude;
|
|
|
|
return corTemperatura;
|
|
}
|
|
|
|
private static double NotaQualidadeGnss(Enums.TiposCorrecaoGPS qualidade)
|
|
{
|
|
switch (qualidade)
|
|
{
|
|
case Enums.TiposCorrecaoGPS.RTKFixo:
|
|
return 100;
|
|
|
|
case Enums.TiposCorrecaoGPS.BaseFix:
|
|
return 100;
|
|
|
|
case Enums.TiposCorrecaoGPS.RTKFlutuante:
|
|
return 78;
|
|
|
|
case Enums.TiposCorrecaoGPS.PPS:
|
|
return 65;
|
|
|
|
case Enums.TiposCorrecaoGPS.DGPS:
|
|
return 58;
|
|
|
|
case Enums.TiposCorrecaoGPS.DeadReckoing:
|
|
return 35;
|
|
|
|
case Enums.TiposCorrecaoGPS.Autonomo:
|
|
return 22;
|
|
|
|
case Enums.TiposCorrecaoGPS.SemCorrecao:
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private static double NotaPrecisaoGnss(double precisaoCm)
|
|
{
|
|
if (precisaoCm <= 2)
|
|
return 100;
|
|
|
|
if (precisaoCm <= 5)
|
|
return InterpolarValor(precisaoCm, 2, 5, 100, 90);
|
|
|
|
if (precisaoCm <= 10)
|
|
return InterpolarValor(precisaoCm, 5, 10, 90, 75);
|
|
|
|
if (precisaoCm <= 30)
|
|
return InterpolarValor(precisaoCm, 10, 30, 75, 50);
|
|
|
|
if (precisaoCm <= 100)
|
|
return InterpolarValor(precisaoCm, 30, 100, 50, 20);
|
|
|
|
return 5;
|
|
}
|
|
|
|
private static double CalcularNotaGnss(Enums.TiposCorrecaoGPS qualidade, double precisaoCm, double saudeModulo)
|
|
{
|
|
double notaFix = NotaQualidadeGnss(qualidade);
|
|
|
|
double notaPrecisao = NotaPrecisaoGnss(precisaoCm);
|
|
|
|
/*
|
|
* O pior dos três critérios define a cor.
|
|
*
|
|
* RTK Fixo com saúde ruim não fica verde.
|
|
* Saúde boa com modo autônomo também não.
|
|
*/
|
|
return Math.Min(notaFix, Math.Min(notaPrecisao, Limitar(saudeModulo, 0, 100)));
|
|
}
|
|
|
|
private static string FormatarQualidadeGnss(Enums.TiposCorrecaoGPS qualidade)
|
|
{
|
|
switch (qualidade)
|
|
{
|
|
case Enums.TiposCorrecaoGPS.SemCorrecao:
|
|
return "Sem correção";
|
|
|
|
case Enums.TiposCorrecaoGPS.Autonomo:
|
|
return "Autônomo";
|
|
|
|
case Enums.TiposCorrecaoGPS.DGPS:
|
|
return "DGPS";
|
|
|
|
case Enums.TiposCorrecaoGPS.PPS:
|
|
return "PPS";
|
|
|
|
case Enums.TiposCorrecaoGPS.RTKFixo:
|
|
return "RTK Fixo";
|
|
|
|
case Enums.TiposCorrecaoGPS.RTKFlutuante:
|
|
return "RTK Flutuante";
|
|
|
|
case Enums.TiposCorrecaoGPS.DeadReckoing:
|
|
return "Dead Reckoning";
|
|
|
|
case Enums.TiposCorrecaoGPS.BaseFix:
|
|
return "Base Fix";
|
|
|
|
default:
|
|
return "Desconhecido";
|
|
}
|
|
}
|
|
|
|
private static Color CorDistanciaBase(double distanciaMetros, double distanciaMaximaMetros)
|
|
{
|
|
if (double.IsNaN(distanciaMetros) || double.IsInfinity(distanciaMetros) || distanciaMetros < 0)
|
|
{
|
|
return HmiTheme.Danger;
|
|
}
|
|
|
|
double percentualSaudavel = 100 - (distanciaMetros / distanciaMaximaMetros * 100);
|
|
|
|
return CorPorPercentual(percentualSaudavel);
|
|
}
|
|
|
|
private static string FormatarDistancia(double distanciaMetros)
|
|
{
|
|
if (double.IsNaN(distanciaMetros) || double.IsInfinity(distanciaMetros) || distanciaMetros < 0)
|
|
{
|
|
return "Indisponível";
|
|
}
|
|
|
|
if (distanciaMetros >= 1000)
|
|
{
|
|
return $"{distanciaMetros / 1000.0:0.00} km";
|
|
}
|
|
|
|
return $"{distanciaMetros:0.0} m";
|
|
}
|
|
|
|
private void AtualizarStatusOperacao(Enums.StatusOperacao status, bool pausada, bool emergencia, int? inicio_em = null)
|
|
{
|
|
string titulo;
|
|
string descricao;
|
|
Color cor;
|
|
|
|
if (emergencia)
|
|
{
|
|
titulo = "EMERGÊNCIA";
|
|
descricao = "Operação interrompida por emergência.";
|
|
|
|
cor = HmiTheme.Danger;
|
|
}
|
|
else if (pausada)
|
|
{
|
|
titulo = "OPERAÇÃO PAUSADA";
|
|
descricao = "Aguardando retomada pelo operador.";
|
|
|
|
cor = HmiTheme.Warning;
|
|
}
|
|
else
|
|
{
|
|
switch (status)
|
|
{
|
|
case Enums.StatusOperacao.NaoIniciado:
|
|
titulo = "AGUARDANDO";
|
|
descricao = "Aguardando parâmetros da operação.";
|
|
|
|
cor = HmiTheme.TextMuted;
|
|
break;
|
|
|
|
case Enums.StatusOperacao.Parametrizando:
|
|
titulo = "PARAMETRIZANDO";
|
|
descricao = "Aplicando parâmetros recebidos da base.";
|
|
|
|
cor = HmiTheme.Info;
|
|
break;
|
|
|
|
case Enums.StatusOperacao.Calibrando:
|
|
titulo = "CALIBRANDO";
|
|
descricao = "Executando verificações e calibrações.";
|
|
|
|
cor = HmiTheme.Warning;
|
|
break;
|
|
|
|
case Enums.StatusOperacao.Aguardando:
|
|
titulo = "PRONTO";
|
|
if (inicio_em.HasValue)
|
|
descricao = $"Início em {inicio_em.Value} segundos";
|
|
else
|
|
descricao = "Equipamento aguardando início.";
|
|
|
|
cor = HmiTheme.Info;
|
|
break;
|
|
|
|
case Enums.StatusOperacao.EmAndamento:
|
|
titulo = "EM OPERAÇÃO";
|
|
descricao = "Rover executando a operação.";
|
|
|
|
cor = HmiTheme.Success;
|
|
break;
|
|
|
|
case Enums.StatusOperacao.Parado:
|
|
titulo = "PARADO";
|
|
descricao = "Equipamento parado com segurança.";
|
|
|
|
cor = HmiTheme.Warning;
|
|
break;
|
|
|
|
case Enums.StatusOperacao.Concluido:
|
|
titulo = "CONCLUÍDO";
|
|
descricao = "Operação finalizada com sucesso.";
|
|
|
|
cor = HmiTheme.Success;
|
|
break;
|
|
|
|
case Enums.StatusOperacao.Erro:
|
|
titulo = "ERRO";
|
|
descricao = "Falha detectada durante a operação.";
|
|
|
|
cor = HmiTheme.Danger;
|
|
break;
|
|
|
|
default:
|
|
titulo = "INDEFINIDO";
|
|
descricao = "Estado operacional não reconhecido.";
|
|
|
|
cor = HmiTheme.TextMuted;
|
|
break;
|
|
}
|
|
}
|
|
|
|
AtualizarCabecalhoOperacao(titulo, descricao, cor);
|
|
}
|
|
|
|
private void AtualizarAcoesOperacao(Enums.StatusOperacao status, bool iniciada, bool pausada, bool emergencia)
|
|
{
|
|
DefinirOperacaoPausada(pausada);
|
|
|
|
bool concluida = status == Enums.StatusOperacao.Concluido;
|
|
|
|
bool comErro = status == Enums.StatusOperacao.Erro;
|
|
|
|
bool podePausar = iniciada && !emergencia && !concluida && !comErro;
|
|
|
|
bool podeEmergencia = iniciada && !emergencia && !concluida;
|
|
|
|
bool podeFinalizar = iniciada && !concluida;
|
|
|
|
DefinirAcoesHabilitadas(podePausar, podeEmergencia, podeFinalizar);
|
|
|
|
if (emergencia)
|
|
{
|
|
btnParadaEmergencia.Text = "EM EMERGÊNCIA";
|
|
btnParadaEmergencia.IconText = "■";
|
|
}
|
|
else
|
|
{
|
|
btnParadaEmergencia.Text = "EMERGÊNCIA";
|
|
btnParadaEmergencia.IconText = "■";
|
|
}
|
|
}
|
|
|
|
private static double ObterSaudeModulo(List<ManagerWorkerMessageResponseModulosPendentesModel> modulosSaude, Enums.T_Code modulo)
|
|
{
|
|
if (modulosSaude == null)
|
|
return 0;
|
|
|
|
var item = modulosSaude.FirstOrDefault(x => x.modulo == modulo);
|
|
|
|
if (item == null)
|
|
return 0;
|
|
|
|
return Limitar(Convert.ToDouble(item.saude), 0, 100);
|
|
}
|
|
|
|
private static Color InterpolarCor(Color inicial, Color final, double fator)
|
|
{
|
|
fator = Limitar(fator, 0, 1);
|
|
|
|
int r = (int)Math.Round(inicial.R + (final.R - inicial.R) * fator);
|
|
|
|
int g = (int)Math.Round(inicial.G + (final.G - inicial.G) * fator);
|
|
|
|
int b = (int)Math.Round(inicial.B + (final.B - inicial.B) * fator);
|
|
|
|
return Color.FromArgb(r, g, b);
|
|
}
|
|
|
|
private static double InterpolarValor(double valor, double origemMinima, double origemMaxima, double destinoInicial, double destinoFinal)
|
|
{
|
|
if (origemMaxima <= origemMinima)
|
|
return destinoInicial;
|
|
|
|
double fator = (valor - origemMinima) / (origemMaxima - origemMinima);
|
|
|
|
fator = Limitar(fator, 0, 1);
|
|
|
|
return destinoInicial + (destinoFinal - destinoInicial) * fator;
|
|
}
|
|
|
|
private static double Limitar(double valor, double minimo, double maximo)
|
|
{
|
|
return Math.Max(minimo, Math.Min(maximo, valor));
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
public interface ITelaNavegavel
|
|
{
|
|
event EventHandler VoltarSolicitado;
|
|
void AtualizarDadosTela();
|
|
}
|
|
|
|
}
|