- Separado el control de poligonos excluyentes
- Añadido interpreacion de tipologia de suelo en segmentos andando - Persistencia modo andando - Transbordo penalizado a 6 - Añadidos varias zonas de prohibicion de poligonos
This commit is contained in:
@@ -5,6 +5,7 @@ using System.Net.Http.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using RutasDBUS.Modelos.Planificacion;
|
||||
|
||||
namespace RutasDBUS.Servicios.Caminata;
|
||||
|
||||
@@ -112,6 +113,199 @@ public class ClienteValhalla : IClienteValhalla
|
||||
duracionSegundos);
|
||||
}
|
||||
|
||||
public async Task<InformacionSueloTramo?> ObtenerInformacionSueloAsync(
|
||||
double[,] linea,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var forma = ConstruirFormaTraza(linea);
|
||||
if (forma.Count < 2)
|
||||
return new InformacionSueloTramo
|
||||
{
|
||||
Disponible = false,
|
||||
Mensaje = "No hay geometría suficiente para consultar la superficie."
|
||||
};
|
||||
|
||||
var cuerpo = new SolicitudAtributosSuperficieValhalla
|
||||
{
|
||||
Forma = forma,
|
||||
PerfilCoste = "pedestrian",
|
||||
AjusteForma = "walk_or_snap",
|
||||
Filtros = new FiltrosAtributosValhalla
|
||||
{
|
||||
Atributos = new List<string>
|
||||
{
|
||||
"edge.length",
|
||||
"edge.surface",
|
||||
"edge.unpaved",
|
||||
"edge.use",
|
||||
"edge.way_id",
|
||||
"edge.begin_shape_index",
|
||||
"edge.end_shape_index"
|
||||
}
|
||||
},
|
||||
OpcionesIndicaciones = new OpcionesIndicacionesValhalla
|
||||
{
|
||||
Idioma = "es-ES",
|
||||
Unidades = "kilometers"
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
timeout.CancelAfter(TimeSpan.FromSeconds(8));
|
||||
|
||||
using var respuesta = await _httpClient.PostAsJsonAsync(
|
||||
$"{_baseUrl}/trace_attributes",
|
||||
cuerpo,
|
||||
timeout.Token);
|
||||
|
||||
if (!respuesta.IsSuccessStatusCode)
|
||||
return CrearInformacionSueloNoDisponible("El servicio de superficies no ha respondido correctamente.");
|
||||
|
||||
var data = await respuesta.Content.ReadFromJsonAsync<RespuestaAtributosSuperficieValhalla>(timeout.Token);
|
||||
return ConvertirInformacionSuelo(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return CrearInformacionSueloNoDisponible("No se ha podido consultar la superficie del tramo.");
|
||||
}
|
||||
}
|
||||
|
||||
private static List<PuntoFormaValhalla> ConstruirFormaTraza(double[,] linea)
|
||||
{
|
||||
var forma = new List<PuntoFormaValhalla>();
|
||||
if (linea is null || linea.Rank != 2 || linea.GetLength(1) < 2)
|
||||
return forma;
|
||||
|
||||
for (var i = 0; i < linea.GetLength(0); i++)
|
||||
{
|
||||
var latitud = linea[i, 0];
|
||||
var longitud = linea[i, 1];
|
||||
if (!double.IsFinite(latitud) || !double.IsFinite(longitud))
|
||||
continue;
|
||||
|
||||
if (forma.Count > 0
|
||||
&& Math.Abs(forma[^1].Latitud - latitud) < 0.00000001
|
||||
&& Math.Abs(forma[^1].Longitud - longitud) < 0.00000001)
|
||||
continue;
|
||||
|
||||
forma.Add(new PuntoFormaValhalla { Latitud = latitud, Longitud = longitud });
|
||||
}
|
||||
|
||||
return forma;
|
||||
}
|
||||
|
||||
private static InformacionSueloTramo ConvertirInformacionSuelo(RespuestaAtributosSuperficieValhalla? data)
|
||||
{
|
||||
if (data?.Aristas is null || data.Aristas.Count == 0)
|
||||
return CrearInformacionSueloNoDisponible("No hay datos de superficie para este tramo.");
|
||||
|
||||
var segmentos = new List<SegmentoSueloTramo>();
|
||||
foreach (var arista in data.Aristas)
|
||||
{
|
||||
var distanciaMetros = ConvertirLongitudMetros(arista.Longitud, data.Unidades);
|
||||
if (distanciaMetros <= 0)
|
||||
continue;
|
||||
|
||||
var superficie = EtiquetaSuperficie(arista.Superficie, arista.SinPavimentar);
|
||||
var uso = EtiquetaUso(arista.Uso);
|
||||
|
||||
if (segmentos.Count > 0 && EsMismaSuperficie(segmentos[^1], superficie, uso, arista.SinPavimentar))
|
||||
{
|
||||
var anterior = segmentos[^1];
|
||||
segmentos[^1] = new SegmentoSueloTramo
|
||||
{
|
||||
DistanciaMetros = anterior.DistanciaMetros + distanciaMetros,
|
||||
Superficie = anterior.Superficie,
|
||||
Uso = anterior.Uso,
|
||||
SinPavimentar = anterior.SinPavimentar,
|
||||
IdCamino = anterior.IdCamino == arista.IdCamino ? anterior.IdCamino : null,
|
||||
IndiceInicioForma = anterior.IndiceInicioForma,
|
||||
IndiceFinForma = arista.IndiceFinForma ?? anterior.IndiceFinForma
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
segmentos.Add(new SegmentoSueloTramo
|
||||
{
|
||||
DistanciaMetros = distanciaMetros,
|
||||
Superficie = superficie,
|
||||
Uso = uso,
|
||||
SinPavimentar = arista.SinPavimentar,
|
||||
IdCamino = arista.IdCamino,
|
||||
IndiceInicioForma = arista.IndiceInicioForma,
|
||||
IndiceFinForma = arista.IndiceFinForma
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (segmentos.Count == 0)
|
||||
return CrearInformacionSueloNoDisponible("No hay datos de superficie para este tramo.");
|
||||
|
||||
return new InformacionSueloTramo
|
||||
{
|
||||
Disponible = true,
|
||||
Segmentos = segmentos
|
||||
};
|
||||
}
|
||||
|
||||
private static bool EsMismaSuperficie(
|
||||
SegmentoSueloTramo anterior,
|
||||
string superficie,
|
||||
string? uso,
|
||||
bool? sinPavimentar)
|
||||
=> string.Equals(anterior.Superficie, superficie, StringComparison.Ordinal)
|
||||
&& string.Equals(anterior.Uso, uso, StringComparison.Ordinal)
|
||||
&& anterior.SinPavimentar == sinPavimentar;
|
||||
|
||||
private static double ConvertirLongitudMetros(double? longitud, string? unidades)
|
||||
{
|
||||
if (longitud is not double valor || !double.IsFinite(valor) || valor <= 0)
|
||||
return 0;
|
||||
|
||||
return string.Equals(unidades, "miles", StringComparison.OrdinalIgnoreCase)
|
||||
? valor * 1609.344
|
||||
: valor * 1000.0;
|
||||
}
|
||||
|
||||
private static string EtiquetaSuperficie(string? superficie, bool? sinPavimentar)
|
||||
=> (superficie ?? "").Trim().ToLowerInvariant() switch
|
||||
{
|
||||
"paved_smooth" => "Pavimento liso",
|
||||
"paved" => "Pavimento",
|
||||
"paved_rough" => "Pavimento rugoso",
|
||||
"compacted" => "Tierra compactada",
|
||||
"dirt" => "Tierra",
|
||||
"gravel" => "Grava",
|
||||
"path" => "Senda",
|
||||
"impassable" => "Intransitable",
|
||||
_ when sinPavimentar == true => "No pavimentado",
|
||||
_ => "Sin datos"
|
||||
};
|
||||
|
||||
private static string? EtiquetaUso(string? uso)
|
||||
=> (uso ?? "").Trim().ToLowerInvariant() switch
|
||||
{
|
||||
"sidewalk" => "Acera",
|
||||
"footway" => "Camino peatonal",
|
||||
"steps" => "Escaleras",
|
||||
"path" => "Senda",
|
||||
"track" => "Pista",
|
||||
"road" => "Calzada",
|
||||
"service_other" => "Vía de servicio",
|
||||
"other" => "Otro",
|
||||
"" => null,
|
||||
var valor => valor
|
||||
};
|
||||
|
||||
private static InformacionSueloTramo CrearInformacionSueloNoDisponible(string mensaje)
|
||||
=> new()
|
||||
{
|
||||
Disponible = false,
|
||||
Mensaje = mensaje
|
||||
};
|
||||
|
||||
// =======================
|
||||
// Modelos request/response
|
||||
// =======================
|
||||
@@ -134,6 +328,75 @@ public class ClienteValhalla : IClienteValhalla
|
||||
public OpcionesIndicacionesValhalla OpcionesIndicaciones { get; set; } = new();
|
||||
}
|
||||
|
||||
private sealed class SolicitudAtributosSuperficieValhalla
|
||||
{
|
||||
[JsonPropertyName("shape")]
|
||||
public List<PuntoFormaValhalla> Forma { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("costing")]
|
||||
public string PerfilCoste { get; set; } = "pedestrian";
|
||||
|
||||
[JsonPropertyName("shape_match")]
|
||||
public string AjusteForma { get; set; } = "walk_or_snap";
|
||||
|
||||
[JsonPropertyName("filters")]
|
||||
public FiltrosAtributosValhalla Filtros { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("directions_options")]
|
||||
public OpcionesIndicacionesValhalla OpcionesIndicaciones { get; set; } = new();
|
||||
}
|
||||
|
||||
private sealed class PuntoFormaValhalla
|
||||
{
|
||||
[JsonPropertyName("lat")]
|
||||
public double Latitud { get; set; }
|
||||
|
||||
[JsonPropertyName("lon")]
|
||||
public double Longitud { get; set; }
|
||||
}
|
||||
|
||||
private sealed class FiltrosAtributosValhalla
|
||||
{
|
||||
[JsonPropertyName("attributes")]
|
||||
public List<string> Atributos { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("action")]
|
||||
public string Accion { get; set; } = "include";
|
||||
}
|
||||
|
||||
private sealed class RespuestaAtributosSuperficieValhalla
|
||||
{
|
||||
[JsonPropertyName("edges")]
|
||||
public List<AristaAtributosValhalla> Aristas { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("units")]
|
||||
public string? Unidades { get; set; }
|
||||
}
|
||||
|
||||
private sealed class AristaAtributosValhalla
|
||||
{
|
||||
[JsonPropertyName("length")]
|
||||
public double? Longitud { get; set; }
|
||||
|
||||
[JsonPropertyName("surface")]
|
||||
public string? Superficie { get; set; }
|
||||
|
||||
[JsonPropertyName("unpaved")]
|
||||
public bool? SinPavimentar { get; set; }
|
||||
|
||||
[JsonPropertyName("use")]
|
||||
public string? Uso { get; set; }
|
||||
|
||||
[JsonPropertyName("way_id")]
|
||||
public long? IdCamino { get; set; }
|
||||
|
||||
[JsonPropertyName("begin_shape_index")]
|
||||
public int? IndiceInicioForma { get; set; }
|
||||
|
||||
[JsonPropertyName("end_shape_index")]
|
||||
public int? IndiceFinForma { get; set; }
|
||||
}
|
||||
|
||||
private sealed class LocalizacionValhalla
|
||||
{
|
||||
[JsonPropertyName("lat")]
|
||||
|
||||
Reference in New Issue
Block a user