- 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)
{
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 parada = paradasOrdenadas[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)
_historialCompartidoSeleccionadoId = string.Empty;
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);