otimizado o simulador
This commit is contained in:
parent
024eceef60
commit
1e7b725422
File diff suppressed because it is too large
Load Diff
|
|
@ -1959,7 +1959,7 @@ namespace AgroBase.Models
|
|||
var dispMvd = DispMvd;
|
||||
|
||||
if (dispMvd?.Dados?.Modulos != null) // && value != Controle.TipoMovimento
|
||||
{
|
||||
{
|
||||
Controle.DefinirTipoMovimento(value, dispMvd.Dados.Modulos);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using System.Net.Sockets;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static AgroBase.Models.Enums;
|
||||
|
||||
namespace AgroBase.Services
|
||||
|
|
@ -171,6 +172,94 @@ namespace AgroBase.Services
|
|||
private static string _lastError;
|
||||
private static readonly object _metricsTextLock = new object();
|
||||
|
||||
|
||||
|
||||
private const int IntervaloTrajetoriaMapaMs = 1_000;
|
||||
private const int MaxPontosTrajetoriaMapa = 800;
|
||||
|
||||
private static int _publicacaoMapaAutomaticaHabilitada = 1;
|
||||
private static long _ultimaTrajetoriaMapaMono;
|
||||
|
||||
/// <summary>
|
||||
/// Permite que uma tela seja dona da publicação visual sem interromper o
|
||||
/// processamento GNSS, Redis, trajetória ou histórico da operação.
|
||||
/// O valor padrão preserva o comportamento legado.
|
||||
/// </summary>
|
||||
public static bool PublicacaoMapaAutomaticaHabilitada
|
||||
{
|
||||
get
|
||||
{
|
||||
return Volatile.Read(
|
||||
ref _publicacaoMapaAutomaticaHabilitada
|
||||
) == 1;
|
||||
}
|
||||
set
|
||||
{
|
||||
Volatile.Write(
|
||||
ref _publicacaoMapaAutomaticaHabilitada,
|
||||
value ? 1 : 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AtualizarLeituraSimulada(GPSModel leitura, int atrasoPosicaoPassos = 0)
|
||||
{
|
||||
if (leitura == null)
|
||||
throw new ArgumentNullException(nameof(leitura));
|
||||
|
||||
lock (_stateLock)
|
||||
{
|
||||
double orientacaoReal =
|
||||
GPSUtils.NormalizarAngulo(leitura.OrientacaoReal);
|
||||
|
||||
UltimaLeitura.Momento = leitura.Momento;
|
||||
UltimaLeitura.DataHora = leitura.DataHora;
|
||||
UltimaLeitura.UltimoComandoRespondido =
|
||||
leitura.UltimoComandoRespondido;
|
||||
|
||||
UltimaLeitura.Latitude = leitura.Latitude;
|
||||
UltimaLeitura.Longitude = leitura.Longitude;
|
||||
UltimaLeitura.LatitudeAnt = leitura.LatitudeAnt;
|
||||
UltimaLeitura.LongitudeAnt = leitura.LongitudeAnt;
|
||||
|
||||
UltimaLeitura.OrientacaoReal = orientacaoReal;
|
||||
UltimaLeitura.AnguloCarroDefinido = orientacaoReal;
|
||||
UltimaLeitura.TipoOrientacao = "A";
|
||||
|
||||
UltimaLeitura.OrientacaoMovimento =
|
||||
double.IsNaN(leitura.OrientacaoMovimento) ||
|
||||
double.IsInfinity(leitura.OrientacaoMovimento)
|
||||
? orientacaoReal
|
||||
: GPSUtils.NormalizarAngulo(
|
||||
leitura.OrientacaoMovimento
|
||||
);
|
||||
|
||||
UltimaLeitura.Distancia = leitura.Distancia;
|
||||
UltimaLeitura.Velocidade = leitura.Velocidade;
|
||||
|
||||
if (leitura.TimestampOri != null)
|
||||
UltimaLeitura.TimestampOri =
|
||||
leitura.TimestampOri.Clone();
|
||||
|
||||
if (leitura.TimestampPos != null)
|
||||
UltimaLeitura.TimestampPos =
|
||||
leitura.TimestampPos.Clone();
|
||||
|
||||
UltimaLeitura.Heartbeat = leitura.Heartbeat;
|
||||
UltimaLeitura.Inicializado = true;
|
||||
|
||||
// Monitor/lock do C# é reentrante; os dois métodos abaixo usam o
|
||||
// mesmo lock e permanecem em uma única transação de leitura GNSS.
|
||||
AtualizarAtrasoPosicoes(
|
||||
Math.Max(0, atrasoPosicaoPassos)
|
||||
);
|
||||
AtualizarCoordenadasGPS();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ============================================================
|
||||
// INICIALIZAÇÃO DA PORTA
|
||||
// ============================================================
|
||||
|
|
@ -2198,14 +2287,30 @@ namespace AgroBase.Services
|
|||
op.Trajetoria.LoopAtualizaDados();
|
||||
}
|
||||
|
||||
AtualizarTrajetoriaDinamica();
|
||||
|
||||
EnviarCoordenadasParaMapa(UltimaLeitura.Latitude, UltimaLeitura.Longitude, UltimaLeitura.AnguloCarroDefinido, op.Sensoriamento.Operacao.OperacaoIniciada, rover: true);
|
||||
|
||||
GPSModel posicaoBase = VariaveisOperacao.ObterPosicaoBaseSnapshot();
|
||||
if ((posicaoBase?.UltimoComandoRespondido ?? DateTime.MinValue) > DateTime.UtcNow.AddSeconds(-60))
|
||||
if (PublicacaoMapaAutomaticaHabilitada)
|
||||
{
|
||||
EnviarCoordenadasParaMapa(posicaoBase.Latitude, posicaoBase.Longitude, posicaoBase.OrientacaoReal, false, rover: false);
|
||||
AtualizarTrajetoriaDinamica();
|
||||
|
||||
EnviarCoordenadasParaMapa(
|
||||
UltimaLeitura.Latitude,
|
||||
UltimaLeitura.Longitude,
|
||||
UltimaLeitura.AnguloCarroDefinido,
|
||||
op.Sensoriamento.Operacao.OperacaoIniciada,
|
||||
rover: true
|
||||
);
|
||||
|
||||
GPSModel posicaoBase = VariaveisOperacao.ObterPosicaoBaseSnapshot();
|
||||
|
||||
if ((posicaoBase?.UltimoComandoRespondido ?? DateTime.MinValue) > DateTime.UtcNow.AddSeconds(-60))
|
||||
{
|
||||
EnviarCoordenadasParaMapa(
|
||||
posicaoBase.Latitude,
|
||||
posicaoBase.Longitude,
|
||||
posicaoBase.OrientacaoReal,
|
||||
false,
|
||||
rover: false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PenultimaLeitura.Inicializado = UltimaLeitura.Inicializado;
|
||||
|
|
@ -2221,29 +2326,172 @@ namespace AgroBase.Services
|
|||
// PUBLICAÇÃO LOCAL LATEST-ONLY
|
||||
// ============================================================
|
||||
|
||||
public static void EnviarCoordenadasParaMapa(double Latitude, double Longitude, double Orientacao, bool EmFoco, bool rover)
|
||||
public static void EnviarCoordenadasParaMapa(double latitude, double longitude, double orientacao, bool emFoco, bool rover)
|
||||
{
|
||||
int ID = rover ? MapasVariaveisModel.IDMarcadorRover : MapasVariaveisModel.IDMarcadorBase;
|
||||
Variaveis.OperacaoEmAndamento?.Mapa?.AtualizarPosicaoMapaAsync(ID, Latitude, Longitude, Orientacao, EmFoco);
|
||||
MapasModel mapa = Variaveis.OperacaoEmAndamento?.Mapa;
|
||||
Panel painel = mapa?.pnlMapa;
|
||||
|
||||
// Produto headless: retorna antes de tocar no WebView.
|
||||
if (painel == null || painel.IsDisposed || !painel.IsHandleCreated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int id = rover
|
||||
? MapasVariaveisModel.IDMarcadorRover
|
||||
: MapasVariaveisModel.IDMarcadorBase;
|
||||
|
||||
ExecutarMapaNaUi(
|
||||
mapa,
|
||||
delegate
|
||||
{
|
||||
Task tarefa = mapa.AtualizarPosicaoMapaAsync(
|
||||
id,
|
||||
latitude,
|
||||
longitude,
|
||||
orientacao,
|
||||
emFoco
|
||||
);
|
||||
|
||||
ObservarFalhaMapa(
|
||||
tarefa,
|
||||
"GPSService.EnviarCoordenadasParaMapa"
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static void AtualizarTrajetoriaDinamica()
|
||||
{
|
||||
var op = Variaveis.OperacaoEmAndamento;
|
||||
var trajetoria = op?.Trajetoria;
|
||||
MapasModel mapa = op?.Mapa;
|
||||
Panel painel = mapa?.pnlMapa;
|
||||
|
||||
var dinamica = op.Trajetoria?._TrajetoriaDinamica;
|
||||
// No produto sem UI, não cria cópia nem serializa a trajetória.
|
||||
if (trajetoria == null || painel == null || painel.IsDisposed || !painel.IsHandleCreated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(dinamica?.Any() ?? false))
|
||||
long anterior = Interlocked.Read(ref _ultimaTrajetoriaMapaMono);
|
||||
|
||||
if (GetAgeMs(anterior) < IntervaloTrajetoriaMapaMs)
|
||||
return;
|
||||
|
||||
var trajetoria = op.Trajetoria.TrajetoriaDinamica.Select(x => new
|
||||
{
|
||||
latitude = x.Latitude,
|
||||
longitude = x.Longitude
|
||||
})
|
||||
.ToArray();
|
||||
long agora = Stopwatch.GetTimestamp();
|
||||
|
||||
op?.Mapa?.DefinirTrajetoriaPlanejadaAsync(op.Trajetoria.TrajetoriaDinamica);
|
||||
// Caso duas leituras cheguem juntas, somente uma publica.
|
||||
if (Interlocked.CompareExchange(ref _ultimaTrajetoriaMapaMono, agora, anterior) != anterior)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<GPSModel> pontos = CriarTrajetoriaMapaVisual(trajetoria._TrajetoriaDinamica, MaxPontosTrajetoriaMapa);
|
||||
|
||||
if (pontos.Count == 0)
|
||||
return;
|
||||
|
||||
ExecutarMapaNaUi(
|
||||
mapa,
|
||||
delegate
|
||||
{
|
||||
Task tarefa = mapa.DefinirTrajetoriaPlanejadaAsync(pontos);
|
||||
|
||||
ObservarFalhaMapa(
|
||||
tarefa,
|
||||
"GPSService.AtualizarTrajetoriaDinamica"
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static List<GPSModel> CriarTrajetoriaMapaVisual(IList<PontoTrajetoriaModel> origem, int limite)
|
||||
{
|
||||
var resultado = new List<GPSModel>();
|
||||
|
||||
if (origem == null || origem.Count == 0)
|
||||
return resultado;
|
||||
|
||||
int count = origem.Count;
|
||||
int passo = Math.Max(1, (int)Math.Ceiling(count / (double)Math.Max(2, limite)));
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
PontoTrajetoriaModel ponto = origem[i];
|
||||
|
||||
if (ponto?.Posicao == null)
|
||||
continue;
|
||||
|
||||
bool estrutural =
|
||||
ponto.PontoBorda ||
|
||||
ponto.PontoLigacao ||
|
||||
ponto.Tipo == TipoPontoRua.BordaEntrada ||
|
||||
ponto.Tipo == TipoPontoRua.BordaSaida ||
|
||||
ponto.Tipo == TipoPontoRua.LigacaoEntrada ||
|
||||
ponto.Tipo == TipoPontoRua.LigacaoSaida;
|
||||
|
||||
if (i != 0 && i != count - 1 && !estrutural && i % passo != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
resultado.Add(new GPSModel()
|
||||
{
|
||||
Latitude = ponto.Posicao.Latitude,
|
||||
Longitude = ponto.Posicao.Longitude
|
||||
});
|
||||
}
|
||||
|
||||
return resultado;
|
||||
}
|
||||
|
||||
private static void ExecutarMapaNaUi(MapasModel mapa, Action acao)
|
||||
{
|
||||
Panel painel = mapa?.pnlMapa;
|
||||
|
||||
if (acao == null || painel == null || painel.IsDisposed || !painel.IsHandleCreated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (painel.InvokeRequired)
|
||||
{
|
||||
painel.BeginInvoke(acao);
|
||||
return;
|
||||
}
|
||||
|
||||
acao();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// A janela pode estar fechando entre as validações.
|
||||
}
|
||||
}
|
||||
|
||||
private static void ObservarFalhaMapa(Task tarefa, string origem)
|
||||
{
|
||||
if (tarefa == null)
|
||||
return;
|
||||
|
||||
_ = tarefa.ContinueWith(
|
||||
t =>
|
||||
{
|
||||
Exception erro = t.Exception?.GetBaseException();
|
||||
RecordError(
|
||||
"[" + origem + "] " +
|
||||
(erro?.Message ?? "Falha desconhecida no mapa.")
|
||||
);
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskContinuationOptions.OnlyOnFaulted,
|
||||
TaskScheduler.Default
|
||||
);
|
||||
}
|
||||
|
||||
private static async Task LocalPublisherLoopAsync(CancellationToken cancellationToken)
|
||||
|
|
|
|||
Loading…
Reference in New Issue