diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs
index 9bf6988..c98ce10 100644
--- a/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs
+++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Estado.cs
@@ -151,7 +151,7 @@ public partial class PlanificadorRutas : ComponentBase
}
///
- /// Expone el factor que convierte metros andando a metros equivalentes de bus en el modo equilibrado.
+ /// Expone el factor que reduce el peso de la distancia en bus en el modo equilibrado.
///
private string FactorEquilibradoAndarBusTexto
{
@@ -164,8 +164,8 @@ public partial class PlanificadorRutas : ComponentBase
if (!double.TryParse(texto, NumberStyles.Float, CultureInfo.InvariantCulture, out var valor))
return;
- if (double.IsFinite(valor))
- _factorEquilibradoAndarBus = Math.Max(0, valor);
+ if (double.IsFinite(valor) && valor > 0)
+ _factorEquilibradoAndarBus = valor;
}
}
@@ -1420,25 +1420,6 @@ public partial class PlanificadorRutas : ComponentBase
return EstimarDuracionPieSegundos(distanciaCorregida);
}
- ///
- /// Calcula la aportacion de todos los tramos andando a la distancia equilibrada.
- ///
- private double CalcularDistanciaEquilibradaAndandoAlternativa(AlternativaRuta? alternativa)
- {
- if (alternativa is null)
- return 0;
-
- var distanciaAndando = CalcularDistanciaCorregidaAlternativa(alternativa);
- var factor = double.IsFinite(_factorEquilibradoAndarBus)
- ? Math.Max(0, _factorEquilibradoAndarBus)
- : FactorEquilibradoAndarBusPorDefecto;
- var distanciaEquilibrada = Math.Max(0, distanciaAndando) * factor;
-
- return double.IsFinite(distanciaEquilibrada)
- ? distanciaEquilibrada
- : 0;
- }
-
private double CalcularScoreEquilibradoFactor(AlternativaRuta? alternativa)
{
if (alternativa is null)
@@ -1453,11 +1434,14 @@ public partial class PlanificadorRutas : ComponentBase
distanciaBus = Math.Max(0, alternativa.AlternativaBus.DistanciaTotalBus);
}
- var distanciaEquilibradaAndando = CalcularDistanciaEquilibradaAndandoAlternativa(alternativa);
+ var distanciaAndando = CalcularDistanciaCorregidaAlternativa(alternativa);
+ var factor = double.IsFinite(_factorEquilibradoAndarBus) && _factorEquilibradoAndarBus > 0
+ ? _factorEquilibradoAndarBus
+ : FactorEquilibradoAndarBusPorDefecto;
var penalizacionTransbordos = UtilidadesTransitoDbus.CalcularPenalizacionTransbordosRankingMetros(
alternativa.NumeroTransbordosReales,
CrearParametrosPenalizacionActuales());
- var score = distanciaBus + distanciaEquilibradaAndando + penalizacionTransbordos;
+ var score = distanciaAndando + (distanciaBus / factor) + penalizacionTransbordos;
return double.IsFinite(score) && score >= 0
? score
: double.PositiveInfinity;
@@ -1469,7 +1453,7 @@ public partial class PlanificadorRutas : ComponentBase
if (!double.IsFinite(score))
return string.Empty;
- return (score / 1000.0).ToString("0.000", CultureInfo.InvariantCulture);
+ return score.ToString("0", CultureInfo.InvariantCulture);
}
private async Task RecalcularRutaEquilibradaTrasCambioFactorAsync()
diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs
index e368a96..fc18127 100644
--- a/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs
+++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Historial.cs
@@ -27,6 +27,9 @@ public partial class PlanificadorRutas
private CancellationTokenSource? _historialCompartidoCts;
private string _historialLocalSeleccionadoId = string.Empty;
private string _historialCompartidoSeleccionadoId = string.Empty;
+ private TipoReferenciaHistorial _tipoReferenciaHistorial;
+ private string _historialReferenciaId = string.Empty;
+ private bool _rutaActualDerivadaDeHistorial;
private string _mensajeHistorial = string.Empty;
private bool _mensajeHistorialEsError = false;
private bool _mostrarHistorialRutas = false;
@@ -43,6 +46,13 @@ public partial class PlanificadorRutas
private string _resumenErrorHistorialLocal = string.Empty;
private string _detalleErrorHistorialLocal = string.Empty;
+ private enum TipoReferenciaHistorial
+ {
+ Ninguna,
+ Personal,
+ Compartido
+ }
+
private sealed class ResultadoStorageNavegador
{
[JsonPropertyName("ok")]
@@ -400,6 +410,11 @@ public partial class PlanificadorRutas
_historialLocal.AddRange(items);
if (!_historialLocal.Any(x => x.Id == _historialLocalSeleccionadoId))
_historialLocalSeleccionadoId = string.Empty;
+ if (_tipoReferenciaHistorial == TipoReferenciaHistorial.Personal &&
+ !_historialLocal.Any(x => x.Id == _historialReferenciaId))
+ {
+ LimpiarReferenciaHistorial();
+ }
_historialLocalCargado = true;
}
@@ -632,11 +647,18 @@ public partial class PlanificadorRutas
if (_historialCompartido.Count == 0)
{
_historialCompartidoSeleccionadoId = string.Empty;
+ if (_tipoReferenciaHistorial == TipoReferenciaHistorial.Compartido)
+ LimpiarReferenciaHistorial();
return;
}
if (!_historialCompartido.Any(x => x.Id == _historialCompartidoSeleccionadoId))
_historialCompartidoSeleccionadoId = string.Empty;
+ if (_tipoReferenciaHistorial == TipoReferenciaHistorial.Compartido &&
+ !_historialCompartido.Any(x => x.Id == _historialReferenciaId))
+ {
+ LimpiarReferenciaHistorial();
+ }
}
catch (Exception)
{
@@ -783,12 +805,14 @@ public partial class PlanificadorRutas
{
_historialLocalSeleccionadoId = id;
_historialCompartidoSeleccionadoId = string.Empty;
+ EstablecerReferenciaHistorial(TipoReferenciaHistorial.Personal, id);
}
private void SeleccionarHistorialCompartido(string id)
{
_historialLocalSeleccionadoId = string.Empty;
_historialCompartidoSeleccionadoId = id;
+ EstablecerReferenciaHistorial(TipoReferenciaHistorial.Compartido, id);
}
private void LimpiarSeleccionHistorial()
@@ -797,6 +821,74 @@ public partial class PlanificadorRutas
_historialCompartidoSeleccionadoId = string.Empty;
}
+ private bool PrepararDerivacionHistorialParaRecalculo()
+ {
+ var procedeDeHistorial = _tipoReferenciaHistorial != TipoReferenciaHistorial.Ninguna &&
+ !string.IsNullOrWhiteSpace(_historialReferenciaId);
+
+ _rutaActualDerivadaDeHistorial = false;
+ LimpiarSeleccionHistorial();
+ return procedeDeHistorial;
+ }
+
+ private void ConfirmarDerivacionHistorial()
+ {
+ _rutaActualDerivadaDeHistorial = ExisteReferenciaHistorialActual();
+ }
+
+ private void EstablecerReferenciaHistorial(TipoReferenciaHistorial tipo, string id)
+ {
+ _tipoReferenciaHistorial = tipo;
+ _historialReferenciaId = id;
+ _rutaActualDerivadaDeHistorial = false;
+ }
+
+ private void LimpiarReferenciaHistorial()
+ {
+ _tipoReferenciaHistorial = TipoReferenciaHistorial.Ninguna;
+ _historialReferenciaId = string.Empty;
+ _rutaActualDerivadaDeHistorial = false;
+ }
+
+ private bool ExisteReferenciaHistorialActual()
+ => _tipoReferenciaHistorial switch
+ {
+ TipoReferenciaHistorial.Personal =>
+ _historialLocal.Any(x => x.Id == _historialReferenciaId),
+ TipoReferenciaHistorial.Compartido =>
+ _historialCompartido.Any(x => x.Id == _historialReferenciaId),
+ _ => false
+ };
+
+ private bool EsReferenciaDerivadaHistorialPersonal(string id)
+ => _rutaActualDerivadaDeHistorial &&
+ _tipoReferenciaHistorial == TipoReferenciaHistorial.Personal &&
+ string.Equals(_historialReferenciaId, id, StringComparison.OrdinalIgnoreCase);
+
+ private bool EsReferenciaDerivadaHistorialCompartido(string id)
+ => _rutaActualDerivadaDeHistorial &&
+ _tipoReferenciaHistorial == TipoReferenciaHistorial.Compartido &&
+ string.Equals(_historialReferenciaId, id, StringComparison.OrdinalIgnoreCase);
+
+ private string TextoReferenciaHistorialDerivado()
+ {
+ if (!_rutaActualDerivadaDeHistorial)
+ return string.Empty;
+
+ var (nombre, indice) = _tipoReferenciaHistorial switch
+ {
+ TipoReferenciaHistorial.Personal =>
+ ("Personal", _historialLocal.FindIndex(x => x.Id == _historialReferenciaId)),
+ TipoReferenciaHistorial.Compartido =>
+ ("Compartido", _historialCompartido.FindIndex(x => x.Id == _historialReferenciaId)),
+ _ => (string.Empty, -1)
+ };
+
+ return indice >= 0
+ ? $"Ruta actual derivada del Historial {nombre} n.º {indice + 1}."
+ : string.Empty;
+ }
+
private async Task CompartirEscenarioActualAsync()
{
var actual = ConstruirRegistroHistorialActual()
@@ -854,6 +946,11 @@ public partial class PlanificadorRutas
var estabaSeleccionado = _historialLocalSeleccionadoId == id;
_historialLocal.RemoveAt(indiceEliminado);
+ if (_tipoReferenciaHistorial == TipoReferenciaHistorial.Personal &&
+ string.Equals(_historialReferenciaId, id, StringComparison.OrdinalIgnoreCase))
+ {
+ LimpiarReferenciaHistorial();
+ }
await PersistirHistorialLocalAsync();
@@ -924,6 +1021,11 @@ public partial class PlanificadorRutas
await CargarHistorialCompartidoAsync();
_historialCompartido.RemoveAll(x => x.Id == id);
+ if (_tipoReferenciaHistorial == TipoReferenciaHistorial.Compartido &&
+ string.Equals(_historialReferenciaId, id, StringComparison.OrdinalIgnoreCase))
+ {
+ LimpiarReferenciaHistorial();
+ }
if (estabaSeleccionado)
{
@@ -973,9 +1075,11 @@ public partial class PlanificadorRutas
_criterioPrioritarioRuta = NormalizarCriterioRuta(item.CriterioPrioritarioRuta, item.PreferenciaEtiquetaRuta);
SincronizarPreferenciaDesdeCriterioRuta();
- if (item.FactorEquilibradoAndarBus is { } factorEquilibrado && double.IsFinite(factorEquilibrado))
+ if (item.FactorEquilibradoAndarBus is { } factorEquilibrado &&
+ double.IsFinite(factorEquilibrado) &&
+ factorEquilibrado > 0)
{
- _factorEquilibradoAndarBus = Math.Max(0, factorEquilibrado);
+ _factorEquilibradoAndarBus = factorEquilibrado;
SincronizarTextosPenalizacionPie();
if (_configuracionTemporalPreviaHistorial is not null)
@@ -1063,8 +1167,9 @@ public partial class PlanificadorRutas
HoraSimulada = TimeOnly.FromDateTime(ahora).ToString("HH:mm:ss", CultureInfo.InvariantCulture),
CriterioPrioritarioRuta = _criterioPrioritarioRuta,
PreferenciaEtiquetaRuta = _preferenciaEtiquetaRuta,
- FactorEquilibradoAndarBus = double.IsFinite(_factorEquilibradoAndarBus)
- ? Math.Max(0, _factorEquilibradoAndarBus)
+ FactorEquilibradoAndarBus = double.IsFinite(_factorEquilibradoAndarBus) &&
+ _factorEquilibradoAndarBus > 0
+ ? _factorEquilibradoAndarBus
: FactorEquilibradoAndarBusPorDefecto,
ActivarFiltroLineas = _activarRangoLineas,
LineasPermitidas = ObtenerLineasPermitidasSeleccionadas().ToList(),
@@ -1194,8 +1299,10 @@ public partial class PlanificadorRutas
var fecha = item.UsarHoraSimulada ? item.FechaSimulada?.Trim() ?? string.Empty : string.Empty;
var hora = item.UsarHoraSimulada ? item.HoraSimulada?.Trim() ?? string.Empty : string.Empty;
var criterio = NormalizarCriterioRuta(item.CriterioPrioritarioRuta, item.PreferenciaEtiquetaRuta);
- var factorEquilibrado = item.FactorEquilibradoAndarBus is { } factor && double.IsFinite(factor)
- ? Math.Max(0, factor).ToString("0.######", CultureInfo.InvariantCulture)
+ var factorEquilibrado = item.FactorEquilibradoAndarBus is { } factor &&
+ double.IsFinite(factor) &&
+ factor > 0
+ ? factor.ToString("0.######", CultureInfo.InvariantCulture)
: string.Empty;
var lineas = item.ActivarFiltroLineas
? string.Join(",", NormalizarLineasHistorial(item.LineasPermitidas))
diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs
index b160338..d726c85 100644
--- a/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs
+++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Itinerarios.cs
@@ -1202,7 +1202,7 @@ public partial class PlanificadorRutas : ComponentBase
private bool _elevPopupMinimizado = false;
- private const string _versionApp = "(v-20260807b)";
+ private const string _versionApp = "(v-20260825b)";
private double? _paradaElevIdee;
diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs
index 1bffe95..b65f8fc 100644
--- a/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs
+++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Persistencia.cs
@@ -227,11 +227,13 @@ public partial class PlanificadorRutas
: coeficienteAltura;
if (config.PesoTransbordoRankingMinutos is { } pesoTransbordo && double.IsFinite(pesoTransbordo))
_pesoTransbordoRankingMinutos = Math.Abs(pesoTransbordo - 8.0) < 0.0001 ? 4.0 : Math.Max(0, pesoTransbordo);
- if (config.FactorEquilibradoAndarBus is { } factorEquilibrado && double.IsFinite(factorEquilibrado))
+ if (config.FactorEquilibradoAndarBus is { } factorEquilibrado &&
+ double.IsFinite(factorEquilibrado) &&
+ factorEquilibrado > 0)
_factorEquilibradoAndarBus = (config.VersionFactorEquilibrado ?? 0) < VersionPersistenciaFactorEquilibrado &&
Math.Abs(factorEquilibrado - 12.0) < 0.0001
? FactorEquilibradoAndarBusPorDefecto
- : Math.Max(0, factorEquilibrado);
+ : factorEquilibrado;
var migrarValoresPendientes = (config.VersionPendientes ?? 0) < VersionPersistenciaPendientes;
_mostrarElevacionesRuta = migrarValoresPendientes
? true
diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs
index 93c03fd..f14e24d 100644
--- a/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs
+++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Planificacion.cs
@@ -1270,9 +1270,123 @@ public partial class PlanificadorRutas : ComponentBase
var listaOrdenada = ordenadas.ToList();
_opcionesRuta.Clear();
_opcionesRuta.AddRange(listaOrdenada);
+ FiltrarAlternativasBusRedundantes();
RenumerarEtiquetasGenericasOpcionesRuta();
}
+ ///
+ /// Conserva la mejor alternativa de cada direccion de acceso a una misma linea
+ /// y descarta rutas en bus que no ahorran ninguna distancia andando.
+ ///
+ private void FiltrarAlternativasBusRedundantes()
+ {
+ if (_opcionesRuta.Count <= 1)
+ return;
+
+ var distanciaSoloPie = _opcionesRuta
+ .Where(opcion => opcion.EsSoloAPie &&
+ double.IsFinite(opcion.DistanciaSoloAPie) &&
+ opcion.DistanciaSoloAPie > 0)
+ .Select(opcion => opcion.DistanciaSoloAPie)
+ .DefaultIfEmpty(double.PositiveInfinity)
+ .Min();
+
+ var conservadas = new List(_opcionesRuta.Count);
+ foreach (var candidata in _opcionesRuta)
+ {
+ if (candidata.EsSoloAPie)
+ {
+ conservadas.Add(candidata);
+ continue;
+ }
+
+ if (double.IsFinite(distanciaSoloPie) &&
+ double.IsFinite(candidata.DistanciaPieTotalAprox) &&
+ candidata.DistanciaPieTotalAprox >= distanciaSoloPie)
+ {
+ continue;
+ }
+
+ var repiteDireccionAcceso = conservadas.Any(referencia =>
+ !referencia.EsSoloAPie &&
+ EsMismaLineaInicial(referencia, candidata) &&
+ CaminanEnLaMismaDireccionDesdeOrigen(referencia, candidata));
+
+ if (!repiteDireccionAcceso)
+ conservadas.Add(candidata);
+ }
+
+ if (conservadas.Count == _opcionesRuta.Count)
+ return;
+
+ _opcionesRuta.Clear();
+ _opcionesRuta.AddRange(conservadas);
+ }
+
+ private static bool EsMismaLineaInicial(
+ AlternativaRuta referencia,
+ AlternativaRuta candidata)
+ {
+ var tramoReferencia = referencia.AlternativaBus?.Tramos.FirstOrDefault();
+ var tramoCandidata = candidata.AlternativaBus?.Tramos.FirstOrDefault();
+ if (tramoReferencia is null || tramoCandidata is null)
+ return false;
+
+ return string.Equals(
+ UtilidadesTransitoDbus.LineaCodigoStr(tramoReferencia.Variante),
+ UtilidadesTransitoDbus.LineaCodigoStr(tramoCandidata.Variante),
+ StringComparison.OrdinalIgnoreCase) &&
+ tramoReferencia.Variante.CodigoItinerario == tramoCandidata.Variante.CodigoItinerario;
+ }
+
+ private bool CaminanEnLaMismaDireccionDesdeOrigen(
+ AlternativaRuta referencia,
+ AlternativaRuta candidata)
+ {
+ if (_coordenadasOrigen is null ||
+ _coordenadasOrigen.Length < 2 ||
+ referencia.OrigenParada is null ||
+ candidata.OrigenParada is null)
+ {
+ return false;
+ }
+
+ var latitudOrigen = _coordenadasOrigen[0];
+ var longitudOrigen = _coordenadasOrigen[1];
+ if (!double.IsFinite(latitudOrigen) || !double.IsFinite(longitudOrigen))
+ return false;
+
+ var metrosPorGradoLatitud = 111_320d;
+ var metrosPorGradoLongitud =
+ metrosPorGradoLatitud * Math.Cos(latitudOrigen * Math.PI / 180d);
+
+ var referenciaX =
+ (referencia.OrigenParada.Longitud - longitudOrigen) * metrosPorGradoLongitud;
+ var referenciaY =
+ (referencia.OrigenParada.Latitud - latitudOrigen) * metrosPorGradoLatitud;
+ var candidataX =
+ (candidata.OrigenParada.Longitud - longitudOrigen) * metrosPorGradoLongitud;
+ var candidataY =
+ (candidata.OrigenParada.Latitud - latitudOrigen) * metrosPorGradoLatitud;
+
+ var moduloReferencia = Math.Sqrt(
+ referenciaX * referenciaX + referenciaY * referenciaY);
+ var moduloCandidata = Math.Sqrt(
+ candidataX * candidataX + candidataY * candidataY);
+ if (!double.IsFinite(moduloReferencia) ||
+ !double.IsFinite(moduloCandidata) ||
+ moduloReferencia < 1d ||
+ moduloCandidata < 1d)
+ {
+ return false;
+ }
+
+ var cosenoDireccion =
+ (referenciaX * candidataX + referenciaY * candidataY) /
+ (moduloReferencia * moduloCandidata);
+ return double.IsFinite(cosenoDireccion) && cosenoDireccion >= 0d;
+ }
+
private void RenumerarEtiquetasGenericasOpcionesRuta()
{
for (var i = 0; i < _opcionesRuta.Count; i++)
@@ -1744,8 +1858,8 @@ public partial class PlanificadorRutas : ComponentBase
_mostrarElevacionesRuta = _mostrarElevacionesRutaConfiguracion;
- if (!_aplicandoRegistroHistorial)
- LimpiarSeleccionHistorial();
+ var confirmarDerivacionHistorial = !_aplicandoRegistroHistorial &&
+ PrepararDerivacionHistorialParaRecalculo();
var cronometroCalculo = System.Diagnostics.Stopwatch.StartNew();
_panelRutasMovilContraido = _mostrarBuscadorMapa;
@@ -1872,6 +1986,8 @@ public partial class PlanificadorRutas : ComponentBase
{
await RegistrarEscenarioActualEnHistorialLocalAsync();
}
+ if (confirmarDerivacionHistorial)
+ ConfirmarDerivacionHistorial();
await ActualizarResumenTecnicoRutaAsync(CancellationToken.None);
_tiempoUltimoCalculoRuta = cronometroCalculo.Elapsed;
StateHasChanged();
diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs b/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs
index 1bbbaba..c10148b 100644
--- a/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs
+++ b/RutasDBUS/Components/Pages/PlanificadorRutas.Renderizado.cs
@@ -1151,6 +1151,8 @@ public partial class PlanificadorRutas : ComponentBase
_coordenadasOrigen = null;
_coordenadasDestino = null;
+ LimpiarSeleccionHistorial();
+ LimpiarReferenciaHistorial();
_textoBusquedaOrigen = string.Empty;
_textoBusquedaDestino = string.Empty;
_ubicacionOrigenSeleccionada = null;
diff --git a/RutasDBUS/Components/Pages/PlanificadorRutas.razor b/RutasDBUS/Components/Pages/PlanificadorRutas.razor
index 5329467..112042d 100644
--- a/RutasDBUS/Components/Pages/PlanificadorRutas.razor
+++ b/RutasDBUS/Components/Pages/PlanificadorRutas.razor
@@ -913,7 +913,6 @@
: _duracionTotalSegundos;
var dRecta = DistanciaLineaRectaOrigenDestino();
var dCorregida = CalcularDistanciaCorregidaAlternativa(altSeleccionada);
- var dEquilibradaAndando = CalcularDistanciaEquilibradaAndandoAlternativa(altSeleccionada);
var xyzOrigen = FormatearResumenXYZOrigen();
var xyzDestino = FormatearResumenXYZDestino();
var callejeroOrigen = FormatearResumenCallejeroOrigen();
@@ -934,7 +933,7 @@
}
- @if (dRecta > 0 || dCorregida > 0 || dEquilibradaAndando > 0)
+ @if (dRecta > 0 || dCorregida > 0)
{
@if (dRecta > 0)
@@ -945,10 +944,6 @@
{
d.Corregida a pie: @FormatearDistanciaDetalleRuta(dCorregida)
}
- @if (dEquilibradaAndando > 0)
- {
-
d.Equilib. A: @FormatearDistanciaDetalleRuta(dEquilibradaAndando)
- }
@if (!string.IsNullOrWhiteSpace(scoreEquilibradoSeleccionado))
{
Score equilibrado A: @scoreEquilibradoSeleccionado
@@ -1067,12 +1062,18 @@
{
var item = _historialLocal[i];
var numeroPersonal = i + 1;
+ var esReferenciaDerivada = EsReferenciaDerivadaHistorialPersonal(item.Id);
-
+
@@ -1129,12 +1130,18 @@
{
var item = _historialCompartido[i];
var numeroCompartido = i + 1;
+ var esReferenciaDerivada = EsReferenciaDerivadaHistorialCompartido(item.Id);
-
+
@@ -1150,7 +1157,17 @@
}
- @if (!string.IsNullOrWhiteSpace(_mensajeHistorial))
+ @{ var textoReferenciaDerivada = TextoReferenciaHistorialDerivado(); }
+ @if (!string.IsNullOrWhiteSpace(textoReferenciaDerivada))
+ {
+
+ *
+ @textoReferenciaDerivada
+
+ }
+
+ @if (!string.IsNullOrWhiteSpace(_mensajeHistorial) &&
+ (string.IsNullOrWhiteSpace(textoReferenciaDerivada) || _mensajeHistorialEsError))
{
@_mensajeHistorial
@@ -1499,9 +1516,9 @@
diff --git a/RutasDBUS/Modelos/Planificacion/ParadaCandidata.cs b/RutasDBUS/Modelos/Planificacion/ParadaCandidata.cs
index ccc6eb0..fde8307 100644
--- a/RutasDBUS/Modelos/Planificacion/ParadaCandidata.cs
+++ b/RutasDBUS/Modelos/Planificacion/ParadaCandidata.cs
@@ -34,6 +34,7 @@ public sealed class ParametrosPlanificadorRuta
public double FactorPenalizacionDistanciaPie { get; set; } = 1.35;
public double ParametroPenalizacionDistanciaPieMetros { get; set; } = 200.0;
public double PesoTransbordoRankingMinutos { get; set; } = 4.0;
+ // Divisor aplicado a la distancia en bus dentro del score equilibrado.
public double FactorEquilibradoAndarBus { get; set; } = 6.0;
// selección candidatas
diff --git a/RutasDBUS/Servicios/Historial/ServicioHistorialRutasCompartido.cs b/RutasDBUS/Servicios/Historial/ServicioHistorialRutasCompartido.cs
index d50ecfb..7762edb 100644
--- a/RutasDBUS/Servicios/Historial/ServicioHistorialRutasCompartido.cs
+++ b/RutasDBUS/Servicios/Historial/ServicioHistorialRutasCompartido.cs
@@ -315,8 +315,10 @@ public sealed class ServicioHistorialRutasCompartido : IHistorialRutasCompartido
var criterio = NormalizarTextoClave(item.CriterioPrioritarioRuta);
if (string.IsNullOrWhiteSpace(criterio))
criterio = NormalizarTextoClave(item.PreferenciaEtiquetaRuta);
- var factorEquilibrado = item.FactorEquilibradoAndarBus is { } factor && double.IsFinite(factor)
- ? Math.Max(0, factor).ToString("0.######", CultureInfo.InvariantCulture)
+ var factorEquilibrado = item.FactorEquilibradoAndarBus is { } factor &&
+ double.IsFinite(factor) &&
+ factor > 0
+ ? factor.ToString("0.######", CultureInfo.InvariantCulture)
: string.Empty;
var lineas = item.ActivarFiltroLineas
? string.Join(",", NormalizarLineas(item.LineasPermitidas))
diff --git a/RutasDBUS/Servicios/Planificacion/BuscadorRutasTemporalesDbus.cs b/RutasDBUS/Servicios/Planificacion/BuscadorRutasTemporalesDbus.cs
index 3be96fa..a265d8b 100644
--- a/RutasDBUS/Servicios/Planificacion/BuscadorRutasTemporalesDbus.cs
+++ b/RutasDBUS/Servicios/Planificacion/BuscadorRutasTemporalesDbus.cs
@@ -826,14 +826,15 @@ public sealed class BuscadorRutasTemporalesDbus
resultado.DistanciasPieTransbordosPorTramo,
resultado.DistanciaPieFin),
parametros);
- var factor = double.IsFinite(parametros.FactorEquilibradoAndarBus)
- ? Math.Max(0, parametros.FactorEquilibradoAndarBus)
+ var factor = double.IsFinite(parametros.FactorEquilibradoAndarBus) &&
+ parametros.FactorEquilibradoAndarBus > 0
+ ? parametros.FactorEquilibradoAndarBus
: 6.0;
var penalizacionTransbordos = UtilidadesTransitoDbus.CalcularPenalizacionTransbordosRankingMetros(
UtilidadesTransitoDbus.ContarTransbordosReales(resultado.RutaBus.Tramos),
parametros);
- var score = distanciaBus + (distanciaAndando * factor) + penalizacionTransbordos;
+ var score = distanciaAndando + (distanciaBus / factor) + penalizacionTransbordos;
return double.IsFinite(score) && score >= 0
? score
: double.PositiveInfinity;
diff --git a/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs b/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs
index 46e57af..fbe6257 100644
--- a/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs
+++ b/RutasDBUS/Servicios/Planificacion/PlanificadorRutasServicio.cs
@@ -1543,8 +1543,10 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
: UtilidadesTransitoDbus.CalcularDistanciaPieCorregidaTotalMetros(
ConstruirDistanciasPiePorTramo(resultado),
parametros);
- var factor = parametros is not null && double.IsFinite(parametros.FactorEquilibradoAndarBus)
- ? Math.Max(0, parametros.FactorEquilibradoAndarBus)
+ var factor = parametros is not null &&
+ double.IsFinite(parametros.FactorEquilibradoAndarBus) &&
+ parametros.FactorEquilibradoAndarBus > 0
+ ? parametros.FactorEquilibradoAndarBus
: 6.0;
var penalizacionTransbordos = parametros is null
? 0
@@ -1552,7 +1554,7 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
UtilidadesTransitoDbus.ContarTransbordosReales(resultado.RutaBus.Tramos),
parametros);
- var score = distanciaBus + (distanciaAndando * factor) + penalizacionTransbordos;
+ var score = distanciaAndando + (distanciaBus / factor) + penalizacionTransbordos;
return double.IsFinite(score) && score >= 0
? score
: double.PositiveInfinity;
@@ -3244,14 +3246,15 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
var distanciaBus = Math.Max(0, alternativa.AlternativaBus.DistanciaTotalBus);
var distanciaAndando = CalcularDistanciaAndandoCorregidaMetros(alternativa, parametros);
- var factor = double.IsFinite(parametros.FactorEquilibradoAndarBus)
- ? Math.Max(0, parametros.FactorEquilibradoAndarBus)
+ var factor = double.IsFinite(parametros.FactorEquilibradoAndarBus) &&
+ parametros.FactorEquilibradoAndarBus > 0
+ ? parametros.FactorEquilibradoAndarBus
: 6.0;
var penalizacionTransbordos = UtilidadesTransitoDbus.CalcularPenalizacionTransbordosRankingMetros(
alternativa.NumeroTransbordosReales,
parametros);
- var score = distanciaBus + (distanciaAndando * factor) + penalizacionTransbordos;
+ var score = distanciaAndando + (distanciaBus / factor) + penalizacionTransbordos;
return double.IsFinite(score) && score >= 0
? score
: double.PositiveInfinity;
@@ -3508,8 +3511,8 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
}
///
- /// Firma orientada a UI: agrupa alternativas con la misma secuencia de lineas y sentidos
- /// aunque cambie la parada exacta.
+ /// Firma orientada a UI: agrupa solo alternativas con el mismo recorrido visible.
+ /// Las paradas forman parte de la identidad porque cambian el acceso a pie y sus pendientes.
///
private static string CrearFirmaFamiliaRutaBus(RutaBusAlternativa alternativa)
{
@@ -3518,7 +3521,8 @@ public sealed class PlanificadorRutasServicio : IPlanificadorRutas
{
var linea = UtilidadesTransitoDbus.LineaCodigoStr(tramo.Variante);
var sentido = UtilidadesTransitoDbus.NormalizarSentidoCodigo(tramo.Variante.Sentido?.Codigo);
- var parte = $"{linea}.{tramo.Variante.CodigoItinerario}-{sentido}";
+ var parte = $"{linea}.{tramo.Variante.CodigoItinerario}-{sentido}:" +
+ $"{tramo.CodigoParadaInicio}>{tramo.CodigoParadaFin}";
if (partes.Count == 0 || !string.Equals(partes[^1], parte, StringComparison.OrdinalIgnoreCase))
partes.Add(parte);
}
diff --git a/RutasDBUS/wwwroot/app.css b/RutasDBUS/wwwroot/app.css
index 6f1cda5..1f8ac76 100644
--- a/RutasDBUS/wwwroot/app.css
+++ b/RutasDBUS/wwwroot/app.css
@@ -1232,6 +1232,24 @@ html, body {
background: rgba(21,128,61,.18);
}
+.history-item--derived-source .history-item-main {
+ border-color: rgba(245,158,11,.72);
+ background: rgba(120,53,15,.17);
+}
+
+.history-derived-marker {
+ color: #fbbf24;
+ font-weight: 800;
+}
+
+.history-derived-note {
+ display: flex;
+ align-items: baseline;
+ gap: .35rem;
+ font-size: .76rem;
+ color: #fcd34d;
+}
+
.history-item-action,
.history-item-delete {
flex: 0 0 32px;