agrobot_base/AgroBase/AgroBase/Services/GPSService.cs

310 lines
11 KiB
C#

using AgroBase.Models;
using Emgu.CV.Features2D;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AgroBase.Services
{
public class GPSService
{
public static bool Iniciado = false;
public static SerialPort PortaGPS = null;
public static GPSModel UltimaLeitura = new GPSModel();
public static GPSModel PenultimaLeitura = new GPSModel();
public static void AtualizarPortaGPS(SerialPort _porta)
{
PortaGPS = new SerialPort()
{
PortName = _porta.PortName,
BaudRate = _porta.BaudRate,
};
PortaGPS.DataReceived -= PortaGPS_DataReceived;
PortaGPS.DataReceived += PortaGPS_DataReceived;
}
public static void IniciarRecepcaoDados()
{
try
{
if (PortaGPS != null && !PortaGPS.IsOpen)
{
PortaGPS.Open();
if (PortaGPS.IsOpen)
{
Iniciado = true;
}
}
}
catch
{
PortaGPS = null;
}
}
public static void PararRecepcaoDados()
{
if (PortaGPS != null && PortaGPS.IsOpen)
{
PortaGPS.Close();
if (!PortaGPS.IsOpen)
{
Iniciado = false;
}
}
}
private static void PortaGPS_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (PortaGPS.IsOpen)
{
string Recebido = PortaGPS.ReadLine();
if (Recebido.Length > 2)
{
ProcessarStringNMEA(Recebido);
}
}
}
public static void ProcessarStringNMEA(string nmeaString)
{
if (string.IsNullOrWhiteSpace(nmeaString))
return;
string[] parts = nmeaString.Split(',');
switch (parts[0])
{
// Global Positioning System Fix Data
case "$GPGGA":
PenultimaLeitura.Latitude = UltimaLeitura.Latitude;
PenultimaLeitura.Longitude = UltimaLeitura.Longitude;
PenultimaLeitura.Altitude = UltimaLeitura.Altitude;
PenultimaLeitura.PrecisaoHorizontal = UltimaLeitura.PrecisaoHorizontal;
PenultimaLeitura.DataHora = UltimaLeitura.DataHora;
PenultimaLeitura.NumeroSatelites = UltimaLeitura.NumeroSatelites;
PenultimaLeitura.Velocidade = UltimaLeitura.Velocidade;
if (parts[2] != "" && parts[3] != "")
{
UltimaLeitura.Latitude = ConvertToDecimalDegrees(parts[2], parts[3], 2); // ConvertToDouble(parts[2]);
}
if (parts[4] != "" && parts[5] != "")
{
UltimaLeitura.Longitude = ConvertToDecimalDegrees(parts[4], parts[5], 3); // ConvertToDouble(parts[4]);
}
UltimaLeitura.NumeroSatelites = int.TryParse(parts[7], out int numSat) ? numSat : 0;
UltimaLeitura.PrecisaoHorizontal = double.TryParse(parts[8], NumberStyles.Float, CultureInfo.InvariantCulture, out double hdop) ? hdop : 0;
UltimaLeitura.Altitude = ConvertToDouble(parts[9]);
APIService.AtualizarCoordenadasGPS(UltimaLeitura, APIService.GPS_IDcoordenadasRobo);
break;
// Recommended minimum specific GPS/Transit data
case "$GPRMC":
UltimaLeitura.DataHora = ParseDateTime(parts[9], parts[1], -3);
UltimaLeitura.Velocidade = ConvertKnotsToKmh(ConvertToDouble(parts[7]));
break;
// Você pode adicionar mais cases aqui para outros tipos de sentenças NMEA que você deseja processar
}
}
private static double ConvertToDecimalDegrees(string nmeaCoordinate, string direction, int digits)
{
// Divide a string em graus e minutos
int degrees = int.Parse(nmeaCoordinate.Substring(0, digits));
double minutes = double.Parse(nmeaCoordinate.Substring(digits), CultureInfo.InvariantCulture);
// Converte para graus decimais
double decimalDegrees = degrees + (minutes / 60);
// Se a direção for Sul ou Oeste, o valor deve ser negativo
if (direction == "S" || direction == "W")
{
decimalDegrees *= -1;
}
return decimalDegrees;
}
private static double ConvertToDouble(string value)
{
double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out double result);
return result;
}
private static DateTime ParseDateTime(string date, string time, int timeZoneOffset)
{
// DDMMAA, HHMMSS.ss
string dateTimeFormat = "ddMMyyHHmmss.ff";
// Verifica se o formato de data e hora está completo
if (date.Length == 6 && (time.Length == 6 || time.Length == 9))
{
string dateTimeStr = date + time;
if (DateTime.TryParseExact(dateTimeStr, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result))
{
// Ajusta o DateTime para o fuso horário especificado
result = result.AddHours(timeZoneOffset);
return result;
}
}
// Se a conversão falhar, retorne DateTime.MinValue ou lance uma exceção, conforme sua necessidade
return DateTime.MinValue;
}
private static double ConvertKnotsToKmh(double knots)
{
return knots * 1.852;
}
public static double CalcularOrientacao(GPSModel P1, GPSModel P2)
{
// Converter latitudes e longitudes de graus para radianos
double latA = P1.Latitude * (Math.PI / 180.0);
double lonA = P1.Longitude * (Math.PI / 180.0);
double latB = P2.Latitude * (Math.PI / 180.0);
double lonB = P2.Longitude * (Math.PI / 180.0);
// Calcular a diferença de longitude
double deltaLon = lonB - lonA;
// Calcular a direção
double y = Math.Sin(deltaLon) * Math.Cos(latB);
double x = Math.Cos(latA) * Math.Sin(latB) - Math.Sin(latA) * Math.Cos(latB) * Math.Cos(deltaLon);
double direcaoRadianos = Math.Atan2(y, x);
// Converter a direção de radianos para graus
double direcaoGraus = direcaoRadianos * (180.0 / Math.PI);
// Normalizar a direção para que esteja no intervalo de 0 a 360 graus
direcaoGraus = (direcaoGraus + 360) % 360;
return direcaoGraus;
}
public static double DistanciaEntrePontos(GPSModel P1, GPSModel P2)
{
double lat1 = P1.Latitude;
double lat2 = P2.Latitude;
double lon1 = P1.Longitude;
double lon2 = P2.Longitude;
double R = 6371.0; // Raio da Terra em Km
double dLat = ToRadians(lat2 - lat1);
double dLon = ToRadians(lon2 - lon1);
lat1 = ToRadians(lat1);
lat2 = ToRadians(lat2);
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Sin(dLon / 2) * Math.Sin(dLon / 2) * Math.Cos(lat1) * Math.Cos(lat2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
double distance = R * c;
// Converter para centímetros
distance = distance * 1000;
//distance = distance * 0.5;
return distance;
}
public static double DistanciaDoTrecho(List<GPSModel> Trecho)
{
double d = 0;
for (int i = 0; i < Trecho.Count - 1; i++)
{
d += DistanciaEntrePontos(Trecho[i], Trecho[i + 1]);
}
return d;
}
private static double ToRadians(double angle)
{
return Math.PI / 180 * angle;
}
private static MapaFeatureCollectionModel TrajetoFake = new MapaFeatureCollectionModel();
private static int idxPonto = 0;
private static int idxRuaA = 0;
public static void SimularGPS()
{
var dados = File.ReadAllText("trajetoFakeGps.json");
TrajetoFake = JsonConvert.DeserializeObject<MapaFeatureCollectionModel>(dados);
int i = 0;
TrajetoFake.features.ForEach(feature =>
{
feature.geometry.id = i.ToString();
i++;
});
Timer tmr = new Timer() { Interval = 1000 };
tmr.Tick += Tmr_Tick;
tmr.Start();
Iniciado = true;
}
private static void Tmr_Tick(object sender, EventArgs e)
{
if (Variaveis.OperacaoEmAndamento.Mapa.IdxRuaAtual >= TrajetoFake.features.Count) // Verifica se chegou ao fim do trajeto total
{
((Timer)sender).Stop();
Iniciado = false;
return; // Encerra a execução para evitar processamento adicional
}
if (idxRuaA != Variaveis.OperacaoEmAndamento.Mapa.IdxRuaAtual)
{
idxPonto = 0;
idxRuaA = Variaveis.OperacaoEmAndamento.Mapa.IdxRuaAtual;
//double distPP = DistanciaEntrePontos(UltimaLeitura, new GPSModel() { Longitude = TrajetoFake.features[idxRuaA].geometry.coordinates[0][0], Latitude = TrajetoFake.features[idxRuaA].geometry.coordinates[0][1] });
//double distUP = DistanciaEntrePontos(UltimaLeitura, new GPSModel() { Longitude = TrajetoFake.features[idxRuaA].geometry.coordinates[TrajetoFake.features[idxRuaA].geometry.coordinates.Count - 1][0], Latitude = TrajetoFake.features[idxRuaA].geometry.coordinates[TrajetoFake.features[idxRuaA].geometry.coordinates.Count - 1][1] });
if (idxRuaA % 2 != 0)
{
TrajetoFake.features[idxRuaA].geometry.coordinates.Reverse();
}
}
UltimaLeitura = new GPSModel()
{
DataHora = DateTime.Now,
Longitude = TrajetoFake.features[idxRuaA].geometry.coordinates[idxPonto][0],
Latitude = TrajetoFake.features[idxRuaA].geometry.coordinates[idxPonto][1],
};
APIService.AtualizarCoordenadasGPS(UltimaLeitura, APIService.GPS_IDcoordenadasRobo);
if (Variaveis.OperacaoEmAndamento.Tempo.Minutes == 0 && Variaveis.OperacaoEmAndamento.Tempo.Seconds < Variaveis.OperacaoEmAndamento.TempoIniciarOperacao)
{
return;
}
if (idxPonto < TrajetoFake.features[idxRuaA].geometry.coordinates.Count - 1)
{
idxPonto++;
}
}
}
}