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( 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 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(); } } }