366 lines
13 KiB
C#
366 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using static AgroBase.Models.Enums;
|
|
|
|
namespace AgroBase.Models.Operadores
|
|
{
|
|
public class VisualWorkerModel
|
|
{
|
|
public bool Iniciado { get; set; }
|
|
public DateTime IniciadoEm { get; set; }
|
|
public bool Pronto { get; set; }
|
|
public DateTime ProntoEm { get; set; }
|
|
public VisualWorkerMessageModel UltimaMensagem { get; set; }
|
|
public VisualWorkerMessageModel Leitura { get; set; } = new VisualWorkerMessageModel();
|
|
|
|
public void ReiniciarEstado()
|
|
{
|
|
Iniciado = false;
|
|
IniciadoEm = DateTime.MinValue;
|
|
Pronto = false;
|
|
ProntoEm = DateTime.MinValue;
|
|
UltimaMensagem = new VisualWorkerMessageModel();
|
|
Leitura = new VisualWorkerMessageModel();
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageModel
|
|
{
|
|
public DateTime _Momento { get; set; } = DateTime.MinValue;
|
|
public long momento { get; set; }
|
|
public VisualWorkerMessageType tipo_cmd { get; set; }
|
|
public VisualWorkerCommandType cmd { get; set; }
|
|
public VisualWorkerMessageResponseModel obj { get; set; } = new VisualWorkerMessageResponseModel();
|
|
public dynamic payload { get; set; }
|
|
}
|
|
|
|
public class VisualWorkerMessageResponseModel
|
|
{
|
|
public OAKCameraModel device_status { get; set; }
|
|
public VisualWorkerMessageFrameModel rgb_frame { get; set; }
|
|
public VisualWorkerMessageFrameModel heatmap_frame { get; set; }
|
|
public VisualWorkerMessageFrameModel debug_frame { get; set; }
|
|
public VisualWorkerMessageSetupModel ping { get; set; }
|
|
public VisualWorkerMessageSetupModel calibragem { get; set; }
|
|
public VisualWorkerMessageObstaculosModel obstaculos { get; set; }
|
|
public VisualWorkerMessageCorredorModel corredor { get; set; }
|
|
public VisualWorkerMessageMapaProfundidadeModel mapa_profundidade { get; set; }
|
|
public VisualWorkerMessageObstaculos3DModel obstaculos_3d { get; set; }
|
|
public VisualWorkerMessageAnaliseModel analise { get; set; } = new VisualWorkerMessageAnaliseModel();
|
|
}
|
|
|
|
public class VisualWorkerMessageFrameModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public string frame { get; set; }
|
|
public Bitmap image { get; set; } = null;
|
|
public VisualWorkerMessageFrameModel Clone()
|
|
{
|
|
return new VisualWorkerMessageFrameModel()
|
|
{
|
|
timestamp = timestamp,
|
|
frame = frame,
|
|
image = FuncoesGlobais.Base64ToBitmap(frame),
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageSetupModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public bool status { get; set; }
|
|
public VisualWorkerMessageSetupModel Clone()
|
|
{
|
|
return new VisualWorkerMessageSetupModel()
|
|
{
|
|
timestamp = timestamp,
|
|
status = status,
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageObstaculosModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public bool precisa_micro { get; set; }
|
|
public bool alerta { get; set; }
|
|
public int quantidade { get; set; }
|
|
public bool frontal_bloqueado { get; set; }
|
|
public Dictionary<Direcao, bool> laterais { get; set; }
|
|
public Direcao zona_livre { get; set; }
|
|
public double distancia_minima { get; set; }
|
|
public List<VisualWorkerMessageGridModel> detalhes { get; set; }
|
|
public VisualWorkerMessageObstaculosModel Clone()
|
|
{
|
|
return new VisualWorkerMessageObstaculosModel()
|
|
{
|
|
timestamp = timestamp,
|
|
precisa_micro = precisa_micro,
|
|
alerta = alerta,
|
|
quantidade = quantidade,
|
|
frontal_bloqueado = frontal_bloqueado,
|
|
laterais = new Dictionary<Direcao, bool>(laterais),
|
|
zona_livre = zona_livre,
|
|
distancia_minima = distancia_minima,
|
|
detalhes = new List<VisualWorkerMessageGridModel>(detalhes)
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageGridModel
|
|
{
|
|
public int linha { get; set; }
|
|
public int coluna { get; set; }
|
|
public double distancia { get; set; }
|
|
public VisualWorkerDetectionType tipo { get; set; }
|
|
public VisualWorkerRegionType regiao { get; set; }
|
|
}
|
|
|
|
public class VisualWorkerMessageCorredorModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public double largura_corredor_mm { get; set; }
|
|
public double posicao_central_fracao { get; set; }
|
|
public double[][] pontos_debug { get; set; }
|
|
public VisualWorkerMessageCorredorModel Clone()
|
|
{
|
|
return new VisualWorkerMessageCorredorModel()
|
|
{
|
|
timestamp = timestamp,
|
|
largura_corredor_mm = largura_corredor_mm,
|
|
posicao_central_fracao = posicao_central_fracao,
|
|
pontos_debug = pontos_debug
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageMapaProfundidadeModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public string resolucao { get; set; }
|
|
public string unidade { get; set; }
|
|
public double?[][] grid { get; set; }
|
|
public VisualWorkerMessageMapaProfundidadeModel Clone()
|
|
{
|
|
return new VisualWorkerMessageMapaProfundidadeModel()
|
|
{
|
|
timestamp = timestamp,
|
|
resolucao = resolucao,
|
|
unidade = unidade,
|
|
grid = grid
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageObstaculos3DModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public List<VisualWorkerMessageObstaculos3DDetectadosModel> obstaculos_detectados { get; set; }
|
|
public VisualWorkerMessageObstaculos3DModel Clone()
|
|
{
|
|
return new VisualWorkerMessageObstaculos3DModel()
|
|
{
|
|
timestamp = timestamp,
|
|
obstaculos_detectados = new List<VisualWorkerMessageObstaculos3DDetectadosModel>(obstaculos_detectados)
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageObstaculos3DDetectadosModel
|
|
{
|
|
public double posicao { get; set; }
|
|
public double distancia { get; set; }
|
|
public int largura_px { get; set; }
|
|
}
|
|
|
|
public class VisualWorkerMessageAnaliseModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public List<VisualWorkerMessageAnaliseBBoxModel> anomalias { get; set; }
|
|
public VisualWorkerMessageAnaliseSoloModel solo { get; set; }
|
|
public VisualWorkerMessageAnaliseModel Clone()
|
|
{
|
|
return new VisualWorkerMessageAnaliseModel()
|
|
{
|
|
timestamp = timestamp,
|
|
anomalias = new List<VisualWorkerMessageAnaliseBBoxModel>(anomalias),
|
|
solo = solo.Clone(),
|
|
};
|
|
}
|
|
|
|
public Bitmap PlotarAnalise(VisualWorkerMessageFrameModel frame)
|
|
{
|
|
if (frame?.image == null) return null;
|
|
|
|
try { frame.image.Clone(); } catch { return null; }
|
|
|
|
Bitmap img = new Bitmap(frame.image);
|
|
using (Graphics g = Graphics.FromImage(img))
|
|
{
|
|
Pen penObstaculo = new Pen(Color.Red, 2);
|
|
Pen penErosao = new Pen(Color.Blue, 2);
|
|
Pen penLombada = new Pen(Color.Orange, 2);
|
|
Pen penFaixaSolo = new Pen(Color.Black, 2);
|
|
Pen penGrafico = new Pen(Color.DarkGreen, 2);
|
|
|
|
Font font = new Font("Arial", 8);
|
|
Brush brush = Brushes.Black;
|
|
|
|
// 🔸 Definir brushes semi-transparentes para preenchimento
|
|
Brush brushObstaculo = new SolidBrush(Color.FromArgb(60, Color.Red));
|
|
Brush brushErosao = new SolidBrush(Color.FromArgb(60, Color.Blue));
|
|
Brush brushLombada = new SolidBrush(Color.FromArgb(60, Color.Orange));
|
|
|
|
int imgWidth = img.Width;
|
|
int imgHeight = img.Height;
|
|
|
|
// 🔸 Desenhar Bounding Boxes (Anomalias + Solo)
|
|
List<VisualWorkerMessageAnaliseBBoxModel> bboxes = new List<VisualWorkerMessageAnaliseBBoxModel>();
|
|
if (anomalias != null) bboxes.AddRange(anomalias);
|
|
if (solo?.bbox_list != null) bboxes.AddRange(solo.bbox_list);
|
|
|
|
foreach (var bbox in bboxes)
|
|
{
|
|
Pen pen = penObstaculo;
|
|
Brush fill = brushObstaculo;
|
|
|
|
if (bbox.tipo == "erosao")
|
|
{
|
|
pen = penErosao;
|
|
fill = brushErosao;
|
|
}
|
|
if (bbox.tipo == "lombada")
|
|
{
|
|
pen = penLombada;
|
|
fill = brushLombada;
|
|
}
|
|
|
|
var rect = new Rectangle(bbox.bbox[0], bbox.bbox[1], bbox.bbox[2], bbox.bbox[3]);
|
|
|
|
// 🔸 Preencher com opacidade
|
|
g.FillRectangle(fill, rect);
|
|
|
|
// 🔸 Contorno
|
|
g.DrawRectangle(pen, rect);
|
|
|
|
// 🔸 Label
|
|
string label = $"{bbox.tipo} {bbox.distancia_m}m Δ{bbox.variacao}mm";
|
|
g.DrawString(label, font, brush, rect.X, rect.Y - 12);
|
|
}
|
|
|
|
// 🔸 Linha da faixa do solo
|
|
if (solo != null)
|
|
{
|
|
int yInicio = solo.y_inicio;
|
|
g.DrawLine(penFaixaSolo, 0, yInicio, imgWidth, yInicio);
|
|
}
|
|
|
|
// 🔸 Gráfico do perfil de solo
|
|
if (solo?.perfil != null && solo.perfil.Count > 1)
|
|
{
|
|
var perfil = solo.perfil;
|
|
int setores = solo.n_setores;
|
|
int yInicio = solo.y_inicio;
|
|
int alturaRegiao = solo.altura_regiao;
|
|
|
|
double maxZ = perfil.Max();
|
|
double minZ = perfil.Min();
|
|
if (maxZ == minZ) maxZ += 1; // evita divisão por zero
|
|
|
|
for (int i = 0; i < perfil.Count - 1; i++)
|
|
{
|
|
float x1 = (float)(i * imgWidth / setores + imgWidth / (2.0 * setores));
|
|
float x2 = (float)((i + 1) * imgWidth / setores + imgWidth / (2.0 * setores));
|
|
|
|
float y1 = (float)(yInicio + alturaRegiao - ((perfil[i] - minZ) / (maxZ - minZ)) * alturaRegiao);
|
|
float y2 = (float)(yInicio + alturaRegiao - ((perfil[i + 1] - minZ) / (maxZ - minZ)) * alturaRegiao);
|
|
|
|
g.DrawLine(penGrafico, x1, y1, x2, y2);
|
|
g.FillEllipse(Brushes.DarkGreen, x1 - 3, y1 - 3, 6, 6);
|
|
}
|
|
|
|
// Desenha o último ponto
|
|
float xLast = (float)((perfil.Count - 1) * imgWidth / setores + imgWidth / (2.0 * setores));
|
|
float yLast = (float)(yInicio + alturaRegiao - ((perfil.Last() - minZ) / (maxZ - minZ)) * alturaRegiao);
|
|
g.FillEllipse(Brushes.DarkGreen, xLast - 3, yLast - 3, 6, 6);
|
|
}
|
|
}
|
|
|
|
return img;
|
|
}
|
|
|
|
}
|
|
|
|
public class VisualWorkerMessageAnaliseSoloModel
|
|
{
|
|
public List<double> perfil { get; set; }
|
|
public List<VisualWorkerMessageAnaliseBBoxModel> bbox_list { get; set; }
|
|
public int y_inicio { get; set; }
|
|
public int altura_regiao { get; set; }
|
|
public int n_setores { get; set; }
|
|
public VisualWorkerMessageAnaliseSoloModel Clone()
|
|
{
|
|
return new VisualWorkerMessageAnaliseSoloModel()
|
|
{
|
|
perfil = new List<double>(perfil),
|
|
bbox_list = new List<VisualWorkerMessageAnaliseBBoxModel>(bbox_list),
|
|
y_inicio = y_inicio,
|
|
altura_regiao = altura_regiao,
|
|
n_setores = n_setores
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageAnaliseBBoxModel
|
|
{
|
|
public string tipo { get; set; }
|
|
public List<int> bbox { get; set; } // [x, y, w, h]
|
|
public List<double> centro_percentual { get; set; } // [x%, y%]
|
|
public double? distancia_m { get; set; }
|
|
public double? largura_m { get; set; }
|
|
public double? altura_m { get; set; }
|
|
public List<double> profundidades { get; set; } // [z1, z2] ou null
|
|
public double? variacao { get; set; } // delta Z ou null
|
|
}
|
|
|
|
public enum VisualWorkerMessageType
|
|
{
|
|
TX = 1,
|
|
RX = 2
|
|
}
|
|
|
|
public enum VisualWorkerCommandType
|
|
{
|
|
Ping = 1,
|
|
Get_Status_Dispositivo = 2,
|
|
Get_RGB_Frame = 3,
|
|
Get_Heatmap_Frame = 4,
|
|
Calibrar_Grades = 5,
|
|
Get_Analise_Anomalia = 6,
|
|
Get_Analise_Solo = 7,
|
|
}
|
|
|
|
public enum VisualWorkerDetectionType
|
|
{
|
|
Seguro = 1,
|
|
Obstaculo = 2,
|
|
Depressao = 3,
|
|
}
|
|
|
|
public enum VisualWorkerRegionType
|
|
{
|
|
Solo = 1,
|
|
Aereo = 2,
|
|
}
|
|
|
|
public enum VisualWorkerAnaliseType
|
|
{
|
|
Anomalia = 1,
|
|
Solo = 2,
|
|
}
|
|
|
|
}
|