agrobot_base/AgroBase/AgroBase/Forms/frmOperarioSonar.cs

373 lines
15 KiB
C#

using AgroBase.Models;
using AgroBase.Models.Operadores;
using AgroBase.Services.Operadores;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace AgroBase.Forms
{
public partial class frmOperarioSonar : Form
{
AsyncTaskTimerModel tmrLeitura;
public frmOperarioSonar()
{
InitializeComponent();
pnlInclinacao.GetType().GetMethod("SetStyle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(pnlInclinacao, new object[] { ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true });
}
private void frmOperarioSonar_Load(object sender, EventArgs e)
{
AtualizarListaCameras();
ConfigurarGridDeteccoes(dgvAnomalias);
ConfigurarGridDeteccoes(dgvSolo);
tmrLeitura = new AsyncTaskTimerModel("tmrLeitura_VisalWorker", tmrLeitura_Tick, 100, this);
tmrLeitura.Start();
}
private async void frmOperarioSonar_FormClosing(object sender, FormClosingEventArgs e)
{
tmrLeitura?.Stop();
}
private void AtualizarListaCameras()
{
cmbCameras.Items.Clear();
cmbCameras.Items.AddRange(CameraWorkerService.GetListaCameras().Select(x => x.Name).ToArray());
cmbCameras.SelectedIndex = -1;
}
private async Task tmrLeitura_Tick()
{
if (!chbReqAutomatico.Checked) return;
/*btnLeituraIMU_Click(new object(), new EventArgs());
EnviarComandoReqFrame(VisualWorkerCommandType.Get_RGB_Frame);
EnviarComandoReqFrame(VisualWorkerCommandType.Get_Heatmap_Frame);
EnviarComandoAnalise(VisualWorkerCommandType.Get_Analise_Anomalia);
EnviarComandoAnalise(VisualWorkerCommandType.Get_Analise_Solo);
EnviarComandoReqFrame(VisualWorkerCommandType.Get_Radar_2D);
EnviarComandoReqFrame(VisualWorkerCommandType.Get_Segmentacao_Semantica);*/
}
private async void btnAtualizarCameras_Click(object sender, EventArgs e)
{
AtualizarListaCameras();
}
private async void btnIniciarProcessamento_Click(object sender, EventArgs e)
{
}
private void btnPing_Click(object sender, EventArgs e)
{
//EnviarComando(VisualWorkerCommandType.Ping);
}
private void btnCalibrarGrades_Click(object sender, EventArgs e)
{
VisualWorkerService.RecalibrarGridProfundidade();
}
private async void btnLeituraRGB_Click(object sender, EventArgs e)
{
EnviarComandoReqFrame(CameraFrameType.Rgb);
}
private void btnLeituraHeatmap_Click(object sender, EventArgs e)
{
EnviarComandoReqFrame(CameraFrameType.Heatmap);
}
private void btnLeituraRadar2D_Click(object sender, EventArgs e)
{
EnviarComandoReqFrame(CameraFrameType.RadarTopDown);
}
private void btnLeituraSegmentacaoSemantica_Click(object sender, EventArgs e)
{
EnviarComandoReqFrame(CameraFrameType.Segmentacao);
}
private async void EnviarComandoReqFrame(CameraFrameType tipo)
{
OAKCameraFrameModel frame = await VisualWorkerService.GetCameraFrame(tipo);
PictureBox pic =
tipo == CameraFrameType.Rgb ? picRGB :
tipo == CameraFrameType.Heatmap ? picHeatmap :
tipo == CameraFrameType.RadarTopDown ? picRadar2D :
tipo == CameraFrameType.Segmentacao ? picSegmentacaoSemantica :
new PictureBox();
Label lbl =
tipo == CameraFrameType.Rgb ? lblLeituraRGB :
tipo == CameraFrameType.Heatmap ? lblLeituraHeatmap :
tipo == CameraFrameType.RadarTopDown ? lblLeituraRadar2D :
tipo == CameraFrameType.Segmentacao ? lblLeituraSegmentacaoSemantica :
new Label();
pic.Image?.Dispose();
try { pic.Image = frame?.image(); } catch { }
lbl.Text = $"Leitura em: " + frame?.timestamp.ToString("dd/MM/yyyy HH:mm:ss");
if (tipo == CameraFrameType.RadarTopDown && VisualWorkerService.DadosLeitura.Analises != null)
{
//pic.Image = VariaveisOperacao.Operadores.VisualWorker.DadosLeitura.Leitura.obj.radar_2d.PlotarAnalsie(frame.image);
//PlotarGraficoPerfilCorredor(VisualWorkerService.DadosLeitura.Analises.corredor_prof);
}
}
private void btnReqStatusDispositivo_Click(object sender, EventArgs e)
{
//EnviarComando(VisualWorkerCommandType.Get_Status_Dispositivo);
}
private void btnReqAnomalias_Click(object sender, EventArgs e)
{
AtualizarDadosAnalise();
}
private void btnReqSolo_Click(object sender, EventArgs e)
{
AtualizarDadosAnalise();
}
private async void btnLeituraIMU_Click(object sender, EventArgs e)
{
pnlInclinacao.Invalidate();
lblLeituraIMU.Text = $"Leitura em: {FuncoesGlobais.TimestampToDate(VisualWorkerService.DadosLeitura.Imu?.timestamp ?? 0)}";
}
private void AtualizarDadosAnalise()
{
var analise = VisualWorkerService.DadosLeitura.Analises;
lblLeituraDebug.Text = $"Leitura em: " + (analise?.timestamp ?? DateTime.MinValue).ToString("dd/MM/yyyy HH:mm:ss");
OAKCameraFrameModel frame = VisualWorkerService.DadosLeitura.CameraFrames[CameraFrameType.Heatmap];
picDebug.Image?.Dispose();
picDebug.Image = analise.PlotarAnalise(frame);
//PreencherGridAnomalias(analise.anomalias ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
//PreencherGridSolo(analise.solo?.bbox_list ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
//PlotarGraficoPerfilSolo(analise.solo?.perfil ?? new List<double>());
}
void ConfigurarGridDeteccoes(DataGridView dgv)
{
dgv.Columns.Clear();
dgv.Columns.Add("Tipo", "Tipo");
dgv.Columns.Add("X", "X");
dgv.Columns.Add("Y", "Y");
dgv.Columns.Add("W", "Largura (px)");
dgv.Columns.Add("H", "Altura (px)");
dgv.Columns.Add("Centro", "Centro (%)");
dgv.Columns.Add("Distancia", "Distância (m)");
dgv.Columns.Add("LarguraM", "Largura (m)");
dgv.Columns.Add("AlturaM", "Altura (m)");
dgv.Columns.Add("Variacao", "Variação (mm)");
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
dgv.ReadOnly = true;
dgv.AllowUserToAddRows = false;
dgv.AllowUserToDeleteRows = false;
}
void PreencherGridAnomalias(List<VisualWorkerMessageAnaliseBBoxModel> bboxes)
{
dgvAnomalias.Rows.Clear();
foreach (var bbox in bboxes)
{
int rowIndex = dgvAnomalias.Rows.Add(
bbox.tipo,
bbox.bbox[0], bbox.bbox[1], bbox.bbox[2], bbox.bbox[3],
$"{bbox.centro_percentual[0]:0.0}%, {bbox.centro_percentual[1]:0.0}%",
bbox.distancia_m?.ToString("0.00") ?? "-",
bbox.largura_m?.ToString("0.00") ?? "-",
bbox.altura_m?.ToString("0.00") ?? "-",
bbox.variacao?.ToString("0.0") ?? "-"
);
if (bbox.distancia_m < 1.0)
{
dgvAnomalias.Rows[rowIndex].DefaultCellStyle.BackColor = Color.LightCoral;
}
}
}
void PreencherGridSolo(List<VisualWorkerMessageAnaliseBBoxModel> bboxes)
{
dgvSolo.Rows.Clear();
foreach (var bbox in bboxes)
{
dgvSolo.Rows.Add(
bbox.tipo,
bbox.bbox[0], bbox.bbox[1], bbox.bbox[2], bbox.bbox[3],
$"{bbox.centro_percentual[0]:0.0}%, {bbox.centro_percentual[1]:0.0}%",
bbox.distancia_m?.ToString("0.00") ?? "-",
bbox.largura_m?.ToString("0.00") ?? "-",
bbox.altura_m?.ToString("0.00") ?? "-",
bbox.variacao?.ToString("0.0") ?? "-"
);
}
}
void PlotarGraficoPerfilSolo(List<double> perfil)
{
if (perfil == null || perfil.Count == 0) return;
chartPerfilSolo.Series.Clear();
var serie = chartPerfilSolo.Series.Add("Perfil");
serie.ChartType = SeriesChartType.Line;
for (int i = 0; i < perfil.Count; i++)
{
serie.Points.AddXY(i + 1, perfil[i]);
}
// 🔸 Calcula os limites com margem
double min = perfil.Min();
double max = perfil.Max();
double margem = 5;
chartPerfilSolo.ChartAreas[0].AxisY.Minimum = min - margem;
chartPerfilSolo.ChartAreas[0].AxisY.Maximum = max + margem;
// (Opcional) Deixa os grids bonitos
chartPerfilSolo.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.LightGray;
chartPerfilSolo.ChartAreas[0].AxisX.MajorGrid.LineColor = Color.LightGray;
// 🔥 Legenda embaixo
chartPerfilSolo.Legends[0].Docking = Docking.Bottom;
}
void PlotarGraficoPerfilCorredor(List<VisualWorkerMessageRadar2DPerfilModel> perfilCorredor)
{
chartCorredor.Series.Clear();
var serieEsquerda = chartCorredor.Series.Add("Esquerda");
var serieDireita = chartCorredor.Series.Add("Direita");
//var serieLargura = chartCorredor.Series.Add("Largura Total");
serieEsquerda.ChartType = SeriesChartType.Line;
serieDireita.ChartType = SeriesChartType.Line;
//serieLargura.ChartType = SeriesChartType.Line;
// Estilo diferenciado pra largura
//serieLargura.BorderDashStyle = ChartDashStyle.Dash;
//serieLargura.Color = Color.Gray;
double maxLado = 0;
foreach (var item in perfilCorredor)
{
double distancia = item.distancia_m;
double esquerda = item.esquerda_m;
double direita = item.direita_m;
double largura = item.largura_m;
// Calcula o maior lado
maxLado = Math.Max(maxLado, Math.Max(esquerda, direita));
// Esquerda negativa
serieEsquerda.Points.AddXY(-esquerda, distancia);
serieDireita.Points.AddXY(direita, distancia);
//serieLargura.Points.AddXY(largura, distancia);
}
// 🔥 Define os limites simétricos
chartCorredor.ChartAreas[0].AxisX.Minimum = -maxLado - 0.1;
chartCorredor.ChartAreas[0].AxisX.Maximum = maxLado + 0.1;
// 🔥 Legenda embaixo
chartCorredor.Legends[0].Docking = Docking.Bottom;
// 🔥 Configurações de eixo
chartCorredor.ChartAreas[0].AxisX.Title = "Espaço Lateral (m)";
chartCorredor.ChartAreas[0].AxisY.Title = "Distância Frente (m)";
chartCorredor.ChartAreas[0].AxisX.MajorGrid.LineColor = Color.LightGray;
chartCorredor.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.LightGray;
chartCorredor.ChartAreas[0].AxisX.Crossing = 0; // 🔥 Eixo X cruza no centro (0 lateral)
}
private void pnlInclinacao_Paint(object sender, PaintEventArgs e)
{
Panel _pnlInclinacao = sender as Panel;
double AnguloX = VisualWorkerService.DadosLeitura.Imu?.roll ?? 0;
double AnguloY = VisualWorkerService.DadosLeitura.Imu?.pitch ?? 0;
Graphics g = e.Graphics;
int centerX = _pnlInclinacao.Width / 2;
int centerY = _pnlInclinacao.Height / 2;
int radius = 10;
// Desenhar fundo com bordas arredondadas
GraphicsPath path = new GraphicsPath();
int cornerRadius = 20;
path.AddArc(0, 0, cornerRadius, cornerRadius, 180, 90);
path.AddArc(_pnlInclinacao.Width - cornerRadius, 0, cornerRadius, cornerRadius, 270, 90);
path.AddArc(_pnlInclinacao.Width - cornerRadius, _pnlInclinacao.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90);
path.AddArc(0, _pnlInclinacao.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90);
path.CloseAllFigures();
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillPath(new SolidBrush(Color.LightBlue), path);
g.DrawPath(new Pen(Color.DarkBlue, 2), path);
// Desenhar linhas de referência
Pen pen = new Pen(Color.Gray, 1);
g.DrawLine(pen, centerX, 0, centerX, _pnlInclinacao.Height);
g.DrawLine(pen, 0, centerY, _pnlInclinacao.Width, centerY);
// Desenhar linhas adicionais para ângulos
for (int i = -90; i <= 90; i += 15)
{
int posX = centerX + (int)(i * (_pnlInclinacao.Width / 2 - radius) / 90);
int posY = centerY - (int)(i * (_pnlInclinacao.Height / 2 - radius) / 90);
g.DrawLine(pen, centerX, centerY, posX, centerY);
g.DrawLine(pen, centerX, centerY, centerX, posY);
}
// Desenhar régua na linha central
for (int i = -90; i <= 90; i += 15)
{
int posX = centerX + (int)(i * (_pnlInclinacao.Width / 2 - radius) / 90);
int posY = centerY - (int)(i * (_pnlInclinacao.Height / 2 - radius) / 90);
// Marcas horizontais
g.DrawLine(pen, posX, centerY - 5, posX, centerY + 5);
g.DrawString(i.ToString(), new Font("Arial", 8), Brushes.Black, posX - 10, centerY + 10);
// Marcas verticais
g.DrawLine(pen, centerX - 5, posY, centerX + 5, posY);
g.DrawString(i.ToString(), new Font("Arial", 8), Brushes.Black, centerX + 10, posY - 5);
}
// Calcular a posição do círculo com base nos ângulos
int circlePosX = centerX + (int)(AnguloX * (_pnlInclinacao.Width / 2 - radius) / 90);
int circlePosY = centerY - (int)(AnguloY * (_pnlInclinacao.Height / 2 - radius) / 90);
// Desenhar o círculo
Brush brush = new SolidBrush(Color.Red);
g.FillEllipse(brush, circlePosX - radius, circlePosY - radius, radius * 2, radius * 2);
}
}
}