v-20260914a
- punto z mas pequeño - parada destacada - restaurar valores por itinerairos y lineas - intercambio en el buscar - etiqyetas de soluciones elimiandas - aumentado el nuemro de puntos de exclusion - arreglado zoans de exlusion sin solucion
This commit is contained in:
@@ -54,6 +54,31 @@ async Task<(double[,]? linea, double distancia, double duracion)> Walk(List<List
|
||||
List<double[]> Ring(double lon, double lat, double size) =>
|
||||
new() { new[] { lon, lat }, new[] { lon + size, lat }, new[] { lon + size, lat + size },
|
||||
new[] { lon, lat + size }, new[] { lon, lat } };
|
||||
string Polyline6(params (double lat, double lon)[] puntos)
|
||||
{
|
||||
var texto = new System.Text.StringBuilder();
|
||||
var latitudAnterior = 0;
|
||||
var longitudAnterior = 0;
|
||||
foreach (var punto in puntos)
|
||||
{
|
||||
Codificar((int)Math.Round(punto.lat * 1_000_000) - latitudAnterior, texto);
|
||||
Codificar((int)Math.Round(punto.lon * 1_000_000) - longitudAnterior, texto);
|
||||
latitudAnterior = (int)Math.Round(punto.lat * 1_000_000);
|
||||
longitudAnterior = (int)Math.Round(punto.lon * 1_000_000);
|
||||
}
|
||||
return texto.ToString();
|
||||
|
||||
static void Codificar(int diferencia, System.Text.StringBuilder texto)
|
||||
{
|
||||
var valor = diferencia < 0 ? ~(diferencia << 1) : diferencia << 1;
|
||||
while (valor >= 0x20)
|
||||
{
|
||||
texto.Append((char)((0x20 | (valor & 0x1f)) + 63));
|
||||
valor >>= 5;
|
||||
}
|
||||
texto.Append((char)(valor + 63));
|
||||
}
|
||||
}
|
||||
|
||||
await Walk();
|
||||
var far = new List<List<double[]>> { Ring(-2.3, 43.0, .01) };
|
||||
@@ -79,8 +104,108 @@ var puntos = new List<double[]> { new[] { 43.314, -1.984 }, new[] { 43.315, -1.9
|
||||
await (Task<(double[,]?, double, double)>)walk.Invoke(planner,
|
||||
new object?[] { 43.31, -1.99, 43.32, -1.98, near, puntos })!;
|
||||
Check(fake.Zones == 2 && fake.Points == 2, "Se envian juntos todos los poligonos y puntos activos");
|
||||
var retryHandler = new RetryValhallaHandler();
|
||||
var retryConfig = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["Caminata:Valhalla:BaseUrl"] = "http://v2.test"
|
||||
}).Build();
|
||||
var retryClient = new ClienteValhalla(new HttpClient(retryHandler), retryConfig);
|
||||
await retryClient.ObtenerRutaAsync(
|
||||
43.316344, -1.983193, 43.315282, -1.985457,
|
||||
excludePolygons: new() { Ring(-1.9848, 43.3158, .0001) });
|
||||
Check(retryHandler.Bodies.Count == 8,
|
||||
"V2 amplia progresivamente la busqueda y prueba la alternativa puntual cuando recibe 442");
|
||||
using (var primerIntento = JsonDocument.Parse(retryHandler.Bodies[0]))
|
||||
using (var segundoIntento = JsonDocument.Parse(retryHandler.Bodies[1]))
|
||||
using (var tercerIntento = JsonDocument.Parse(retryHandler.Bodies[2]))
|
||||
using (var cuartoIntento = JsonDocument.Parse(retryHandler.Bodies[3]))
|
||||
{
|
||||
var primeraUbicacionInicial = primerIntento.RootElement.GetProperty("locations")[0];
|
||||
var primeraUbicacionReintento = segundoIntento.RootElement.GetProperty("locations")[0];
|
||||
var primeraUbicacionSegundoReintento = tercerIntento.RootElement.GetProperty("locations")[0];
|
||||
var primeraUbicacionTercerReintento = cuartoIntento.RootElement.GetProperty("locations")[0];
|
||||
Check(!primeraUbicacionInicial.TryGetProperty("radius", out _) &&
|
||||
primeraUbicacionReintento.GetProperty("radius").GetInt32() == 50 &&
|
||||
primeraUbicacionSegundoReintento.GetProperty("radius").GetInt32() == 100 &&
|
||||
primeraUbicacionTercerReintento.GetProperty("radius").GetInt32() == 200,
|
||||
"Los reintentos buscan una arista alternativa hasta un radio controlado de 200 metros");
|
||||
}
|
||||
var polygonFallbackHandler = new PolygonNoPathThenPointSuccessHandler(
|
||||
Polyline6((43.31, -1.99), (43.32, -1.98)),
|
||||
Polyline6((43.31, -1.99), (43.31, -1.98), (43.32, -1.98)));
|
||||
var polygonFallbackClient = new ClienteValhalla(new HttpClient(polygonFallbackHandler), retryConfig);
|
||||
var rutaConPoligonoConvertido = await polygonFallbackClient.ObtenerRutaAsync(
|
||||
43.31, -1.99, 43.32, -1.98,
|
||||
excludePolygons: new() { Ring(-1.9855, 43.3145, .001) });
|
||||
Check(rutaConPoligonoConvertido.Linea is not null && polygonFallbackHandler.Bodies.Count == 6,
|
||||
"Un poligono que devuelve 442 se sustituye por puntos y encuentra una alternativa");
|
||||
using (var peticionConPuntos = JsonDocument.Parse(polygonFallbackHandler.Bodies[^1]))
|
||||
{
|
||||
Check(peticionConPuntos.RootElement.GetProperty("exclude_polygons").ValueKind == JsonValueKind.Null &&
|
||||
peticionConPuntos.RootElement.GetProperty("exclude_locations").GetArrayLength() > 0,
|
||||
"El fallback conserva la zona como validacion y envia a v2 las aristas afectadas");
|
||||
}
|
||||
var poligonoValidacion = Ring(-1.9855, 43.3145, .001);
|
||||
var validationHandler = new PolygonValidationValhallaHandler(
|
||||
Polyline6((43.31, -1.99), (43.32, -1.98)),
|
||||
Polyline6((43.31, -1.99), (43.31, -1.98), (43.32, -1.98)));
|
||||
var validationClient = new ClienteValhalla(new HttpClient(validationHandler), retryConfig);
|
||||
var rutaValidada = await validationClient.ObtenerRutaAsync(
|
||||
43.31, -1.99, 43.32, -1.98, excludePolygons: new() { poligonoValidacion });
|
||||
Check(validationHandler.Bodies.Count == 2 && rutaValidada.Linea is not null,
|
||||
"V2 recalcula una ruta que atraviesa una zona activa");
|
||||
using (var peticionReforzada = JsonDocument.Parse(validationHandler.Bodies[1]))
|
||||
{
|
||||
Check(peticionReforzada.RootElement.GetProperty("exclude_locations").GetArrayLength() > 0,
|
||||
"La ruta conflictiva refuerza la exclusion sobre las aristas atravesadas");
|
||||
}
|
||||
var parametrosConExclusion = new ParametrosPlanificadorRuta
|
||||
{
|
||||
UsarValhallaParaCaminatas = true,
|
||||
PoligonosExclusionCaminata = new() { Ring(-1.985, 43.315, .001) }
|
||||
};
|
||||
var caminataNoResuelta = typeof(PlanificadorRutasServicio).GetMethod(
|
||||
"CaminataNoResueltaConExclusiones", BindingFlags.Static | BindingFlags.NonPublic)!;
|
||||
bool RechazarCaminata(ParametrosPlanificadorRuta parametros, double directa, double[,]? linea, double distancia) =>
|
||||
(bool)caminataNoResuelta.Invoke(null, new object?[] { parametros, directa, linea, distancia })!;
|
||||
Check(RechazarCaminata(parametrosConExclusion, 100, null, 0),
|
||||
"Una caminata V2 sin ruta se descarta cuando hay exclusiones");
|
||||
Check(!RechazarCaminata(new ParametrosPlanificadorRuta { UsarValhallaParaCaminatas = true }, 100, null, 0),
|
||||
"Sin exclusiones se conserva el fallback historico");
|
||||
Check(!RechazarCaminata(parametrosConExclusion, 100, new[,] { { 43.31, -1.99 }, { 43.32, -1.98 } }, 120),
|
||||
"Una caminata V2 valida se conserva con exclusiones");
|
||||
var puntoDentro = typeof(PlanificadorRutasServicio).GetMethod(
|
||||
"PuntoDentroDePoligonoExclusion", BindingFlags.Static | BindingFlags.NonPublic)!;
|
||||
Check((bool)puntoDentro.Invoke(null, new object?[] { 43.3155, -1.9845, parametrosConExclusion.PoligonosExclusionCaminata })!,
|
||||
"Las paradas interiores a una zona se detectan antes de calcular");
|
||||
var page = new PlanificadorRutas();
|
||||
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
|
||||
var formatearEtiqueta = typeof(PlanificadorRutas).GetMethod("FormatearEtiquetaAlternativaTarjeta", flags)!;
|
||||
Check((string)formatearEtiqueta.Invoke(page, new object[]
|
||||
{ new AlternativaRuta { Etiqueta = "Equilibrada" }, 0 })! == "Opción 1",
|
||||
"Las alternativas de bus se muestran numeradas sin etiquetas de criterio");
|
||||
Check((string)formatearEtiqueta.Invoke(page, new object[]
|
||||
{ new AlternativaRuta { EsSoloAPie = true, Etiqueta = "Solo a pie (v2)" }, 3 })! == "Solo a pie (v2)",
|
||||
"Las dos alternativas solo a pie conservan su identificacion");
|
||||
var maximoExclusiones = typeof(PlanificadorRutas).GetField(
|
||||
"MaximoExclusionesCaminata", BindingFlags.Static | BindingFlags.NonPublic)!;
|
||||
Check((int)maximoExclusiones.GetRawConstantValue()! == 25,
|
||||
"Las exclusiones quedan limitadas a 25 elementos");
|
||||
typeof(PlanificadorRutas).GetField("_configuracionFabrica", flags)!.SetValue(page, defaults.Clonar());
|
||||
typeof(PlanificadorRutas).GetField("_activarRangoLineas", flags)!.SetValue(page, true);
|
||||
typeof(PlanificadorRutas).GetField("_lineaMin", flags)!.SetValue(page, 40);
|
||||
typeof(PlanificadorRutas).GetField("_lineaMax", flags)!.SetValue(page, 40);
|
||||
typeof(PlanificadorRutas).GetField("_activarRangoItinerarios", flags)!.SetValue(page, false);
|
||||
typeof(PlanificadorRutas).GetField("_itinerarioMin", flags)!.SetValue(page, 7);
|
||||
typeof(PlanificadorRutas).GetField("_itinerarioMax", flags)!.SetValue(page, 7);
|
||||
typeof(PlanificadorRutas).GetMethod("AplicarValoresFabricaConservandoSeleccion", flags)!.Invoke(page, null);
|
||||
Check(!(bool)typeof(PlanificadorRutas).GetField("_activarRangoLineas", flags)!.GetValue(page)! &&
|
||||
(int)typeof(PlanificadorRutas).GetField("_lineaMin", flags)!.GetValue(page)! == defaults.LineaMin &&
|
||||
(int)typeof(PlanificadorRutas).GetField("_lineaMax", flags)!.GetValue(page)! == defaults.LineaMax &&
|
||||
(bool)typeof(PlanificadorRutas).GetField("_activarRangoItinerarios", flags)!.GetValue(page)! &&
|
||||
(int)typeof(PlanificadorRutas).GetField("_itinerarioMin", flags)!.GetValue(page)! == defaults.ItinerarioMin &&
|
||||
(int)typeof(PlanificadorRutas).GetField("_itinerarioMax", flags)!.GetValue(page)! == defaults.ItinerarioMax,
|
||||
"Restaurar aplica tambien los valores de lineas e itinerarios");
|
||||
var options = (List<AlternativaRuta>)typeof(PlanificadorRutas).GetField("_opcionesRuta", flags)!.GetValue(page)!;
|
||||
var selected = typeof(PlanificadorRutas).GetField("_indiceAlternativaSeleccionada", flags)!;
|
||||
var remember = typeof(PlanificadorRutas).GetMethod("ObtenerProveedorSoloAPieParaRecalculo", flags)!;
|
||||
@@ -120,3 +245,94 @@ sealed class FakeValhalla : IClienteValhalla
|
||||
(new[,] { { latitudDesde, longitudDesde }, { latitudHasta, longitudHasta } }, 100, 100));
|
||||
}
|
||||
}
|
||||
|
||||
sealed class RetryValhallaHandler : HttpMessageHandler
|
||||
{
|
||||
public List<string> Bodies { get; } = new();
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Bodies.Add(await request.Content!.ReadAsStringAsync(cancellationToken));
|
||||
return new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
|
||||
{
|
||||
Content = new StringContent(
|
||||
"{\"error_code\":442,\"error\":\"No path could be found for input\"}",
|
||||
System.Text.Encoding.UTF8,
|
||||
"application/json")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
sealed class PolygonValidationValhallaHandler(string primeraForma, string segundaForma) : HttpMessageHandler
|
||||
{
|
||||
public List<string> Bodies { get; } = new();
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Bodies.Add(await request.Content!.ReadAsStringAsync(cancellationToken));
|
||||
var forma = Bodies.Count == 1 ? primeraForma : segundaForma;
|
||||
var contenido = JsonSerializer.Serialize(new
|
||||
{
|
||||
trip = new
|
||||
{
|
||||
units = "kilometers",
|
||||
summary = new { length = 1.0, time = 600.0 },
|
||||
legs = new[] { new { shape = forma } }
|
||||
}
|
||||
});
|
||||
return new HttpResponseMessage(System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(contenido, System.Text.Encoding.UTF8, "application/json")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
sealed class PolygonNoPathThenPointSuccessHandler(string formaConflictiva, string formaAlternativa)
|
||||
: HttpMessageHandler
|
||||
{
|
||||
public List<string> Bodies { get; } = new();
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var cuerpo = await request.Content!.ReadAsStringAsync(cancellationToken);
|
||||
Bodies.Add(cuerpo);
|
||||
using var documento = JsonDocument.Parse(cuerpo);
|
||||
var raiz = documento.RootElement;
|
||||
var tienePoligonos = raiz.TryGetProperty("exclude_polygons", out var poligonos) &&
|
||||
poligonos.ValueKind == JsonValueKind.Array &&
|
||||
poligonos.GetArrayLength() > 0;
|
||||
if (tienePoligonos)
|
||||
{
|
||||
return new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
|
||||
{
|
||||
Content = new StringContent(
|
||||
"{\"error_code\":442,\"error\":\"No path could be found for input\"}",
|
||||
System.Text.Encoding.UTF8,
|
||||
"application/json")
|
||||
};
|
||||
}
|
||||
|
||||
var tienePuntos = raiz.TryGetProperty("exclude_locations", out var puntos) &&
|
||||
puntos.ValueKind == JsonValueKind.Array &&
|
||||
puntos.GetArrayLength() > 0;
|
||||
var contenido = JsonSerializer.Serialize(new
|
||||
{
|
||||
trip = new
|
||||
{
|
||||
units = "kilometers",
|
||||
summary = new { length = 1.0, time = 600.0 },
|
||||
legs = new[] { new { shape = tienePuntos ? formaAlternativa : formaConflictiva } }
|
||||
}
|
||||
});
|
||||
return new HttpResponseMessage(System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(contenido, System.Text.Encoding.UTF8, "application/json")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user