Mejoras en elevaciones, equilibrado y callejero inverso

Añadida visualización de pendientes en los tramos a pie con puntos coloreados: llano, subida y bajada.
Añadidos umbrales configurables para subida y bajada junto al interruptor de elevaciones.
Añadido callejero inverso en el detalle de la solución, mostrando el lugar del callejero más cercano al origen y al destino.
Ajustado el modo Equilib. A para limpiar la tarjeta visualmente y guardar/restaurar el factor usado desde el historial.
Mejoras menores en el refresco del resumen técnico de rutas y validación de compilación.
This commit is contained in:
2026-07-10 14:01:52 +02:00
parent 7edb2dd2e9
commit 582ab14138
11 changed files with 421 additions and 122 deletions

View File

@@ -7,6 +7,7 @@ using LeafletForBlazor;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using RutasDBUS.Modelos.Planificacion;
using RutasDBUS.Modelos.Geocodificacion;
using RutasDBUS.Modelos.RedBus;
using RutasDBUS.Servicios;
using RutasDBUS.Servicios.Caminata;
@@ -344,6 +345,8 @@ public partial class PlanificadorRutas : ComponentBase
private double _duracionTotalSegundos = 0;
private double? _altitudOrigenResumenRuta = null;
private double? _altitudDestinoResumenRuta = null;
private string? _callejeroOrigenResumenRuta = null;
private string? _callejeroDestinoResumenRuta = null;
private readonly List<AlternativaRuta> _opcionesRuta = new();
private int _indiceAlternativaSeleccionada = 0;
@@ -351,6 +354,8 @@ public partial class PlanificadorRutas : ComponentBase
private TimeSpan? _tiempoUltimoCalculoRuta = null;
private bool _mostrarElevacionesRuta = false;
private bool _pintandoElevacionesRuta = false;
private double _umbralPendienteSubidaRuta = 3.0;
private double _umbralPendienteBajadaRuta = 3.0;
private readonly Dictionary<string, List<Parada>> _paradasItinerarioVisiblesPorId = new(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, List<Parada>> _paradasRutaVisiblesPorId = new(StringComparer.OrdinalIgnoreCase);
@@ -1037,7 +1042,8 @@ public partial class PlanificadorRutas : ComponentBase
double opacity,
string? dashArray = null,
bool arrowEnd = false,
string? lineCap = null)
string? lineCap = null,
IReadOnlyList<object>? elevationSegments = null)
{
try
{
@@ -1045,28 +1051,11 @@ public partial class PlanificadorRutas : ComponentBase
"rt.drawRoute",
id,
LineaToLatLng(linea),
new { color, weight, opacity, dashArray, arrowEnd, lineCap }
new { color, weight, opacity, dashArray, arrowEnd, lineCap, elevationSegments }
);
}
catch { }
}
private async Task DrawRouteElevationPointsJsAsync(string id, IReadOnlyList<object> points)
{
try
{
await JS.InvokeVoidAsync("rt.drawElevPoints", $"route_elev_{id}", points, new
{
radius = 4,
opacity = 0.98,
fillOpacity = 0.95,
showLabels = false,
showSlopeTooltips = true,
className = "rt-route-elev-point"
});
}
catch { }
}
/// <summary>
/// Ajusta rutas js.
@@ -1163,6 +1152,67 @@ public partial class PlanificadorRutas : ComponentBase
return $"D: Y.Lat = {lat} X.Lon = {lon} Z = {alt}";
}
private string FormatearResumenCallejeroOrigen()
{
if (string.IsNullOrWhiteSpace(_callejeroOrigenResumenRuta))
return string.Empty;
return $"O callejero: {_callejeroOrigenResumenRuta}";
}
private string FormatearResumenCallejeroDestino()
{
if (string.IsNullOrWhiteSpace(_callejeroDestinoResumenRuta))
return string.Empty;
return $"D callejero: {_callejeroDestinoResumenRuta}";
}
private static string FormatearLugarCallejeroResumen(LugarGeocodificadoCercano? cercano)
{
if (cercano is null)
return string.Empty;
var nombre = LimpiarTextoCallejeroResumen(cercano.Lugar.Nombre);
if (string.IsNullOrWhiteSpace(nombre))
nombre = LimpiarTextoCallejeroResumen(cercano.Lugar.Subtitulo);
if (string.IsNullOrWhiteSpace(nombre))
return string.Empty;
var distancia = FormatearDistanciaCallejeroResumen(cercano.DistanciaMetros);
if (string.IsNullOrWhiteSpace(distancia))
return nombre;
return cercano.DistanciaMetros <= 20
? $"{nombre} ({distancia})"
: $"mas cercano: {nombre} ({distancia})";
}
private static string LimpiarTextoCallejeroResumen(string texto)
{
if (string.IsNullOrWhiteSpace(texto))
return string.Empty;
texto = texto
.Replace(" · ", " - ", StringComparison.Ordinal)
.Replace("·", "-", StringComparison.Ordinal)
.Replace("·", "-", StringComparison.Ordinal);
return Regex.Replace(texto, @"\s+", " ").Trim();
}
private static string FormatearDistanciaCallejeroResumen(double distanciaMetros)
{
if (!double.IsFinite(distanciaMetros) || distanciaMetros < 0)
return string.Empty;
if (distanciaMetros < 1000)
return $"{Math.Round(distanciaMetros):0} m";
return $"{(distanciaMetros / 1000.0).ToString("0.000", CultureInfo.InvariantCulture)} km";
}
/// <summary>
/// Formatea duracion.
@@ -1638,6 +1688,8 @@ public partial class PlanificadorRutas : ComponentBase
_duracionTotalSegundos = 0;
_altitudOrigenResumenRuta = null;
_altitudDestinoResumenRuta = null;
_callejeroOrigenResumenRuta = null;
_callejeroDestinoResumenRuta = null;
_paradaOrigenSeleccionada = null;
_paradaDestinoSeleccionada = null;