From 56211e4b25fb8d34a730bf4c33215cca8c6602fa Mon Sep 17 00:00:00 2001 From: livio Date: Fri, 11 Sep 2026 18:46:56 +0200 Subject: [PATCH] Fix parcel coordinates and map controls --- Components/Pages/Home.razor | 11 +- LMEMappeCatastaliApp.csproj | 4 +- README.md | 2 + Services/CadastralCatalogService.cs | 17 +- wwwroot/css/app.css | 25 ++- wwwroot/js/lme-map.js | 19 +++ .../leaflet-draw/images/spritesheet-2x.png | Bin 0 -> 3581 bytes .../lib/leaflet-draw/images/spritesheet.png | Bin 0 -> 1906 bytes .../lib/leaflet-draw/images/spritesheet.svg | 156 ++++++++++++++++++ 9 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 wwwroot/lib/leaflet-draw/images/spritesheet-2x.png create mode 100644 wwwroot/lib/leaflet-draw/images/spritesheet.png create mode 100644 wwwroot/lib/leaflet-draw/images/spritesheet.svg diff --git a/Components/Pages/Home.razor b/Components/Pages/Home.razor index 2a257f9..e1014ef 100644 --- a/Components/Pages/Home.razor +++ b/Components/Pages/Home.razor @@ -23,7 +23,7 @@ -
+
GPS non attivo Nessuna particella selezionata @@ -133,6 +133,7 @@
+ } else if (ActiveTab == "settings") @@ -471,7 +472,13 @@ private Task FitImportedLayers() => JS.InvokeVoidAsync("lmeMap.fitImported").AsTask(); private Task ClearImportedLayers() => JS.InvokeVoidAsync("lmeMap.clearImported").AsTask(); private Task AddProjectMarker() => JS.InvokeVoidAsync("lmeMap.addProjectMarker", ProjectName).AsTask(); - private Task EnableDrawTools() => JS.InvokeVoidAsync("lmeMap.enableDrawTools").AsTask(); + private async Task EnableDrawTools() + { + await JS.InvokeVoidAsync("lmeMap.enableDrawTools"); + await SelectTab("map"); + } + + private Task ClearDrawings() => JS.InvokeVoidAsync("lmeMap.clearDrawings").AsTask(); private Task SaveWorkspace() => JS.InvokeVoidAsync("lmeMap.saveWorkspace").AsTask(); private Task LoadWorkspace() => JS.InvokeVoidAsync("lmeMap.loadWorkspace").AsTask(); private Task CenterOnGps() => JS.InvokeVoidAsync("lmeMap.centerOnGps").AsTask(); diff --git a/LMEMappeCatastaliApp.csproj b/LMEMappeCatastaliApp.csproj index 5b3b6cb..afe43a6 100644 --- a/LMEMappeCatastaliApp.csproj +++ b/LMEMappeCatastaliApp.csproj @@ -28,8 +28,8 @@ com.companyname.lmemappecatastaliapp - 0.2.0 - 4 + 0.2.1 + 5 None diff --git a/README.md b/README.md index 18e590a..9fa7f28 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,14 @@ App .NET MAUI Blazor Hybrid per Android, iOS, Mac Catalyst e Windows, pensata pe - Import di file KML, KMZ, GeoJSON e JSON. - Inquadramento e pulizia dei layer importati. - Disegno di marker, linee, poligoni e rettangoli. +- Toolbar di disegno completa di icone, modifica, eliminazione singola e pulizia di tutti i disegni/POI. - POI/progetti salvabili in locale con `localStorage`. - GPS nativo MAUI ad alta precisione con permessi Android/iOS. - Marker posizione, cerchio accuratezza in metri, tracciamento percorso. - Controllo se la posizione GPS cade dentro un poligono importato o disegnato. - Interrogazione WFS ufficiale Agenzia delle Entrate attorno alla posizione GPS per evidenziare la particella catastale corrente quando il servizio restituisce la geometria. - Mappa a tutto schermo con tab Catasto, Progetti e Impostazioni, adattabile agli schermi pieghevoli. +- Ingrandimento oltre lo zoom satellitare nativo senza tessere "Map data not yet available". - Tendine concatenate Regione, Comune, Foglio e Particella. - Catalogo dei Comuni incluso nell'APK e cataloghi regionali OnData scaricati in cache solo quando servono. - Ricerca catastale eseguita dal codice .NET nativo, senza DuckDB WebAssembly nella WebView Android. diff --git a/Services/CadastralCatalogService.cs b/Services/CadastralCatalogService.cs index e56d0f1..d1481af 100644 --- a/Services/CadastralCatalogService.cs +++ b/Services/CadastralCatalogService.cs @@ -128,25 +128,28 @@ public sealed class CadastralCatalogService var parcelValues = new string[count]; var inspireIds = new string[count]; - var longitudes = new long[count]; - var latitudes = new long[count]; + var longitudes = new long?[count]; + var latitudes = new long?[count]; await group.ReadAsync(parcelField, parcelValues, cancellationToken: cancellationToken); await group.ReadAsync(inspireIdField, inspireIds, cancellationToken: cancellationToken); - await group.ReadAsync(longitudeField, longitudes, cancellationToken: cancellationToken); - await group.ReadAsync(latitudeField, latitudes, cancellationToken: cancellationToken); + await group.ReadAsync(longitudeField, longitudes.AsMemory(), cancellationToken: cancellationToken); + await group.ReadAsync(latitudeField, latitudes.AsMemory(), cancellationToken: cancellationToken); foreach (var index in matchingIndexes) { var number = parcelValues[index]; - if (string.IsNullOrWhiteSpace(number) || parcels.ContainsKey(number)) + if (string.IsNullOrWhiteSpace(number) + || parcels.ContainsKey(number) + || !latitudes[index].HasValue + || !longitudes[index].HasValue) { continue; } parcels[number] = new ParcelOption( number, - latitudes[index] / 1_000_000d, - longitudes[index] / 1_000_000d, + latitudes[index]!.Value / 1_000_000d, + longitudes[index]!.Value / 1_000_000d, inspireIds[index] ?? string.Empty); } } diff --git a/wwwroot/css/app.css b/wwwroot/css/app.css index b56f283..79b3b3e 100644 --- a/wwwroot/css/app.css +++ b/wwwroot/css/app.css @@ -152,8 +152,10 @@ input[type="checkbox"] { .gps-overlay { position: absolute; - right: 12px; - bottom: 78px; + top: 72px; + right: auto; + bottom: auto; + left: 12px; z-index: 850; display: grid; grid-template-columns: minmax(160px, auto) auto auto; @@ -164,6 +166,11 @@ input[type="checkbox"] { border-radius: 8px; background: rgba(255, 255, 255, 0.95); box-shadow: 0 3px 14px rgba(0, 0, 0, 0.2); + transition: top 140ms ease; +} + +.gps-overlay.search-open { + top: 140px; } .gps-state { @@ -290,6 +297,13 @@ label { color: var(--ink); } +.danger-command { + width: 100%; + border: 1px solid #cfaca8; + background: #fff; + color: #9b2f26; +} + .file-picker { position: relative; min-height: 52px; @@ -459,13 +473,18 @@ footer { } .gps-overlay { + top: 68px; right: 8px; - bottom: 116px; + bottom: auto; left: 8px; grid-template-columns: minmax(0, 1fr) auto auto; max-width: none; } + .gps-overlay.search-open { + top: 136px; + } + .gps-main, .gps-center { padding: 0 8px; diff --git a/wwwroot/js/lme-map.js b/wwwroot/js/lme-map.js index 782a485..1d8adfa 100644 --- a/wwwroot/js/lme-map.js +++ b/wwwroot/js/lme-map.js @@ -31,6 +31,7 @@ window.lmeMap = { clearImported, addProjectMarker, enableDrawTools, + clearDrawings, saveWorkspace, loadWorkspace, setBaseLayer, @@ -58,11 +59,13 @@ function init() { L.control.zoom({ position: "bottomright" }).addTo(lmeState.map); lmeState.baseLayers.osm = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + maxNativeZoom: 19, maxZoom: 22, attribution: "© OpenStreetMap contributors" }); lmeState.baseLayers.satellite = L.tileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", { + maxNativeZoom: 19, maxZoom: 22, attribution: "Tiles © Esri" }); @@ -288,6 +291,22 @@ function enableDrawTools() { setInfo("Disegno attivo: crea POI, linee e aree sulla mappa."); } +function clearDrawings() { + const count = lmeState.drawings.getLayers().length; + if (!count) { + setInfo("Non ci sono disegni o POI da eliminare."); + return; + } + + if (!window.confirm(`Eliminare ${count} disegni e POI dalla mappa?`)) { + return; + } + + lmeState.drawings.clearLayers(); + updateGpsInsideState(); + setInfo("Disegni e POI eliminati dalla mappa."); +} + function saveWorkspace() { const data = { drawings: lmeState.drawings.toGeoJSON(), diff --git a/wwwroot/lib/leaflet-draw/images/spritesheet-2x.png b/wwwroot/lib/leaflet-draw/images/spritesheet-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c45231aff86b1344333414cdfa7a2a74d38d5304 GIT binary patch literal 3581 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 i{eP_FzxHA`84t@4c6%tZ%} + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +