310 lines
11 KiB
C#
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++;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|