From 8a75c583ca46c7dcbaabc2c5390a0cf48a9a8f51 Mon Sep 17 00:00:00 2001 From: Pedro Date: Tue, 28 Jul 2026 08:17:04 +0200 Subject: [PATCH] cambio foco elemento compartido poner km en los tramos de bus line 16 oscurecida flechas de sentido en las paradas --- .../Pages/PlanificadorRutas.Estado.cs | 63 ++++++- .../Pages/PlanificadorRutas.Historial.cs | 158 ++++++++++-------- .../Pages/PlanificadorRutas.Itinerarios.cs | 2 +- .../Pages/PlanificadorRutas.Planificacion.cs | 3 + .../Pages/PlanificadorRutas.Renderizado.cs | 17 +- RutasDBUS/Servicios/RedBus/RedBusServicio.cs | 5 +- RutasDBUS/wwwroot/app.css | 41 +++++ RutasDBUS/wwwroot/app.js | 29 +++- 8 files changed, 231 insertions(+), 87 deletions(-) diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs index fac233e..987889a 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs @@ -465,13 +465,70 @@ public partial class PlanificadorRutas : ComponentBase /// private static List BuildStopsDesdeParadas(IEnumerable paradas) { - var stops = new List(); - foreach (var parada in paradas) - stops.Add(new { lat = parada.Latitud, lon = parada.Longitud, code = parada.Codigo }); + var paradasOrdenadas = paradas.ToList(); + var stops = new List(paradasOrdenadas.Count); + for (var indice = 0; indice < paradasOrdenadas.Count; indice++) + { + var parada = paradasOrdenadas[indice]; + stops.Add(new + { + lat = parada.Latitud, + lon = parada.Longitud, + code = parada.Codigo, + bearing = CalcularRumboParada(paradasOrdenadas, indice) + }); + } return stops; } + /// + /// Calcula el sentido de marcha hacia la siguiente parada; en la terminal conserva el rumbo de llegada. + /// + private static double? CalcularRumboParada(IReadOnlyList paradas, int indice) + { + var actual = paradas[indice]; + for (var siguiente = indice + 1; siguiente < paradas.Count; siguiente++) + { + var rumbo = CalcularRumboGrados(actual, paradas[siguiente]); + if (rumbo is not null) + return rumbo; + } + + for (var anterior = indice - 1; anterior >= 0; anterior--) + { + var rumbo = CalcularRumboGrados(paradas[anterior], actual); + if (rumbo is not null) + return rumbo; + } + + return null; + } + + private static double? CalcularRumboGrados(Parada origen, Parada destino) + { + if (!double.IsFinite(origen.Latitud) || + !double.IsFinite(origen.Longitud) || + !double.IsFinite(destino.Latitud) || + !double.IsFinite(destino.Longitud)) + { + return null; + } + + var latitudOrigen = origen.Latitud * Math.PI / 180.0; + var latitudDestino = destino.Latitud * Math.PI / 180.0; + var diferenciaLongitud = (destino.Longitud - origen.Longitud) * Math.PI / 180.0; + var y = Math.Sin(diferenciaLongitud) * Math.Cos(latitudDestino); + var x = Math.Cos(latitudOrigen) * Math.Sin(latitudDestino) - + Math.Sin(latitudOrigen) * Math.Cos(latitudDestino) * Math.Cos(diferenciaLongitud); + + if (Math.Abs(x) < 1e-12 && Math.Abs(y) < 1e-12) + return null; + + var rumbo = Math.Atan2(y, x) * 180.0 / Math.PI; + return (rumbo + 360.0) % 360.0; + } + /// /// Construye las paradas visibles recorridas por una variante completa. /// diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs index e4f4398..80e97ae 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs @@ -29,6 +29,7 @@ public partial class PlanificadorRutas private bool _mostrarHistorialRutas = false; private bool _refrescandoHistorialCompartido = false; private bool _omitirRegistroHistorialEnSiguienteCalculo = false; + private bool _aplicandoRegistroHistorial = false; private string? _historialCompartidoPendienteEliminarId; private ConfiguracionLocalPlanificador? _configuracionTemporalPreviaHistorial; private Task? _tareaCargaHistorialLocal; @@ -181,7 +182,8 @@ public partial class PlanificadorRutas { _historialLocal.Clear(); _historialLocal.AddRange(items); - _historialLocalSeleccionadoId = _historialLocal.FirstOrDefault()?.Id ?? string.Empty; + if (!_historialLocal.Any(x => x.Id == _historialLocalSeleccionadoId)) + _historialLocalSeleccionadoId = string.Empty; _historialLocalCargado = true; } @@ -232,7 +234,7 @@ public partial class PlanificadorRutas } if (!_historialCompartido.Any(x => x.Id == _historialCompartidoSeleccionadoId)) - _historialCompartidoSeleccionadoId = _historialCompartido[0].Id; + _historialCompartidoSeleccionadoId = string.Empty; } catch (Exception) { @@ -332,13 +334,12 @@ public partial class PlanificadorRutas while (_historialLocal.Count > MaxItemsHistorialLocal) _historialLocal.RemoveAt(_historialLocal.Count - 1); - _historialLocalSeleccionadoId = existente.Id; await PersistirHistorialLocalAsync(); } - private async Task CargarHistorialLocalSeleccionadoAsync() + private async Task CargarHistorialLocalAsync(string id) { - var item = _historialLocal.FirstOrDefault(x => x.Id == _historialLocalSeleccionadoId); + var item = _historialLocal.FirstOrDefault(x => x.Id == id); if (item is null) { MostrarMensajeHistorial("No encuentro esa combinacion en tu historial personal.", esError: true); @@ -346,18 +347,13 @@ public partial class PlanificadorRutas } await AplicarRegistroHistorialAsync(item); + SeleccionarHistorialLocal(id); MostrarMensajeHistorial("Combinacion personal cargada."); } - private async Task CargarHistorialLocalAsync(string id) + private async Task CargarHistorialCompartidoAsync(string id) { - _historialLocalSeleccionadoId = id; - await CargarHistorialLocalSeleccionadoAsync(); - } - - private async Task CargarHistorialCompartidoSeleccionadoAsync() - { - var item = _historialCompartido.FirstOrDefault(x => x.Id == _historialCompartidoSeleccionadoId); + var item = _historialCompartido.FirstOrDefault(x => x.Id == id); if (item is null) { MostrarMensajeHistorial("No encuentro esa combinacion en el historial compartido.", esError: true); @@ -365,13 +361,26 @@ public partial class PlanificadorRutas } await AplicarRegistroHistorialAsync(item); + SeleccionarHistorialCompartido(id); MostrarMensajeHistorial("Combinación compartida cargada."); } - private async Task CargarHistorialCompartidoAsync(string id) + private void SeleccionarHistorialLocal(string id) { + _historialLocalSeleccionadoId = id; + _historialCompartidoSeleccionadoId = string.Empty; + } + + private void SeleccionarHistorialCompartido(string id) + { + _historialLocalSeleccionadoId = string.Empty; _historialCompartidoSeleccionadoId = id; - await CargarHistorialCompartidoSeleccionadoAsync(); + } + + private void LimpiarSeleccionHistorial() + { + _historialLocalSeleccionadoId = string.Empty; + _historialCompartidoSeleccionadoId = string.Empty; } private async Task CompartirEscenarioActualAsync() @@ -387,9 +396,8 @@ public partial class PlanificadorRutas try { - var guardado = await HistorialRutasCompartidoService.GuardarAsync(actual); + await HistorialRutasCompartidoService.GuardarAsync(actual); await CargarHistorialCompartidoAsync(); - _historialCompartidoSeleccionadoId = guardado.Id; MostrarMensajeHistorial("Combinacion enviada al historial compartido."); } catch (Exception) @@ -400,7 +408,6 @@ public partial class PlanificadorRutas private async Task CompartirHistorialLocalAsync(string id) { - _historialLocalSeleccionadoId = id; var item = _historialLocal.FirstOrDefault(x => x.Id == id); if (item is null) { @@ -410,9 +417,8 @@ public partial class PlanificadorRutas try { - var guardado = await HistorialRutasCompartidoService.GuardarAsync(item); + await HistorialRutasCompartidoService.GuardarAsync(item); await CargarHistorialCompartidoAsync(); - _historialCompartidoSeleccionadoId = guardado.Id; MostrarMensajeHistorial("Combinacion enviada al historial compartido."); } catch (Exception) @@ -433,7 +439,7 @@ public partial class PlanificadorRutas _historialLocal.Remove(item); if (_historialLocalSeleccionadoId == id) - _historialLocalSeleccionadoId = _historialLocal.FirstOrDefault()?.Id ?? string.Empty; + _historialLocalSeleccionadoId = string.Empty; await PersistirHistorialLocalAsync(); MostrarMensajeHistorial("Combinacion eliminada del historial personal."); @@ -477,7 +483,7 @@ public partial class PlanificadorRutas await CargarHistorialCompartidoAsync(); if (_historialCompartidoSeleccionadoId == id) - _historialCompartidoSeleccionadoId = _historialCompartido.FirstOrDefault()?.Id ?? string.Empty; + _historialCompartidoSeleccionadoId = string.Empty; MostrarMensajeHistorial("Combinacion eliminada del historial compartido."); } @@ -489,61 +495,69 @@ public partial class PlanificadorRutas private async Task AplicarRegistroHistorialAsync(RegistroHistorialRuta item) { - CapturarConfiguracionTemporalAntesDeHistorial(); - - _omitirRegistroHistorialEnSiguienteCalculo = true; - _textoBusquedaOrigen = item.OrigenTexto; - _textoBusquedaDestino = item.DestinoTexto; - _coordenadasOrigen = new[] { item.OrigenLatitud, item.OrigenLongitud }; - _coordenadasDestino = new[] { item.DestinoLatitud, item.DestinoLongitud }; - - _usarHorariosTeoricos = item.UsarHorariosTeoricos; - _usarHoraSimulada = item.UsarHoraSimulada; - - if (DateOnly.TryParse(item.FechaSimulada, out var fecha)) - _fechaSimulada = fecha; - - if (TimeOnly.TryParse(item.HoraSimulada, out var hora)) - _horaSimulada = hora; - - _criterioPrioritarioRuta = NormalizarCriterioRuta(item.CriterioPrioritarioRuta, item.PreferenciaEtiquetaRuta); - SincronizarPreferenciaDesdeCriterioRuta(); - - if (item.FactorEquilibradoAndarBus is { } factorEquilibrado && double.IsFinite(factorEquilibrado)) + _aplicandoRegistroHistorial = true; + try { - _factorEquilibradoAndarBus = Math.Max(0, factorEquilibrado); - SincronizarTextosPenalizacionPie(); + CapturarConfiguracionTemporalAntesDeHistorial(); - if (_configuracionTemporalPreviaHistorial is not null) - _configuracionTemporalPreviaHistorial.FactorEquilibradoAndarBus = _factorEquilibradoAndarBus; + _omitirRegistroHistorialEnSiguienteCalculo = true; + _textoBusquedaOrigen = item.OrigenTexto; + _textoBusquedaDestino = item.DestinoTexto; + _coordenadasOrigen = new[] { item.OrigenLatitud, item.OrigenLongitud }; + _coordenadasDestino = new[] { item.DestinoLatitud, item.DestinoLongitud }; + + _usarHorariosTeoricos = item.UsarHorariosTeoricos; + _usarHoraSimulada = item.UsarHoraSimulada; + + if (DateOnly.TryParse(item.FechaSimulada, out var fecha)) + _fechaSimulada = fecha; + + if (TimeOnly.TryParse(item.HoraSimulada, out var hora)) + _horaSimulada = hora; + + _criterioPrioritarioRuta = NormalizarCriterioRuta(item.CriterioPrioritarioRuta, item.PreferenciaEtiquetaRuta); + SincronizarPreferenciaDesdeCriterioRuta(); + + if (item.FactorEquilibradoAndarBus is { } factorEquilibrado && double.IsFinite(factorEquilibrado)) + { + _factorEquilibradoAndarBus = Math.Max(0, factorEquilibrado); + SincronizarTextosPenalizacionPie(); + + if (_configuracionTemporalPreviaHistorial is not null) + _configuracionTemporalPreviaHistorial.FactorEquilibradoAndarBus = _factorEquilibradoAndarBus; + } + + _activarRangoLineas = item.ActivarFiltroLineas; + _lineasPermitidas.Clear(); + foreach (var linea in NormalizarLineasHistorial(item.LineasPermitidas)) + _lineasPermitidas.Add(linea); + _busFilteredCache.Clear(); + + SincronizarSegundosPorParadaConHorarios(); + + StopClock(); + if (_usarHoraSimulada) + await RefrescarHoraUIAsync(); + else + StartClock(); + + await PersistirConfiguracionAsync(); + await CerrarTodasLasPreviewsAsync(); + await CerrarPopupsAsync(); + + if (_mapa is not null) + { + try { await _mapa.Geometric.DisplayPolylinesFromArray.deleteConnectors(); } catch { } + await ClearRoutesJsAsync(); + } + + await SincronizarMarcadoresOrigenDestinoJsAsync(); + await CalcularRutaCompletaAsync(); } - - _activarRangoLineas = item.ActivarFiltroLineas; - _lineasPermitidas.Clear(); - foreach (var linea in NormalizarLineasHistorial(item.LineasPermitidas)) - _lineasPermitidas.Add(linea); - _busFilteredCache.Clear(); - - SincronizarSegundosPorParadaConHorarios(); - - StopClock(); - if (_usarHoraSimulada) - await RefrescarHoraUIAsync(); - else - StartClock(); - - await PersistirConfiguracionAsync(); - await CerrarTodasLasPreviewsAsync(); - await CerrarPopupsAsync(); - - if (_mapa is not null) + finally { - try { await _mapa.Geometric.DisplayPolylinesFromArray.deleteConnectors(); } catch { } - await ClearRoutesJsAsync(); + _aplicandoRegistroHistorial = false; } - - await SincronizarMarcadoresOrigenDestinoJsAsync(); - await CalcularRutaCompletaAsync(); } private void CapturarConfiguracionTemporalAntesDeHistorial() diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs index c6b3754..37b504c 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs @@ -1204,7 +1204,7 @@ public partial class PlanificadorRutas : ComponentBase private bool _elevPopupMinimizado = false; - private const string _versionApp = "(v-20260721a)"; + private const string _versionApp = "(v-20260727a)"; private double? _paradaElevG; diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs index a85c6d9..764fc2b 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs @@ -1552,6 +1552,9 @@ public partial class PlanificadorRutas : ComponentBase if (_mapa is null || _coordenadasOrigen is null || _coordenadasDestino is null) return; + if (!_aplicandoRegistroHistorial) + LimpiarSeleccionHistorial(); + var cronometroCalculo = System.Diagnostics.Stopwatch.StartNew(); _panelRutasMovilContraido = _mostrarBuscadorMapa; diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs index c51949d..be8d796 100644 --- a/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs +++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs @@ -859,6 +859,13 @@ public partial class PlanificadorRutas : ComponentBase DateTime? depT = null; DateTime? arrT = null; + double distanciaTramo = 0; + for (int p = 1; p < lineaGeom.GetLength(0); p++) + { + distanciaTramo += CalcularDistanciaMetros( + lineaGeom[p - 1, 0], lineaGeom[p - 1, 1], + lineaGeom[p, 0], lineaGeom[p, 1]); + } if (_usarHorariosTeoricos && _horariosOk) { @@ -957,21 +964,13 @@ public partial class PlanificadorRutas : ComponentBase Descripcion = CapitalizarPalabrasClave( $"{HHmm(depT.Value)} -> {HHmm(arrT.Value)} - Linea {codLineaItinSentidoMostrado} ({infoVariante.Linea.Nombre})." ), - DistanciaMetros = 0, + DistanciaMetros = distanciaTramo, DuracionSegundos = durBus, VarianteBus = infoVariante }); } else { - double distanciaTramo = 0; - for (int p = 1; p < lineaGeom.GetLength(0); p++) - { - distanciaTramo += CalcularDistanciaMetros( - lineaGeom[p - 1, 0], lineaGeom[p - 1, 1], - lineaGeom[p, 0], lineaGeom[p, 1]); - } - int paradasTramo = ContarParadasRecorridas(tramo); double extraParadasSeg = paradasTramo * Math.Max(0, _segundosPorParadaBus); double duracionBusSegundos = EstimarDuracionBusSegundos(distanciaTramo) + extraParadasSeg; diff --git a/RutasDBUS/Servicios/RedBus/RedBusServicio.cs b/RutasDBUS/Servicios/RedBus/RedBusServicio.cs index 2ab3a43..3516591 100644 --- a/RutasDBUS/Servicios/RedBus/RedBusServicio.cs +++ b/RutasDBUS/Servicios/RedBus/RedBusServicio.cs @@ -8,6 +8,7 @@ namespace RutasDBUS.Servicios.RedBus; public class RedBusServicio : IRedBusServicio { + private const string ColorVisualLinea16Argb = "FF5AAED6"; private const string ColorVisualLinea40Argb = "FF9A7B00"; private readonly OpcionesRedBus _opciones; private readonly ILogger _logger; @@ -143,7 +144,9 @@ public class RedBusServicio : IRedBusServicio private static void AjustarColorVisualLinea(LineaBus linea) { - if (string.Equals(linea.Codigo, "40", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(linea.Codigo, "16", StringComparison.OrdinalIgnoreCase)) + linea.ColorArgb = ColorVisualLinea16Argb; + else if (string.Equals(linea.Codigo, "40", StringComparison.OrdinalIgnoreCase)) linea.ColorArgb = ColorVisualLinea40Argb; } diff --git a/RutasDBUS/wwwroot/app.css b/RutasDBUS/wwwroot/app.css index 5c7c550..a78c5e7 100644 --- a/RutasDBUS/wwwroot/app.css +++ b/RutasDBUS/wwwroot/app.css @@ -1755,6 +1755,47 @@ html, body { border: none; } +.rt-stop-direction-icon { + border: 0; + background: transparent; + pointer-events: none; +} + +.rt-stop-direction-arrow { + position: absolute; + top: 50%; + left: 50%; + width: 10px; + height: 12px; + transform: translate(-50%, -50%) rotate(var(--stop-bearing, 0deg)); + transform-origin: 50% 50%; + filter: drop-shadow(0 0 1px #0f172a) drop-shadow(0 1px 0 #0f172a); +} + +.rt-stop-direction-arrow::before { + content: ""; + position: absolute; + top: 0; + left: 50%; + width: 0; + height: 0; + transform: translateX(-50%); + border-right: 3px solid transparent; + border-bottom: 6px solid #f8fafc; + border-left: 3px solid transparent; +} + +.rt-stop-direction-arrow::after { + content: ""; + position: absolute; + top: 5px; + left: 4px; + width: 2px; + height: 6px; + border-radius: 1px; + background: #f8fafc; +} + .rt-arrow { position: relative; transform-origin: 50% 50%; diff --git a/RutasDBUS/wwwroot/app.js b/RutasDBUS/wwwroot/app.js index 88f0d87..94a79f9 100644 --- a/RutasDBUS/wwwroot/app.js +++ b/RutasDBUS/wwwroot/app.js @@ -894,7 +894,32 @@ window.rt.ensureItStopsLayer = function () { return true; }; -// stops: [{lat, lon}] +window.rt.addStopDirectionMarker = function (group, stop, pane, radius) { + if (!group || !stop || !window.L) return; + + const bearing = Number(stop.bearing); + const lat = Number(stop.lat); + const lon = Number(stop.lon); + if (!Number.isFinite(bearing) || !Number.isFinite(lat) || !Number.isFinite(lon)) return; + + const size = Math.max(14, Number(radius || 7) * 2); + const icon = window.L.divIcon({ + className: "rt-stop-direction-icon", + html: ``, + iconSize: [size, size], + iconAnchor: [size / 2, size / 2] + }); + + window.L.marker([lat, lon], { + pane, + icon, + interactive: false, + keyboard: false, + zIndexOffset: 1000 + }).addTo(group); +}; + +// stops: [{lat, lon, code, bearing}] window.rt.toggleItStops = function (id, stops, options) { if (!window.rt.ensureItStopsLayer()) return; @@ -944,6 +969,7 @@ window.rt.toggleItStops = function (id, stops, options) { } m.addTo(group); + window.rt.addStopDirectionMarker(group, s, "rtStopsPane", radius); } } @@ -1021,6 +1047,7 @@ window.rt.drawRouteStops = function (id, stops, options) { } m.addTo(group); + window.rt.addStopDirectionMarker(group, s, "rtRouteStopsPane", radius); } group.addTo(window.rt._routeStopsLayer);