SXXXXXXX_GeoElevation/doc/map_manager.md
2025-12-02 09:50:29 +01:00

149 lines
8.2 KiB
Markdown

Ecco il piano operativo completo per il refactoring e la creazione del modulo `python-map-manager`. Questo documento è strutturato per essere inserito direttamente nella documentazione tecnica del progetto.
---
# Piano Operativo: Refactoring e Creazione Modulo `python-map-manager`
## 1. Obiettivo del Refactoring
L'obiettivo primario è disaccoppiare la logica di gestione, recupero e visualizzazione delle mappe geografiche (attualmente integrata nell'applicazione `geoelevation`) per creare un componente software autonomo, riutilizzabile e manutenibile separatamente.
Questo nuovo componente sarà gestito come **Git Submodule** e denominato **`python-map-manager`**.
### Obiettivi Specifici
1. **Indipendenza**: Il modulo non deve avere dipendenze dalla logica di business dell'applicazione ospite (es. non deve conoscere `ElevationManager`).
2. **Modularità**: Separazione netta tra logica di elaborazione (`Engine`) e logica di visualizzazione (`Visualizer`).
3. **Testabilità**: Inclusione di un tool di debug integrato (`debug_tool.py`) per lo sviluppo e il test isolato delle funzionalità.
4. **Interfaccia Chiara**: Esposizione di API semplici per richiedere immagini di mappe basate su aree, punti o raggi.
---
## 2. Architettura del Nuovo Modulo
Il modulo `python-map-manager` esporrà due componenti principali:
### A. `MapEngine` (Logica Backend)
È il cervello del modulo. Non ha interfaccia grafica.
* **Responsabilità**:
* Gestione dei provider di mappe (es. OpenStreetMap).
* Gestione della cache su disco (download, salvataggio, recupero).
* Calcoli matematici (conversioni coordinate Geo <-> Pixel, calcolo Bounding Box).
* Stitching (unione) delle tile per formare un'unica immagine PIL.
* **Funzionalità Chiave**:
* `get_image_for_area(bbox, max_size)`: Restituisce un'immagine ottimizzata per coprire un'area.
* `get_image_for_point(lat, lon, zoom, size)`: Restituisce un'immagine centrata su un punto.
### B. `MapVisualizer` (Interfaccia Frontend - Opzionale)
È il componente di visualizzazione interattiva (basato su OpenCV).
* **Responsabilità**:
* Apertura e gestione della finestra grafica.
* Gestione dell'input utente (Mouse, Zoom, Pan).
* Rendering dell'immagine fornita dall'`Engine`.
* **Disaccoppiamento**:
* Invece di chiamare funzioni esterne, il Visualizer emette **Eventi** (tramite callback) quando l'utente interagisce (es. `on_map_click`, `on_area_selected`). L'applicazione ospite si sottoscrive a questi eventi.
---
## 3. Struttura del Repository `python-map-manager`
```text
python-map-manager/
├── map_manager/ # Package Python principale
│ ├── __init__.py # Espone MapEngine e MapVisualizer
│ ├── engine.py # Classe MapEngine (Facade logica)
│ ├── visualizer.py # Classe MapVisualizer (Gestione Window/OpenCV)
│ ├── tile_manager.py # Gestione download e cache (ex map_manager.py)
│ ├── services.py # Definizioni Provider Mappe (ex map_services.py)
│ ├── utils.py # Calcoli geografici puri (ex map_utils.py)
│ └── drawing.py # Funzioni di disegno su PIL (ex map_drawing.py)
├── debug_tool.py # Tool CLI/GUI per testare il modulo isolatamente
├── requirements.txt # Dipendenze (requests, Pillow, opencv-python, mercantile, pyproj)
└── README.md # Documentazione API
```
---
## 4. Fasi di Implementazione
### Fase 1: Setup dell'Ambiente e Migrazione File "Puri"
In questa fase si crea la struttura base e si migrano le librerie di utilità che non richiedono refactoring logico.
1. Creare la cartella `python-map-manager` e inizializzare git.
2. Creare la struttura cartelle `map_manager/`.
3. **Migrazione Diretta**:
* Copiare `geoelevation/map_viewer/map_services.py` -> `map_manager/services.py`.
* Copiare `geoelevation/map_viewer/map_utils.py` -> `map_manager/utils.py`.
* Copiare `geoelevation/map_viewer/map_drawing.py` -> `map_manager/drawing.py`.
* Copiare `geoelevation/map_viewer/map_manager.py` -> `map_manager/tile_manager.py` (Rinominato per chiarezza).
4. **Normalizzazione Import**: Aggiornare gli import interni ai file copiati per puntare ai nuovi percorsi relativi (es. `from .services import ...` invece di `from .map_services import ...`).
### Fase 2: Implementazione di `MapEngine` (`engine.py`)
In questa fase si astrae la logica di calcolo e recupero immagini.
1. Creare `map_manager/engine.py`.
2. Definire la classe `MapEngine`.
3. Implementare il metodo `__init__` per configurare il `MapTileManager` e la cache.
4. Implementare `get_image_for_area`:
* Deve accettare coordinate `(min_lat, min_lon, max_lat, max_lon)`.
* Deve usare `utils.py` per calcolare lo zoom ottimale in base alle dimensioni pixel richieste.
* Deve chiamare `tile_manager.stitch_map_image`.
5. Implementare `get_image_for_point`:
* Accetta centro e livello di zoom.
* Calcola il Bounding Box necessario usando `utils.py`.
* Richiede lo stitching.
### Fase 3: Implementazione di `MapVisualizer` (`visualizer.py`)
In questa fase si crea il gestore della finestra, rimuovendo ogni logica di business specifica di `geoelevation`.
1. Creare `map_manager/visualizer.py`.
2. Definire la classe `MapVisualizer` che accetta un'istanza di `MapEngine`.
3. Estrarre la logica OpenCV da `geo_map_viewer.py` e `map_display.py`.
4. Implementare il loop di gestione eventi mouse (`cv2.setMouseCallback`).
5. **Refactoring Eventi**:
* Definire una proprietà `callback_on_click` (funzione che accetta lat, lon).
* Quando avviene un click, usare `engine` o `utils` per convertire Pixel -> Lat/Lon.
* Invocare `self.callback_on_click(lat, lon)` invece di chiamare `elevation_manager`.
### Fase 4: Creazione del `debug_tool.py`
Uno strumento essenziale per garantire che il modulo funzioni "out of the box".
1. Creare `debug_tool.py` nella root del repository.
2. Lo script deve:
* Istanziare `MapEngine` (con una cache temporanea o di debug).
* Istanziare `MapVisualizer`.
* Definire una funzione dummy: `def on_click(lat, lon): print(f"Clicked: {lat}, {lon}")`.
* Collegare la funzione al visualizzatore.
* Avviare la mappa su coordinate di default (es. Roma).
3. Questo tool servirà per verificare lo zoom, il pan e la correttezza del download delle tile.
### Fase 5: Integrazione nell'Applicazione Principale
Una volta che il submodule è stabile e pushato sul repository remoto.
1. In `geoelevation`, rimuovere la cartella `map_viewer` esistente.
2. Aggiungere il submodule:
```bash
git submodule add -b master <URL_REPO> external/python-map-manager
```
3. Configurare i path in `geoelevation/__init__.py` (o file di setup path dedicato) per includere il submodule.
4. Modificare `geoelevation/process_targets.py` (o dove risiede il processo mappa):
* Importare `MapEngine` e `MapVisualizer` dal submodule.
* Nel processo dedicato alla mappa, definire la funzione di callback reale che interroga `ElevationManager`.
* Passare questa callback al `MapVisualizer`.
---
## 5. Specifiche Tecniche e Standard
* **PEP8**: Tutto il codice deve seguire rigorosamente lo standard PEP8.
* **Type Hinting**: Ogni funzione deve avere le annotazioni di tipo (`-> Optional[Image.Image]`, ecc.).
* **Docstrings**: Ogni classe e metodo pubblico deve avere docstring in Inglese.
* **Dipendenze**:
* Non usare `try-except ImportError` per nascondere dipendenze mancanti all'interno del modulo. Se `MapVisualizer` richiede OpenCV, l'import deve fallire esplicitamente se manca, o essere gestito a livello di `__init__.py` per esporre le funzionalità disponibili.
* Il file `requirements.txt` deve elencare le versioni minime testate.
## 6. Risultato Atteso
Al termine di questo processo, avremo:
1. Un repository `python-map-manager` autonomo.
2. La possibilità di sviluppare e migliorare la gestione mappe lanciando solo `python debug_tool.py`.
3. L'applicazione `geoelevation` più leggera, che delega tutta la complessità cartografica al modulo esterno, mantenendo solo la logica di "cosa fare quando l'utente clicca un punto" (ovvero chiedere l'elevazione).