Add mapped Pro fiducial point layer

This commit is contained in:
livio committed 2026-10-04 15:18:42 +02:00
1 parent 7b642afe2d
commit 85e1c93d8a
4 files changed
+360 -19

No files matched your search

+114
View File
@@ -1,5 +1,6 @@
using System.Net;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace LMEMappeCatastaliApp.Services;
@@ -7,6 +8,7 @@ namespace LMEMappeCatastaliApp.Services;
public sealed partial class FiducialPointService
{
private const string ServiceBaseUrl = "https://www1.agenziaentrate.gov.it/servizi/Monografie/";
private const string MappedPointsUrl = "https://cartografia.globogis.it/arcgis/rest/services/fiduciali/Punti_fiduciali/MapServer/2/query";
private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(30) };
public FiducialPointService()
@@ -77,6 +79,105 @@ public sealed partial class FiducialPointService
.ToArray();
}
public async Task<IReadOnlyList<MappedFiducialPoint>> GetMappedFiducialsAsync(
string municipalityCode,
string sheet,
CancellationToken cancellationToken = default)
{
var municipality = NormalizeCode(municipalityCode);
if (!int.TryParse(new string(sheet.Where(char.IsDigit).ToArray()), out var sheetNumber))
{
throw new ArgumentException("Numero di foglio non valido.", nameof(sheet));
}
var query = new Dictionary<string, string>
{
["f"] = "json",
["where"] = $"COMUNENAZI='{municipality}' AND FOGLIO={sheetNumber}",
["outFields"] = "ETICHETTA,PARTICELLA,NORD,EST,ATTENDIBIL,QUOTA,DATAAGGIOR,IDORIGINE,URL_AGENZI,FOGLIO,ALLEGATO,FIDUCIALE",
["returnGeometry"] = "true",
["outSR"] = "3857",
["resultRecordCount"] = "500"
};
var url = $"{MappedPointsUrl}?{string.Join('&', query.Select(item => $"{item.Key}={Uri.EscapeDataString(item.Value)}"))}";
using var response = await _httpClient.GetAsync(url, cancellationToken);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
using var document = await JsonDocument.ParseAsync(stream, cancellationToken: cancellationToken);
if (document.RootElement.TryGetProperty("error", out var error))
{
throw new InvalidOperationException(error.TryGetProperty("message", out var message)
? message.GetString()
: "Servizio cartografico PF non disponibile.");
}
if (!document.RootElement.TryGetProperty("features", out var features))
{
return [];
}
return features.EnumerateArray()
.Select(feature => ParseMappedPoint(feature, municipality))
.Where(point => point is not null)
.Cast<MappedFiducialPoint>()
.DistinctBy(point => point.Identifier, StringComparer.OrdinalIgnoreCase)
.OrderBy(point => point.Identifier, StringComparer.OrdinalIgnoreCase)
.ToArray();
}
private static MappedFiducialPoint? ParseMappedPoint(JsonElement feature, string municipalityCode)
{
if (!feature.TryGetProperty("geometry", out var geometry)
|| !TryGetDouble(geometry, "x", out var x)
|| !TryGetDouble(geometry, "y", out var y))
{
return null;
}
var attributes = feature.GetProperty("attributes");
var label = GetString(attributes, "ETICHETTA");
var identifier = FormatIdentifier(label);
if (identifier == label)
{
var sheet = GetString(attributes, "FOGLIO").PadLeft(4, '0');
var number = GetString(attributes, "FIDUCIALE").PadLeft(2, '0');
identifier = $"PF{number}/{sheet}/{municipalityCode}";
}
const double earthRadius = 6378137d;
var longitude = x / earthRadius * 180d / Math.PI;
var latitude = (2d * Math.Atan(Math.Exp(y / earthRadius)) - Math.PI / 2d) * 180d / Math.PI;
return new MappedFiducialPoint(
identifier,
latitude,
longitude,
GetNullableDouble(attributes, "NORD"),
GetNullableDouble(attributes, "EST"),
GetString(attributes, "ATTENDIBIL"),
GetNullableDouble(attributes, "QUOTA"),
GetString(attributes, "PARTICELLA"),
GetString(attributes, "DATAAGGIOR"),
GetString(attributes, "IDORIGINE"));
}
private static bool TryGetDouble(JsonElement element, string name, out double value)
{
value = 0;
return element.TryGetProperty(name, out var property)
&& (property.ValueKind == JsonValueKind.Number
? property.TryGetDouble(out value)
: double.TryParse(property.ToString(), System.Globalization.NumberStyles.Float,
System.Globalization.CultureInfo.InvariantCulture, out value));
}
private static double? GetNullableDouble(JsonElement element, string name) =>
TryGetDouble(element, name, out var value) ? value : null;
private static string GetString(JsonElement element, string name) =>
element.TryGetProperty(name, out var property) && property.ValueKind != JsonValueKind.Null
? property.ToString().Trim()
: string.Empty;
private async Task<string> GetHtmlAsync(string relativeUrl, CancellationToken cancellationToken)
{
using var response = await _httpClient.GetAsync(ServiceBaseUrl + relativeUrl, cancellationToken);
@@ -146,3 +247,16 @@ public sealed partial class FiducialPointService
public sealed record FiducialAreaOption(string Code, string Name);
public sealed record FiducialPointEntry(string Identifier, string MonographUrl);
public sealed record MappedFiducialPoint(
string Identifier,
double Latitude,
double Longitude,
double? CadastralNorth,
double? CadastralEast,
string Reliability,
double? Elevation,
string Parcel,
string UpdatedAt,
string OriginId,
string MonographUrl = "");