From e42e1e6109f74ae72607bc52ea784de142a0483c Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Thu, 26 Mar 2026 22:42:40 -0300 Subject: [PATCH] =?UTF-8?q?Adicionado=20m=C3=A9todo=20de=20retorno=20?= =?UTF-8?q?=C3=A0=20base=20por=20pontos=20manuais?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/Operacoes/OperacaoModel.cs | 14 +- .../Operacoes/OperacaoParametrosModel.cs | 1 + .../Models/TrajetoriaMapaOperacaoModel.cs | 8 +- .../Controls/MapViewControl.xaml.cs | 127 +++++++++++++++++- .../Monitoramento/ParametrizacaoViewModel.cs | 1 + .../Views/Operacao/OperacaoLeftViewModel.cs | 1 + .../ViewModels/Windows/DockWindowViewModel.cs | 53 ++++++-- 7 files changed, 182 insertions(+), 23 deletions(-) diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index 346301ae4..3b8c84652 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -344,6 +344,7 @@ namespace AgroBase.Models IP = VariaveisEquipamento.Parametros.rover_ip, RuasPercorrer = null, Mapa = null, + PontosRetorno = null, DadosLeitura = new OperacaoParametrosDadosModel(), }; @@ -1130,6 +1131,7 @@ namespace AgroBase.Models p.QtdCamerasSolo = Parametros.QtdCamerasSolo; p.Mapa = Parametros.Mapa; p.RuasPercorrer = Parametros.RuasPercorrer; + p.PontosRetorno = Parametros.PontosRetorno; p.ModulosMandatorios = Parametros.ModulosMandatorios; p.ParametrosMandatorios = Parametros.ParametrosMandatorios; @@ -1221,6 +1223,13 @@ namespace AgroBase.Models Variaveis.OperacaoEmAndamento.Finalizando = false; Variaveis.OperacaoEmAndamento.Trajetoria?.AutonomiaCorredor?.Parar(); Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.FinalizarOperacao(); + + if (Variaveis.OperacaoEmAndamento.Parametros.Modo == ModoOperacao.RetornoBase) + { + var p = CarregarParametrosOperacaoPadrao(ModoOperacao.MapaGPS, false); + Variaveis.OperacaoEmAndamento.Parametros = p; + RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false)); + } } public void ReiniciarOperacao(bool daBase) @@ -1835,8 +1844,9 @@ namespace AgroBase.Models if (controleBase.Dispositivo == T_Code.Trj) { var (lat, lon, pontosRetorno) = ((JObject)controleBase._comp_value).ToObject<(double?, double?, List)>(); - if (lat == null || lon == null) return; - GPSModel posicaoBase = new GPSModel() { Latitude = lat.Value, Longitude = lon.Value }; + GPSModel posicaoBase = null; + if (lat != null && lon != null) + posicaoBase = new GPSModel() { Latitude = lat.Value, Longitude = lon.Value }; List pontosRetornoPos = null; if (pontosRetorno?.Any() ?? false) pontosRetornoPos = pontosRetorno.Select(x => new GPSModel() { Latitude = x[0], Longitude = x[1] }).ToList(); diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs index 4074d0f66..a30c165ad 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs @@ -148,6 +148,7 @@ namespace AgroBase.Models.Operacoes public MapaFeatureCollectionModel Mapa { get; set; } public List RuasPercorrer { get; set; } + public List PontosRetorno { get; set; } public OperacaoParametrosDadosModel DadosLeitura { get; set; } diff --git a/AgroBase/AgroBase/Models/TrajetoriaMapaOperacaoModel.cs b/AgroBase/AgroBase/Models/TrajetoriaMapaOperacaoModel.cs index 556fa20d0..fec2132f2 100644 --- a/AgroBase/AgroBase/Models/TrajetoriaMapaOperacaoModel.cs +++ b/AgroBase/AgroBase/Models/TrajetoriaMapaOperacaoModel.cs @@ -1752,11 +1752,8 @@ namespace AgroBase.Models // Retorno a base automatico public void IniciarRetornoBase(GPSModel baseGps, List waypointsManual = null) { - if (baseGps == null) - throw new ArgumentNullException(nameof(baseGps)); - bool valido = false; - List pontosRetorno; + List pontosRetorno = null; // ========================= // MODO MANUAL (operador) @@ -1772,7 +1769,8 @@ namespace AgroBase.Models // ========================= // MODO AUTOMÁTICO // ========================= - (valido, pontosRetorno) = GerarTrajetoriaRetornoAutomatico(baseGps); + if (baseGps != null) + (valido, pontosRetorno) = GerarTrajetoriaRetornoAutomatico(baseGps); } if (!valido || pontosRetorno == null || pontosRetorno.Count < 1) diff --git a/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs b/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs index 58c9d1d20..c728f856e 100644 --- a/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs +++ b/AgroBase/OperationControl/Controls/MapViewControl.xaml.cs @@ -32,6 +32,7 @@ using Mapsui.Extensions; using OperationControl.Models; using static AgroBase.Models.Enums; using System.Windows.Input; +using AgroBase.Models; namespace OperationControl.Controls @@ -545,6 +546,10 @@ namespace OperationControl.Controls if (ParametrizandoOperacao) HighlightRoad(roadFeature); } + else if (EmModoRetorno) + { + AlternarPontoNoMapa(sp); + } else { OnMarkerClicked(null); @@ -566,6 +571,8 @@ namespace OperationControl.Controls Mapa.Cursor = System.Windows.Input.Cursors.Hand; else if (feat != null && info?.Layer == MapaPlantacao_Layer && feat is MIFeature roadFeature && ParametrizandoOperacao) Mapa.Cursor = System.Windows.Input.Cursors.Hand; + else if (feat != null && info?.Layer == _layerPontosSelecionados && feat is PointFeature pointFeature && EmModoRetorno) + Mapa.Cursor = System.Windows.Input.Cursors.Hand; else Mapa.Cursor = System.Windows.Input.Cursors.Arrow; } @@ -577,6 +584,120 @@ namespace OperationControl.Controls } + #region RETORNO A BASE MANUAL + + private MemoryLayer _layerPontosSelecionados; + public List _pontosSelecionados = new List(); + double ToleranciaRemocaoMetros = 2.0; + private bool EmModoRetorno => + !SemRoverFocado && + !(VariaveisControleOperacao.RoverEmFoco?.DadosLeitura?.Operacao?.Iniciada ?? false) && + (VariaveisControleOperacao.RoverEmFoco?.DadosLeitura?.Operacao?.Status ?? StatusOperacao.NaoIniciado) == StatusOperacao.Parametrizando && + Models.Variaveis.Dock?._vm?._viewOperacaoRight?._vm?.SecaoAtual == ViewModels.Views.Operacao.SecaoRightBar.Parametrizacao && + Models.Variaveis.Dock?._vm?._viewOperacaoRight?.areaParametrizacao?._vm?.Parametros?.Modo == ModoOperacao.RetornoBase; + + private void AlternarPontoNoMapa(ScreenPosition sp) + { + try + { + // Dependendo da versão do Mapsui, pode ser: + // var world = Mapa.Navigator.Viewport.ScreenToWorld(sp.X, sp.Y); + // ou: + var world = Mapa.Map.Navigator.Viewport.ScreenToWorld(sp.X, sp.Y); + + // Normalmente o mapa está em EPSG:3857 + var lonLat = Mapsui.Projections.SphericalMercator.ToLonLat(world.X, world.Y); + + GPSModel ponto = new GPSModel() { Latitude = lonLat.lat, Longitude = lonLat.lon }; + + var existente = _pontosSelecionados + .FirstOrDefault(p => GPSUtils.DistanciaEntrePontos(ponto, p) <= ToleranciaRemocaoMetros); + + if (existente != null) + { + _pontosSelecionados.Remove(existente); + } + else + { + _pontosSelecionados.Add(ponto); + } + + RedesenharPontosSelecionados(); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Erro ao alternar ponto no mapa: {ex.Message}"); + } + finally + { + Models.Variaveis.MostrarLog($"Pontos: {_pontosSelecionados.Count}"); + } + } + + private void RedesenharPontosSelecionados() + { + var features = new List(); + + for (int i = 0; i < _pontosSelecionados.Count; i++) + { + var p = _pontosSelecionados[i]; + + var mercator = Mapsui.Projections.SphericalMercator.FromLonLat(p.Longitude, p.Latitude); + + var feature = new PointFeature(mercator.x, mercator.y); + + // número do ponto + feature["label"] = (i + 1).ToString(); + + // círculo + feature.Styles.Add(new SymbolStyle + { + SymbolType = SymbolType.Ellipse, + SymbolScale = 1.2, + Fill = new Brush(Color.Red), + Outline = new Pen(Color.White, 2) + }); + + // texto (número) + feature.Styles.Add(new LabelStyle + { + LabelColumn = "label", + ForeColor = Color.White, + BackColor = null, + HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center, + VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Center, + Offset = new Offset(0, 0), + Font = new Font { Size = 12 } + }); + + features.Add(feature); + } + + if (_layerPontosSelecionados == null) + { + _layerPontosSelecionados = new MemoryLayer + { + Name = "PontosSelecionados" + }; + + Mapa.Map.Layers.Add(_layerPontosSelecionados); + } + + _layerPontosSelecionados.Features = features; + Mapa.Refresh(); + } + + public void LimparPontosSelecionados() + { + _pontosSelecionados = new List(); + RedesenharPontosSelecionados(); + VariaveisControleOperacao.RoverEmFoco.PontosRetorno = null; + } + + #endregion + + + private void EnsureBaseLayer() { try @@ -802,7 +923,7 @@ namespace OperationControl.Controls } catch (Exception ex) { - Variaveis.MostrarLog($"Erro ao carregar coordenadas do mapa: {ex.Message}"); + Models.Variaveis.MostrarLog($"Erro ao carregar coordenadas do mapa: {ex.Message}"); } } @@ -915,7 +1036,7 @@ namespace OperationControl.Controls return _mapa; } - public void CarregarDadosMapa(AgroBase.Models.MapaFeatureCollectionModel Mapa, List RuasSelecionadas) + public void CarregarDadosMapa(AgroBase.Models.MapaFeatureCollectionModel Mapa, List RuasSelecionadas, List pontosSelecionados) { if (RuasMapaCarregado.Any()) { @@ -928,6 +1049,8 @@ namespace OperationControl.Controls AtualizarStylesRuas(); } + _pontosSelecionados = (pontosSelecionados ?? new List()).Select(x => new GPSModel() { Latitude = x[0], Longitude = x[1] }).ToList(); + RedesenharPontosSelecionados(); } diff --git a/AgroBase/OperationControl/ViewModels/Views/Operacao/Monitoramento/ParametrizacaoViewModel.cs b/AgroBase/OperationControl/ViewModels/Views/Operacao/Monitoramento/ParametrizacaoViewModel.cs index 4de50602d..bf2c31d3b 100644 --- a/AgroBase/OperationControl/ViewModels/Views/Operacao/Monitoramento/ParametrizacaoViewModel.cs +++ b/AgroBase/OperationControl/ViewModels/Views/Operacao/Monitoramento/ParametrizacaoViewModel.cs @@ -67,6 +67,7 @@ namespace OperationControl.ViewModels.Views.Operacao.Monitoramento private void ReiniciarOperacao() { VariaveisControleOperacao.EnviarComandoIniciarOperacao(false, false); + Models.Variaveis.Dock?._vm?._viewOperacaoCenter?.Mapa?.LimparPontosSelecionados(); } public void AtualizarParametros(OperacaoParametrosModel origem) diff --git a/AgroBase/OperationControl/ViewModels/Views/Operacao/OperacaoLeftViewModel.cs b/AgroBase/OperationControl/ViewModels/Views/Operacao/OperacaoLeftViewModel.cs index f56225c19..8505ffed2 100644 --- a/AgroBase/OperationControl/ViewModels/Views/Operacao/OperacaoLeftViewModel.cs +++ b/AgroBase/OperationControl/ViewModels/Views/Operacao/OperacaoLeftViewModel.cs @@ -380,6 +380,7 @@ namespace OperationControl.ViewModels.Views.Operacao if (System.Windows.MessageBox.Show("Deseja finalizar a operação em andamento?", "Finalizar Operação", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { VariaveisControleOperacao.EnviarComandoIniciarOperacao(false); + Models.Variaveis.Dock?._vm?._viewOperacaoCenter?.Mapa?.LimparPontosSelecionados(); } } diff --git a/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs b/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs index a8c82f1ad..ec894bbc8 100644 --- a/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs +++ b/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs @@ -1,8 +1,7 @@ -using AgroBase.Models.Operacoes; +using AgroBase.Models; +using AgroBase.Models.Operacoes; using AgroBase.Services; -using Microsoft.VisualBasic.Logging; using Newtonsoft.Json.Linq; -using OpenTK.Windowing.Common.Input; using OperationControl.Controls; using OperationControl.Helpers; using OperationControl.Models; @@ -740,7 +739,7 @@ namespace OperationControl.ViewModels public void AtualizarDadosMapa(OperacaoParametrosModel? dados) { _viewOperacaoCenter?.Mapa?.LoadMapFile(_ultimoMapaCarregado); - _viewOperacaoCenter?.Mapa?.CarregarDadosMapa(dados?.Mapa, dados?.RuasPercorrer); + _viewOperacaoCenter?.Mapa?.CarregarDadosMapa(dados?.Mapa, dados?.RuasPercorrer, dados?.PontosRetorno); } #region TELA 2 @@ -755,9 +754,9 @@ namespace OperationControl.ViewModels Mapa?.markers?.AddMarker( markerId, true, - lat: Variaveis.GpsService?.UltimaLeitura?.Latitude, - lon: Variaveis.GpsService?.UltimaLeitura?.Longitude, - heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal, + lat: Models.Variaveis.GpsService?.UltimaLeitura?.Latitude, + lon: Models.Variaveis.GpsService?.UltimaLeitura?.Longitude, + heading: Models.Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal, label: "Base" ); } @@ -783,11 +782,11 @@ namespace OperationControl.ViewModels { try { - if (!(Variaveis.GpsService.BaseFix?.FixLiberado ?? false)) + if (!(Models.Variaveis.GpsService.BaseFix?.FixLiberado ?? false)) { bool fixar = false; - if (Variaveis.GpsService.BaseFix?.PosicaoBaseFixada ?? false) + if (Models.Variaveis.GpsService.BaseFix?.PosicaoBaseFixada ?? false) { var res = System.Windows.MessageBox.Show( "Mudar posição da base?", @@ -806,12 +805,12 @@ namespace OperationControl.ViewModels if (fixar) { _viewPreparacaoMapaBottom?._vm.IniciarFixacao(); - await Variaveis.GpsService.ConfigurarModulo(true, metodoFix, lat, lon, alt); + await Models.Variaveis.GpsService.ConfigurarModulo(true, metodoFix, lat, lon, alt); } } else { - Variaveis.GpsService.BaseFix.ReiniciarFix(); + Models.Variaveis.GpsService.BaseFix.ReiniciarFix(); BaseFixada = false; } } @@ -852,10 +851,10 @@ namespace OperationControl.ViewModels if (offsetFrontalCm == null || offsetLateralCm == null) return; _viewPreparacaoMapaBottom?._vm.IniciarFixacao(); - var gps = Variaveis.GpsService; + var gps = Models.Variaveis.GpsService; gps.LeverArm = new GeoLeverArm(offsetCampoFrontalCm: offsetFrontalCm.Value, offsetCampoLateralCm: offsetLateralCm.Value); (double lat, double lon) = gps.LeverArm.FixLeverArmLatLon_Fast(gps.BaseFix.LatitudeFix, gps.BaseFix.LongitudeFix, gps.BaseFix.OrientacaoFix); - await Variaveis.GpsService.ConfigurarModulo(true, MetodoFixacaoBase.Manual, lat, lon, gps.BaseFix.AltitudeElpsoidalFix, offset: true); + await Models.Variaveis.GpsService.ConfigurarModulo(true, MetodoFixacaoBase.Manual, lat, lon, gps.BaseFix.AltitudeElpsoidalFix, offset: true); } #endregion @@ -1099,9 +1098,34 @@ namespace OperationControl.ViewModels } private void OnSalvarParametrosSolicitado(OperacaoParametrosModel parametros) { + var rover = VariaveisControleOperacao.RoverEmFoco; + + if (parametros.Modo == AgroBase.Models.Enums.ModoOperacao.RetornoBase) + { + var pontos = _viewOperacaoCenter?.Mapa?._pontosSelecionados; + if (!(pontos?.Any() ?? false)) + { + System.Windows.MessageBox.Show("Clique no mapa para marcar os pontos por onde o equipamento deve seguir", "Pontos não marcados", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + if (System.Windows.MessageBox.Show($"Deseja iniciar a operação de retorno seguindo os {pontos.Count} pontos marcados no mapa, somando em {GPSUtils.DistanciaDoTrecho(pontos):F2} metros?", "Confirmação", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) + { + parametros.PontosRetorno = pontos.Select(x => new double[] { x.Latitude, x.Longitude }).ToList(); + VariaveisControleOperacao.EnviarComandoRetornoBase(pontosRetorno: parametros.PontosRetorno); + + rover.PontosRetorno = parametros.PontosRetorno; + Task.Run(async () => + { + await Task.Delay(500); + _viewOperacaoRight?._vm?.SelecionarSecao(SecaoRightBar.Resumo); + }); + } + return; + } + var dadosMapa = _viewOperacaoCenter?.Mapa?.CriarDadosMapa(); var ruasPercorrer = _viewOperacaoCenter?.Mapa?.RuasMapaCarregado?.Where(x => x.Selected)?.Select(x => x.Id)?.ToList() ?? new List(); - var rover = VariaveisControleOperacao.RoverEmFoco; if (rover?.DadosLeitura?.Operacao?.Modo != parametros.Modo && (rover?.DadosLeitura?.Operacao?.Iniciada ?? false)) { @@ -1283,6 +1307,7 @@ namespace OperationControl.ViewModels rover.ModulosMandatorios = novosParametros.ModulosMandatorios; rover.ParametrosMandatorios = novosParametros.ParametrosMandatorios; rover.RuasPercorrer = novosParametros.RuasPercorrer; + rover.PontosRetorno = novosParametros.PontosRetorno; rover.Mapa = novosParametros.Mapa; AtualizarDadosDiagnostico(rover);