agrobot_base/AgroBase/OperationControl/Mapas/Services/MapaValidationService.cs

273 lines
6.5 KiB
C#

using NetTopologySuite.Geometries;
using OperationControl.Mapas.Models;
namespace OperationControl.Mapas.Services
{
public class MapaValidationService
{
public MapaResultadoValidacao Validar(
MapaDocumento? documento)
{
var resultado =
new MapaResultadoValidacao();
if (documento == null)
{
resultado.AdicionarErro(
"O documento de mapa é nulo."
);
return resultado;
}
if (documento.Ruas == null ||
documento.Ruas.Count == 0)
{
resultado.AdicionarErro(
"O mapa não possui ruas."
);
return resultado;
}
var idsUsados =
new HashSet<string>(
StringComparer.OrdinalIgnoreCase
);
for (
int i = 0;
i < documento.Ruas.Count;
i++)
{
MapaRua? rua =
documento.Ruas[i];
int numeroRua =
i + 1;
if (rua == null)
{
resultado.AdicionarErro(
$"A rua na posição {numeroRua} é nula."
);
continue;
}
ValidarId(
rua,
numeroRua,
idsUsados,
resultado
);
ValidarGeometria(
rua,
numeroRua,
resultado
);
}
return resultado;
}
private static void ValidarId(
MapaRua rua,
int indice,
HashSet<string> idsUsados,
MapaResultadoValidacao resultado)
{
if (string.IsNullOrWhiteSpace(rua.Id))
{
resultado.AdicionarErro(
$"A rua na posição {indice} não possui ID."
);
return;
}
string id =
rua.Id.Trim();
if (!idsUsados.Add(id))
{
resultado.AdicionarErro(
$"O ID de rua '{id}' está duplicado."
);
}
}
private static void ValidarGeometria(
MapaRua rua,
int indice,
MapaResultadoValidacao resultado)
{
LineString? geometria =
rua.Geometria;
if (geometria == null)
{
resultado.AdicionarErro(
$"A rua '{ObterNomeRua(rua, indice)}' " +
"não possui geometria."
);
return;
}
if (geometria.IsEmpty)
{
resultado.AdicionarErro(
$"A rua '{ObterNomeRua(rua, indice)}' " +
"possui geometria vazia."
);
return;
}
if (geometria.NumPoints < 2)
{
resultado.AdicionarErro(
$"A rua '{ObterNomeRua(rua, indice)}' " +
"possui menos de dois pontos."
);
return;
}
Coordinate[] coordenadas =
geometria.Coordinates;
bool possuiSegmentoReal = false;
for (
int i = 0;
i < coordenadas.Length;
i++)
{
Coordinate coordenada =
coordenadas[i];
double longitude =
coordenada.X;
double latitude =
coordenada.Y;
bool valida =
double.IsFinite(longitude) &&
double.IsFinite(latitude) &&
longitude >= -180.0 &&
longitude <= 180.0 &&
latitude >= -90.0 &&
latitude <= 90.0;
if (!valida)
{
resultado.AdicionarErro(
$"A rua '{ObterNomeRua(rua, indice)}', " +
$"ponto {i + 1}, possui coordenada inválida: " +
$"longitude={longitude}, latitude={latitude}."
);
/*
* Não precisamos continuar analisando
* a topologia dessa coordenada.
*/
continue;
}
if (i > 0)
{
Coordinate anterior =
coordenadas[i - 1];
if (
Math.Abs(
anterior.X -
coordenada.X
) > 1e-12 ||
Math.Abs(
anterior.Y -
coordenada.Y
) > 1e-12
)
{
possuiSegmentoReal =
true;
}
else
{
resultado.AdicionarAviso(
$"A rua '{ObterNomeRua(rua, indice)}' " +
$"possui pontos consecutivos repetidos " +
$"nas posições {i} e {i + 1}."
);
}
}
}
if (!possuiSegmentoReal)
{
resultado.AdicionarErro(
$"A rua '{ObterNomeRua(rua, indice)}' " +
"não possui deslocamento geométrico."
);
}
if (
!double.IsFinite(
rua.ComprimentoMetros
) ||
rua.ComprimentoMetros < 0
)
{
resultado.AdicionarErro(
$"A rua '{ObterNomeRua(rua, indice)}' " +
"possui comprimento inválido."
);
}
}
private static string ObterNomeRua(
MapaRua rua,
int indice)
{
if (!string.IsNullOrWhiteSpace(
rua.Id))
{
return rua.Id;
}
return indice.ToString();
}
}
}