- andar equilibraod separado del calculo

- comienzo de penalizacoin en 200m
- centrado de origen
This commit is contained in:
2026-07-29 14:45:59 +02:00
parent 8a75c583ca
commit 6145fb635a
11 changed files with 404 additions and 101 deletions

View File

@@ -48,6 +48,7 @@ public partial class PlanificadorRutas : ComponentBase
// CONFIG
private const double FactorPenalizacionDistanciaPiePorDefecto = 1.35;
private const double ParametroPenalizacionDistanciaPieMetrosPorDefecto = 200.0;
private const double CoeficienteEsfuerzoAlturaPorDefecto = 8.2;
private const double UmbralPendienteSubidaRutaPorDefecto = 2.0;
private const double UmbralPendienteBajadaRutaPorDefecto = 5.0;
@@ -56,12 +57,12 @@ public partial class PlanificadorRutas : ComponentBase
private double _velocidadPieKmH = 3.6;
private double _factorPenalizacionDistanciaPie = FactorPenalizacionDistanciaPiePorDefecto;
private double _parametroPenalizacionDistanciaPieMetros = 100.0;
private double _parametroPenalizacionDistanciaPieMetros = ParametroPenalizacionDistanciaPieMetrosPorDefecto;
private double _coeficienteEsfuerzoAltura = CoeficienteEsfuerzoAlturaPorDefecto;
private double _pesoTransbordoRankingMinutos = 4.0;
private double _factorEquilibradoAndarBus = 12.0;
private string _factorPenalizacionDistanciaPieTextoEdicion = "1.35";
private string _parametroPenalizacionDistanciaPieTextoEdicion = "100";
private string _parametroPenalizacionDistanciaPieTextoEdicion = "200";
private string _coeficienteEsfuerzoAlturaTextoEdicion = "8.20";
private string _pesoTransbordoRankingTextoEdicion = "4,0";
private string _factorEquilibradoAndarBusTextoEdicion = "12";
@@ -461,21 +462,47 @@ public partial class PlanificadorRutas : ComponentBase
/// <summary>
/// Construye paradas for variante.
/// Construye el payload JS de paradas de una variante.
/// </summary>
private static List<object> BuildStopsDesdeParadas(IEnumerable<Parada> paradas)
private List<object> BuildStopsForVariante(InfoVariante v)
{
var paradasOrdenadas = paradas.ToList();
var stops = new List<object>(paradasOrdenadas.Count);
for (var indice = 0; indice < paradasOrdenadas.Count; indice++)
if (v?.CodigosParadas is null || v.CodigosParadas.Count == 0)
return new List<object>();
return BuildStopsParaRangoVariante(v, 0, v.CodigosParadas.Count - 1);
}
/// <summary>
/// Construye el payload JS de paradas recorridas por un tramo concreto.
/// </summary>
private List<object> BuildStopsForTramoBus(TramoBus tramo)
{
var parada = paradasOrdenadas[indice];
if (tramo?.Variante?.CodigosParadas is null || tramo.Variante.CodigosParadas.Count == 0)
return new List<object>();
var ultimoIndice = tramo.Variante.CodigosParadas.Count - 1;
var inicio = Math.Clamp(Math.Min(tramo.IndiceInicio, tramo.IndiceFin), 0, ultimoIndice);
var fin = Math.Clamp(Math.Max(tramo.IndiceInicio, tramo.IndiceFin), 0, ultimoIndice);
return BuildStopsParaRangoVariante(tramo.Variante, inicio, fin);
}
private List<object> BuildStopsParaRangoVariante(InfoVariante variante, int inicio, int fin)
{
var stops = new List<object>();
var codigosVistos = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
for (var indice = inicio; indice <= fin; indice++)
{
var codigo = variante.CodigosParadas[indice];
if (!codigosVistos.Add(codigo) || !_paradaByCode.TryGetValue(codigo, out var parada))
continue;
stops.Add(new
{
lat = parada.Latitud,
lon = parada.Longitud,
code = parada.Codigo,
bearing = CalcularRumboParada(paradasOrdenadas, indice)
bearing = CalcularRumboParada(variante, indice)
});
}
@@ -483,21 +510,121 @@ public partial class PlanificadorRutas : ComponentBase
}
/// <summary>
/// Calcula el sentido de marcha hacia la siguiente parada; en la terminal conserva el rumbo de llegada.
/// Obtiene la tangente local de la geometria real al salir de la parada.
/// En la terminal usa la tangente de llegada del ultimo trayecto.
/// </summary>
private static double? CalcularRumboParada(IReadOnlyList<Parada> paradas, int indice)
private double? CalcularRumboParada(InfoVariante variante, int indiceParada)
{
var actual = paradas[indice];
for (var siguiente = indice + 1; siguiente < paradas.Count; siguiente++)
var idsTrayectos = variante.Variante?.IdsTrayectos;
if (idsTrayectos is not null)
{
var rumbo = CalcularRumboGrados(actual, paradas[siguiente]);
if (indiceParada >= 0 &&
indiceParada < idsTrayectos.Count &&
RedBusServicio.Trayectos.TryGetValue(idsTrayectos[indiceParada], out var trayectoSalida))
{
var rumboSalida = CalcularRumboGeometriaTrayecto(trayectoSalida.Posiciones, desdeInicio: true);
if (rumboSalida is not null)
return rumboSalida;
}
var indiceTrayectoLlegada = indiceParada - 1;
if (indiceTrayectoLlegada >= 0 &&
indiceTrayectoLlegada < idsTrayectos.Count &&
RedBusServicio.Trayectos.TryGetValue(idsTrayectos[indiceTrayectoLlegada], out var trayectoLlegada))
{
var rumboLlegada = CalcularRumboGeometriaTrayecto(trayectoLlegada.Posiciones, desdeInicio: false);
if (rumboLlegada is not null)
return rumboLlegada;
}
}
return CalcularRumboParadaPorCoordenadas(variante, indiceParada);
}
private static double? CalcularRumboGeometriaTrayecto(
IReadOnlyList<double[]> posiciones,
bool desdeInicio)
{
var puntos = posiciones
.Where(punto =>
punto is { Length: >= 2 } &&
double.IsFinite(punto[0]) &&
double.IsFinite(punto[1]))
.ToList();
if (puntos.Count < 2)
return null;
const double distanciaMinimaRumboMetros = 3.0;
double? rumboCorto = null;
if (desdeInicio)
{
var origen = puntos[0];
for (var indice = 1; indice < puntos.Count; indice++)
{
var destino = puntos[indice];
var rumbo = CalcularRumboGrados(origen[0], origen[1], destino[0], destino[1]);
if (rumbo is null)
continue;
rumboCorto ??= rumbo;
if (CalcularDistanciaMetros(origen[0], origen[1], destino[0], destino[1]) >= distanciaMinimaRumboMetros)
return rumbo;
}
}
else
{
var destino = puntos[^1];
for (var indice = puntos.Count - 2; indice >= 0; indice--)
{
var origen = puntos[indice];
var rumbo = CalcularRumboGrados(origen[0], origen[1], destino[0], destino[1]);
if (rumbo is null)
continue;
rumboCorto ??= rumbo;
if (CalcularDistanciaMetros(origen[0], origen[1], destino[0], destino[1]) >= distanciaMinimaRumboMetros)
return rumbo;
}
}
return rumboCorto;
}
private double? CalcularRumboParadaPorCoordenadas(InfoVariante variante, int indice)
{
if (indice < 0 ||
indice >= variante.CodigosParadas.Count ||
!_paradaByCode.TryGetValue(variante.CodigosParadas[indice], out var actual))
{
return null;
}
for (var siguiente = indice + 1; siguiente < variante.CodigosParadas.Count; siguiente++)
{
if (!_paradaByCode.TryGetValue(variante.CodigosParadas[siguiente], out var paradaSiguiente))
continue;
var rumbo = CalcularRumboGrados(
actual.Latitud,
actual.Longitud,
paradaSiguiente.Latitud,
paradaSiguiente.Longitud);
if (rumbo is not null)
return rumbo;
}
for (var anterior = indice - 1; anterior >= 0; anterior--)
{
var rumbo = CalcularRumboGrados(paradas[anterior], actual);
if (!_paradaByCode.TryGetValue(variante.CodigosParadas[anterior], out var paradaAnterior))
continue;
var rumbo = CalcularRumboGrados(
paradaAnterior.Latitud,
paradaAnterior.Longitud,
actual.Latitud,
actual.Longitud);
if (rumbo is not null)
return rumbo;
}
@@ -505,19 +632,23 @@ public partial class PlanificadorRutas : ComponentBase
return null;
}
private static double? CalcularRumboGrados(Parada origen, Parada destino)
private static double? CalcularRumboGrados(
double latitudOrigenGrados,
double longitudOrigenGrados,
double latitudDestinoGrados,
double longitudDestinoGrados)
{
if (!double.IsFinite(origen.Latitud) ||
!double.IsFinite(origen.Longitud) ||
!double.IsFinite(destino.Latitud) ||
!double.IsFinite(destino.Longitud))
if (!double.IsFinite(latitudOrigenGrados) ||
!double.IsFinite(longitudOrigenGrados) ||
!double.IsFinite(latitudDestinoGrados) ||
!double.IsFinite(longitudDestinoGrados))
{
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 latitudOrigen = latitudOrigenGrados * Math.PI / 180.0;
var latitudDestino = latitudDestinoGrados * Math.PI / 180.0;
var diferenciaLongitud = (longitudDestinoGrados - longitudOrigenGrados) * 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);
@@ -529,33 +660,6 @@ public partial class PlanificadorRutas : ComponentBase
return (rumbo + 360.0) % 360.0;
}
/// <summary>
/// Construye las paradas visibles recorridas por una variante completa.
/// </summary>
private List<Parada> BuildParadasForVariante(InfoVariante v)
{
var stops = new List<Parada>(v?.CodigosParadas?.Count ?? 0);
if (v?.CodigosParadas is null) return stops;
var codigosVistos = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var cod in v.CodigosParadas)
{
if (!codigosVistos.Add(cod))
continue;
if (_paradaByCode.TryGetValue(cod, out var parada))
stops.Add(parada);
}
return stops;
}
/// <summary>
/// Construye el payload JS de paradas de una variante.
/// </summary>
private List<object> BuildStopsForVariante(InfoVariante v)
=> BuildStopsDesdeParadas(BuildParadasForVariante(v));
/// <summary>
/// Construye las paradas visibles recorridas por un tramo concreto de bus.
/// </summary>
@@ -1061,14 +1165,16 @@ public partial class PlanificadorRutas : ComponentBase
/// <summary>
/// Ajusta rutas js.
/// </summary>
private async Task FitRoutesJsAsync(IReadOnlyList<double[]>? coordenadas = null)
private async Task FitRoutesJsAsync(
IReadOnlyList<double[]>? coordenadas = null,
double[]? centroPreferido = null)
{
try
{
if (coordenadas is null)
if (coordenadas is null && centroPreferido is null)
await JS.InvokeVoidAsync("rt.fitRoutes");
else
await JS.InvokeVoidAsync("rt.fitRoutes", coordenadas);
await JS.InvokeVoidAsync("rt.fitRoutes", coordenadas, centroPreferido);
}
catch { }
}
@@ -1267,11 +1373,19 @@ public partial class PlanificadorRutas : ComponentBase
var parametros = CrearParametrosPenalizacionActuales();
var distanciaCorregidaBase = alternativa.EsSoloAPie
? UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(alternativa.DistanciaSoloAPie, parametros)
: UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(alternativa.DistanciaPieInicioAprox, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(alternativa.DistanciaPieTransbordosAprox, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(alternativa.DistanciaPieFinAprox, parametros);
IEnumerable<double> distanciasPiePorTramo = alternativa.EsSoloAPie
? new[] { alternativa.DistanciaSoloAPie }
: alternativa.DistanciasPiePorTramoAprox.Count > 0
? alternativa.DistanciasPiePorTramoAprox
: new[]
{
alternativa.DistanciaPieInicioAprox,
alternativa.DistanciaPieTransbordosAprox,
alternativa.DistanciaPieFinAprox
};
var distanciaCorregidaBase = UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaTotalMetros(
distanciasPiePorTramo,
parametros);
var esfuerzoExtra = double.IsFinite(alternativa.EsfuerzoExtraPendienteMetros)
? Math.Max(0, alternativa.EsfuerzoExtraPendienteMetros)
: 0;
@@ -1391,12 +1505,19 @@ public partial class PlanificadorRutas : ComponentBase
alternativa.DistanciaSoloAPie);
}
var distanciasPiePorTramo = alternativa.DistanciasPiePorTramoAprox.Count > 0
? alternativa.DistanciasPiePorTramoAprox.ToArray()
: new[]
{
alternativa.DistanciaPieInicioAprox,
alternativa.DistanciaPieTransbordosAprox,
alternativa.DistanciaPieFinAprox
};
return UtilidadesTransitoDbus.CalcularCosteConPenalizacionPieSegundos(
duracionReal,
parametros,
alternativa.DistanciaPieInicioAprox,
alternativa.DistanciaPieTransbordosAprox,
alternativa.DistanciaPieFinAprox);
distanciasPiePorTramo);
}
/// <summary>

View File

@@ -432,16 +432,29 @@ public partial class PlanificadorRutas
if (!await AsegurarHistorialLocalCargadoAsync())
return;
var item = _historialLocal.FirstOrDefault(x => x.Id == id);
if (item is null)
var indiceEliminado = _historialLocal.FindIndex(x => x.Id == id);
if (indiceEliminado < 0)
return;
_historialLocal.Remove(item);
if (_historialLocalSeleccionadoId == id)
_historialLocalSeleccionadoId = string.Empty;
var estabaSeleccionado = _historialLocalSeleccionadoId == id;
_historialLocal.RemoveAt(indiceEliminado);
await PersistirHistorialLocalAsync();
if (estabaSeleccionado)
{
if (_historialLocal.Count == 0)
{
_historialLocalSeleccionadoId = string.Empty;
}
else
{
var siguiente = _historialLocal[Math.Min(indiceEliminado, _historialLocal.Count - 1)];
await AplicarRegistroHistorialAsync(siguiente);
SeleccionarHistorialLocal(siguiente.Id);
}
}
MostrarMensajeHistorial("Combinacion eliminada del historial personal.");
}
@@ -473,6 +486,8 @@ public partial class PlanificadorRutas
{
try
{
var indiceEliminado = _historialCompartido.FindIndex(x => x.Id == id);
var estabaSeleccionado = _historialCompartidoSeleccionadoId == id;
var ok = await HistorialRutasCompartidoService.EliminarAsync(id);
if (!ok)
{
@@ -481,9 +496,22 @@ public partial class PlanificadorRutas
}
await CargarHistorialCompartidoAsync();
_historialCompartido.RemoveAll(x => x.Id == id);
if (_historialCompartidoSeleccionadoId == id)
if (estabaSeleccionado)
{
if (_historialCompartido.Count == 0)
{
_historialCompartidoSeleccionadoId = string.Empty;
}
else
{
var indiceSiguiente = Math.Clamp(indiceEliminado, 0, _historialCompartido.Count - 1);
var siguiente = _historialCompartido[indiceSiguiente];
await AplicarRegistroHistorialAsync(siguiente);
SeleccionarHistorialCompartido(siguiente.Id);
}
}
MostrarMensajeHistorial("Combinacion eliminada del historial compartido.");
}

View File

@@ -1204,7 +1204,7 @@ public partial class PlanificadorRutas : ComponentBase
private bool _elevPopupMinimizado = false;
private const string _versionApp = "(v-20260727a)";
private const string _versionApp = "(v-20260728a)";
private double? _paradaElevG;

View File

@@ -192,7 +192,10 @@ public partial class PlanificadorRutas
? FactorPenalizacionDistanciaPiePorDefecto
: factor;
if (config.ParametroPenalizacionDistanciaPieMetros is { } parametro && double.IsFinite(parametro))
_parametroPenalizacionDistanciaPieMetros = parametro;
_parametroPenalizacionDistanciaPieMetros =
Math.Abs(parametro - 100.0) < 0.0001
? ParametroPenalizacionDistanciaPieMetrosPorDefecto
: parametro;
if (config.CoeficienteEsfuerzoAltura is { } coeficienteAltura && double.IsFinite(coeficienteAltura))
_coeficienteEsfuerzoAltura =
Math.Abs(coeficienteAltura - 1.6) < 0.0001 ||
@@ -315,7 +318,7 @@ public partial class PlanificadorRutas
_maxTransbordosPermitidos = 3;
_factorPenalizacionDistanciaPie = FactorPenalizacionDistanciaPiePorDefecto;
_parametroPenalizacionDistanciaPieMetros = 100.0;
_parametroPenalizacionDistanciaPieMetros = ParametroPenalizacionDistanciaPieMetrosPorDefecto;
_coeficienteEsfuerzoAltura = CoeficienteEsfuerzoAlturaPorDefecto;
_pesoTransbordoRankingMinutos = 4.0;
_factorEquilibradoAndarBus = 12.0;
@@ -365,7 +368,7 @@ public partial class PlanificadorRutas
_maxTransbordosPermitidos = 3;
_factorPenalizacionDistanciaPie = FactorPenalizacionDistanciaPiePorDefecto;
_parametroPenalizacionDistanciaPieMetros = 100.0;
_parametroPenalizacionDistanciaPieMetros = ParametroPenalizacionDistanciaPieMetrosPorDefecto;
_coeficienteEsfuerzoAltura = CoeficienteEsfuerzoAlturaPorDefecto;
_pesoTransbordoRankingMinutos = 4.0;
_factorEquilibradoAndarBus = 12.0;

View File

@@ -463,7 +463,7 @@ public partial class PlanificadorRutas : ComponentBase
await CerrarPopupsAsync();
ThrowIfPintadoObsoleto(versionPintado);
await FitRoutesJsAsync();
await FitRoutesJsAsync(centroPreferido: _coordenadasOrigen);
ThrowIfPintadoObsoleto(versionPintado);
StateHasChanged();
}
@@ -505,7 +505,7 @@ public partial class PlanificadorRutas : ComponentBase
if (paradasTramo.Count == 0)
continue;
var stops = BuildStopsDesdeParadas(paradasTramo);
var stops = BuildStopsForTramoBus(tramo);
var id = $"route_stops_{indice}_{tramo.Variante.Linea.Codigo}_{tramo.Variante.CodigoItinerario}_{NormalizarSentidoCodigo(tramo.Variante.Sentido?.Codigo)}";
var color = ColorCssDesdeVariante(tramo.Variante);

View File

@@ -20,6 +20,7 @@ public sealed class AlternativaRuta
public double DistanciaPieFinAprox { get; set; }
public double DistanciaPieTotalAprox =>
DistanciaPieInicioAprox + DistanciaPieTransbordosAprox + DistanciaPieFinAprox;
public List<double> DistanciasPiePorTramoAprox { get; set; } = new();
public List<double[,]> LineasPieCalculoElevacion { get; set; } = new();
public double EsfuerzoExtraPendienteMetros { get; set; }

View File

@@ -24,7 +24,7 @@ public sealed class ParametrosPlanificadorRuta
public int MargenTransbordoSegundos { get; set; } = 120;
public int SegundosPorParadaBus { get; set; } = 30;
public double FactorPenalizacionDistanciaPie { get; set; } = 1.35;
public double ParametroPenalizacionDistanciaPieMetros { get; set; } = 100.0;
public double ParametroPenalizacionDistanciaPieMetros { get; set; } = 200.0;
public double PesoTransbordoRankingMinutos { get; set; } = 4.0;
public double FactorEquilibradoAndarBus { get; set; } = 12.0;

View File

@@ -714,13 +714,16 @@ public sealed class BuscadorRutasTemporalesDbus
};
var duracionEstimada = Math.Max(0, (estadoDestino.Llegada - instanteSalida).TotalSeconds) + destino.TiempoAPie;
var distanciasPieTransbordos = ObtenerDistanciasPieTransbordos(estadoDestino);
var distanciasPiePorTramo = ConstruirDistanciasPiePorTramo(
origen.DistanciaAPie,
distanciasPieTransbordos,
destino.DistanciaAPie);
var puntuacionCoste = UtilidadesTransitoDbus.CalcularCosteConPenalizacionesRankingSegundos(
duracionEstimada,
parametros,
numeroTransbordos,
origen.DistanciaAPie,
estadoDestino.DistanciaPieTransbordos,
destino.DistanciaAPie);
distanciasPiePorTramo.ToArray());
var resultado = new ResultadoBusquedaRutaBusDbus
{
@@ -731,6 +734,7 @@ public sealed class BuscadorRutasTemporalesDbus
DistanciaPieFin = destino.DistanciaAPie,
TiempoPieFin = destino.TiempoAPie,
DistanciaPieTransbordos = estadoDestino.DistanciaPieTransbordos,
DistanciasPieTransbordosPorTramo = distanciasPieTransbordos,
TiempoEsperaInicialSegundos = estadoDestino.TiempoEsperaInicialSegundos,
TiempoEsperaTransbordosSegundos = estadoDestino.TiempoEsperaTransbordosSegundos,
DuracionEstimadaSegundos = duracionEstimada,
@@ -816,10 +820,12 @@ public sealed class BuscadorRutasTemporalesDbus
ParametrosPlanificadorRuta parametros)
{
var distanciaBus = Math.Max(0, resultado.RutaBus.DistanciaTotalBus);
var distanciaAndando =
UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(resultado.DistanciaPieInicio, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(resultado.DistanciaPieTransbordos, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(resultado.DistanciaPieFin, parametros);
var distanciaAndando = UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaTotalMetros(
ConstruirDistanciasPiePorTramo(
resultado.DistanciaPieInicio,
resultado.DistanciasPieTransbordosPorTramo,
resultado.DistanciaPieFin),
parametros);
var factor = double.IsFinite(parametros.FactorEquilibradoAndarBus)
? Math.Max(0, parametros.FactorEquilibradoAndarBus)
: 12.0;
@@ -830,6 +836,45 @@ public sealed class BuscadorRutasTemporalesDbus
: double.PositiveInfinity;
}
private static List<double> ObtenerDistanciasPieTransbordos(EstadoBusquedaParadaDbus estadoDestino)
{
var distancias = new List<double>();
var cursor = estadoDestino;
while (cursor is not null)
{
if (cursor.Movimiento is MovimientoPieTransbordoDbus movimiento &&
double.IsFinite(movimiento.DistanciaMetros) &&
movimiento.DistanciaMetros > 0)
{
distancias.Add(movimiento.DistanciaMetros);
}
cursor = cursor.EstadoAnterior;
}
distancias.Reverse();
return distancias;
}
private static List<double> ConstruirDistanciasPiePorTramo(
double distanciaInicio,
IEnumerable<double> distanciasTransbordos,
double distanciaFin)
{
var distancias = new List<double>();
AgregarDistancia(distanciaInicio);
foreach (var distancia in distanciasTransbordos)
AgregarDistancia(distancia);
AgregarDistancia(distanciaFin);
return distancias;
void AgregarDistancia(double distancia)
{
if (double.IsFinite(distancia) && distancia > 0)
distancias.Add(distancia);
}
}
private static double CalcularDistanciaBusEstado(EstadoBusquedaParadaDbus estadoDestino)
{
var distancia = 0.0;
@@ -1345,6 +1390,11 @@ public sealed class ResultadoBusquedaRutaBusDbus
/// </summary>
public double DistanciaPieTransbordos { get; init; }
/// <summary>
/// Distancias peatonales de cada transbordo, sin agregarlas antes de penalizarlas.
/// </summary>
public IReadOnlyList<double> DistanciasPieTransbordosPorTramo { get; init; } = Array.Empty<double>();
/// <summary>
/// Espera inicial acumulada.
/// </summary>

View File

@@ -295,6 +295,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
DistanciaPieInicioAprox = candidataBus.DistanciaPieInicio,
DistanciaPieFinAprox = candidataBus.DistanciaPieFin,
DistanciaPieTransbordosAprox = candidataBus.DistanciaPieTransbordos,
DistanciasPiePorTramoAprox = ConstruirDistanciasPiePorTramo(candidataBus),
TiempoPieInicio = candidataBus.TiempoPieInicio,
TiempoPieFin = candidataBus.TiempoPieFin,
TiempoEsperaInicialSegundos = candidataBus.TiempoEsperaInicialSegundos,
@@ -992,6 +993,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
DistanciaPieFin = destino.DistanciaAPie,
TiempoPieFin = destino.TiempoAPie,
DistanciaPieTransbordos = transferencia.DistanciaMetros,
DistanciasPieTransbordosPorTramo = new[] { transferencia.DistanciaMetros },
TiempoEsperaInicialSegundos = esperaInicial,
TiempoEsperaTransbordosSegundos = esperaTotalTransbordos,
DuracionEstimadaSegundos = duracionTotal,
@@ -1343,6 +1345,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
DistanciaPieFin = baseRuta.DistanciaPieFin,
TiempoPieFin = baseRuta.TiempoPieFin,
DistanciaPieTransbordos = baseRuta.DistanciaPieTransbordos,
DistanciasPieTransbordosPorTramo = baseRuta.DistanciasPieTransbordosPorTramo.ToArray(),
TiempoEsperaInicialSegundos = esperaInicial,
TiempoEsperaTransbordosSegundos = baseRuta.TiempoEsperaTransbordosSegundos,
DuracionEstimadaSegundos = duracionTotal,
@@ -1350,9 +1353,10 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
duracionTotal,
parametros,
numeroTransbordos,
ConstruirDistanciasPiePorTramo(
origen.DistanciaAPie,
baseRuta.DistanciaPieTransbordos,
baseRuta.DistanciaPieFin),
ObtenerDistanciasPieTransbordosPorTramo(baseRuta),
baseRuta.DistanciaPieFin).ToArray()),
RutaBus = ruta
};
@@ -1518,9 +1522,9 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
var distanciaAndando = parametros is null
? Math.Max(0, resultado.DistanciaPieTotal)
: UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(resultado.DistanciaPieInicio, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(resultado.DistanciaPieTransbordos, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(resultado.DistanciaPieFin, parametros);
: UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaTotalMetros(
ConstruirDistanciasPiePorTramo(resultado),
parametros);
var factor = parametros is not null && double.IsFinite(parametros.FactorEquilibradoAndarBus)
? Math.Max(0, parametros.FactorEquilibradoAndarBus)
: 12.0;
@@ -1531,6 +1535,42 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
: double.PositiveInfinity;
}
private static List<double> ConstruirDistanciasPiePorTramo(ResultadoBusquedaRutaBusDbus resultado)
=> ConstruirDistanciasPiePorTramo(
resultado.DistanciaPieInicio,
ObtenerDistanciasPieTransbordosPorTramo(resultado),
resultado.DistanciaPieFin);
private static IReadOnlyList<double> ObtenerDistanciasPieTransbordosPorTramo(
ResultadoBusquedaRutaBusDbus resultado)
{
if (resultado.DistanciasPieTransbordosPorTramo.Count > 0)
return resultado.DistanciasPieTransbordosPorTramo;
return double.IsFinite(resultado.DistanciaPieTransbordos) && resultado.DistanciaPieTransbordos > 0
? new[] { resultado.DistanciaPieTransbordos }
: Array.Empty<double>();
}
private static List<double> ConstruirDistanciasPiePorTramo(
double distanciaInicio,
IEnumerable<double> distanciasTransbordos,
double distanciaFin)
{
var distancias = new List<double>();
AgregarDistancia(distanciaInicio);
foreach (var distancia in distanciasTransbordos)
AgregarDistancia(distancia);
AgregarDistancia(distanciaFin);
return distancias;
void AgregarDistancia(double distancia)
{
if (double.IsFinite(distancia) && distancia > 0)
distancias.Add(distancia);
}
}
private static bool DebeBuscarTransbordosRobustos(
IReadOnlyList<ResultadoBusquedaRutaBusDbus> candidatasBus,
IReadOnlyList<ParadaCandidata> candidatasOrigen,
@@ -2033,6 +2073,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
ProveedorRuta = "v1",
LineaSoloAPie = osrm.linea,
LineasPieCalculoElevacion = new List<double[,]> { osrm.linea },
DistanciasPiePorTramoAprox = new List<double> { osrm.distancia },
DistanciaSoloAPie = osrm.distancia,
DuracionSoloAPie = duracion,
DuracionTotalAproxSegundos = duracion,
@@ -2052,6 +2093,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
ProveedorRuta = "v2",
LineaSoloAPie = valhalla.linea,
LineasPieCalculoElevacion = new List<double[,]> { valhalla.linea },
DistanciasPiePorTramoAprox = new List<double> { valhalla.distancia },
DistanciaSoloAPie = valhalla.distancia,
DuracionSoloAPie = duracion,
DuracionTotalAproxSegundos = duracion,
@@ -2091,6 +2133,23 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
});
}
private static void AgregarDistanciaPiePorTramo(AlternativaRuta alternativa, double distanciaMetros)
{
if (double.IsFinite(distanciaMetros) && distanciaMetros > 0)
alternativa.DistanciasPiePorTramoAprox.Add(distanciaMetros);
}
private static void AcumularDistanciaPieEnPrimerTramo(AlternativaRuta alternativa, double distanciaMetros)
{
if (!double.IsFinite(distanciaMetros) || distanciaMetros <= 0)
return;
if (alternativa.DistanciasPiePorTramoAprox.Count == 0)
alternativa.DistanciasPiePorTramoAprox.Add(distanciaMetros);
else
alternativa.DistanciasPiePorTramoAprox[0] += distanciaMetros;
}
/// <summary>
/// Recalcula una alternativa de bus usando caminatas exactas y horarios reales.
/// </summary>
@@ -2105,6 +2164,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
return double.PositiveInfinity;
alternativa.LineasPieCalculoElevacion.Clear();
alternativa.DistanciasPiePorTramoAprox.Clear();
alternativa.EsfuerzoExtraPendienteMetros = 0;
var tramosBus = alternativa.AlternativaBus.Tramos;
@@ -2155,6 +2215,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
alternativa.DistanciaPieInicioAprox = acceso.distancia > 0
? acceso.distancia
: UtilidadesTransitoDbus.CalcularDistanciaMetros(origenLatLon[0], origenLatLon[1], paradaInicioBus.Latitud, paradaInicioBus.Longitud);
AgregarDistanciaPiePorTramo(alternativa, alternativa.DistanciaPieInicioAprox);
alternativa.TiempoPieInicio = UtilidadesTransitoDbus.EstimarDuracionPieSegundos(alternativa.DistanciaPieInicioAprox, parametros);
total += alternativa.TiempoPieInicio;
cursor = UtilidadesTransitoDbus.AddSecondsSafe(cursor, alternativa.TiempoPieInicio);
@@ -2229,10 +2290,12 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
{
alternativa.DistanciaPieInicioAprox += distanciaTransferencia;
alternativa.TiempoPieInicio += UtilidadesTransitoDbus.EstimarDuracionPieSegundos(distanciaTransferencia, parametros);
AcumularDistanciaPieEnPrimerTramo(alternativa, distanciaTransferencia);
}
else
{
alternativa.DistanciaPieTransbordosAprox += distanciaTransferencia;
AgregarDistanciaPiePorTramo(alternativa, distanciaTransferencia);
}
var duracionTransferencia = UtilidadesTransitoDbus.EstimarDuracionPieSegundos(distanciaTransferencia, parametros);
@@ -2345,6 +2408,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
alternativa.DistanciaPieFinAprox = salidaFinal.distancia > 0
? salidaFinal.distancia
: UtilidadesTransitoDbus.CalcularDistanciaMetros(puntoUltimaLlegada[0], puntoUltimaLlegada[1], destinoLatLon[0], destinoLatLon[1]);
AgregarDistanciaPiePorTramo(alternativa, alternativa.DistanciaPieFinAprox);
alternativa.TiempoPieFin = UtilidadesTransitoDbus.EstimarDuracionPieSegundos(alternativa.DistanciaPieFinAprox, parametros);
total += alternativa.TiempoPieFin;
@@ -2462,6 +2526,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
DistanciaPieFin = candidataBase.DistanciaPieFin,
TiempoPieFin = candidataBase.TiempoPieFin,
DistanciaPieTransbordos = candidataBase.DistanciaPieTransbordos,
DistanciasPieTransbordosPorTramo = candidataBase.DistanciasPieTransbordosPorTramo.ToArray(),
TiempoEsperaInicialSegundos = esperaInicial,
TiempoEsperaTransbordosSegundos = candidataBase.TiempoEsperaTransbordosSegundos,
DuracionEstimadaSegundos = duracionEstimada,
@@ -2469,9 +2534,10 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
duracionEstimada,
parametros,
rutaDirecta.NumeroTransbordos,
ConstruirDistanciasPiePorTramo(
origenDirecto.DistanciaAPie,
candidataBase.DistanciaPieTransbordos,
candidataBase.DistanciaPieFin),
ObtenerDistanciasPieTransbordosPorTramo(candidataBase),
candidataBase.DistanciaPieFin).ToArray()),
RutaBus = rutaDirecta
};
@@ -3156,9 +3222,22 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
private static double CalcularDistanciaAndandoCorregidaMetros(
AlternativaRuta alternativa,
ParametrosPlanificadorRuta parametros)
=> UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(alternativa.DistanciaPieInicioAprox, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(alternativa.DistanciaPieTransbordosAprox, parametros)
+ UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaMetros(alternativa.DistanciaPieFinAprox, parametros);
=> UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaTotalMetros(
ObtenerDistanciasPiePorTramo(alternativa),
parametros);
private static IReadOnlyList<double> ObtenerDistanciasPiePorTramo(AlternativaRuta alternativa)
{
if (alternativa.DistanciasPiePorTramoAprox.Count > 0)
return alternativa.DistanciasPiePorTramoAprox;
return ConstruirDistanciasPiePorTramo(
alternativa.DistanciaPieInicioAprox,
alternativa.DistanciaPieTransbordosAprox > 0
? new[] { alternativa.DistanciaPieTransbordosAprox }
: Array.Empty<double>(),
alternativa.DistanciaPieFinAprox);
}
private static double DuracionVisibleOrdenacion(AlternativaRuta alternativa)
=> double.IsFinite(alternativa.DuracionTotalAproxSegundos)
@@ -3355,9 +3434,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
alternativa.DuracionTotalAproxSegundos,
parametros,
alternativa.NumeroTransbordosReales,
alternativa.DistanciaPieInicioAprox,
alternativa.DistanciaPieTransbordosAprox,
alternativa.DistanciaPieFinAprox);
ObtenerDistanciasPiePorTramo(alternativa).ToArray());
}
/// <summary>

View File

@@ -316,7 +316,7 @@ internal static class UtilidadesTransitoDbus
: 1.35;
var parametroBaseMetros = double.IsFinite(parametros.ParametroPenalizacionDistanciaPieMetros)
? Math.Abs(parametros.ParametroPenalizacionDistanciaPieMetros)
: 100.0;
: 200.0;
if (parametroBaseMetros <= 0)
parametroBaseMetros = 1.0;
@@ -325,6 +325,22 @@ internal static class UtilidadesTransitoDbus
return Math.Max(distanciaMetros, corregida);
}
/// <summary>
/// Aplica la correccion a cada tramo peatonal por separado y suma los resultados.
/// </summary>
public static double CalcularDistanciaPieCorregidaTotalMetros(
IEnumerable<double> distanciasPieMetros,
ParametrosPlanificadorRuta parametros)
{
var total = 0.0;
foreach (var distancia in distanciasPieMetros)
total += CalcularDistanciaPieCorregidaMetros(distancia, parametros);
return double.IsFinite(total) && total >= 0
? total
: double.PositiveInfinity;
}
/// <summary>
/// Calcula un coste interno que penaliza de forma progresiva la caminata sin cambiar el tiempo real.
/// </summary>

View File

@@ -322,7 +322,7 @@ window.rt.drawRoute = function (id, coords, options) {
}
};
window.rt.fitRoutes = function (coords) {
window.rt.fitRoutes = function (coords, preferredCenter) {
const map = window.__rtLeafletMap;
if (!map || !window.L) return false;
@@ -364,7 +364,14 @@ window.rt.fitRoutes = function (coords) {
const geometryBounds = window.L.latLngBounds(points);
if (!geometryBounds.isValid()) return false;
map.panTo(geometryBounds.getCenter(), {
const center = Array.isArray(preferredCenter)
&& preferredCenter.length >= 2
&& Number.isFinite(Number(preferredCenter[0]))
&& Number.isFinite(Number(preferredCenter[1]))
? window.L.latLng(Number(preferredCenter[0]), Number(preferredCenter[1]))
: geometryBounds.getCenter();
map.panTo(center, {
animate: true,
duration: 0.35
});