8.2 KiB
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
- Indipendenza: Il modulo non deve avere dipendenze dalla logica di business dell'applicazione ospite (es. non deve conoscere
ElevationManager). - Modularità: Separazione netta tra logica di elaborazione (
Engine) e logica di visualizzazione (Visualizer). - Testabilità: Inclusione di un tool di debug integrato (
debug_tool.py) per lo sviluppo e il test isolato delle funzionalità. - 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.
- Invece di chiamare funzioni esterne, il Visualizer emette Eventi (tramite callback) quando l'utente interagisce (es.
3. Struttura del Repository python-map-manager
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.
- Creare la cartella
python-map-managere inizializzare git. - Creare la struttura cartelle
map_manager/. - 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).
- Copiare
- Normalizzazione Import: Aggiornare gli import interni ai file copiati per puntare ai nuovi percorsi relativi (es.
from .services import ...invece difrom .map_services import ...).
Fase 2: Implementazione di MapEngine (engine.py)
In questa fase si astrae la logica di calcolo e recupero immagini.
- Creare
map_manager/engine.py. - Definire la classe
MapEngine. - Implementare il metodo
__init__per configurare ilMapTileManagere la cache. - Implementare
get_image_for_area:- Deve accettare coordinate
(min_lat, min_lon, max_lat, max_lon). - Deve usare
utils.pyper calcolare lo zoom ottimale in base alle dimensioni pixel richieste. - Deve chiamare
tile_manager.stitch_map_image.
- Deve accettare coordinate
- 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.
- Creare
map_manager/visualizer.py. - Definire la classe
MapVisualizerche accetta un'istanza diMapEngine. - Estrarre la logica OpenCV da
geo_map_viewer.pyemap_display.py. - Implementare il loop di gestione eventi mouse (
cv2.setMouseCallback). - Refactoring Eventi:
- Definire una proprietà
callback_on_click(funzione che accetta lat, lon). - Quando avviene un click, usare
engineoutilsper convertire Pixel -> Lat/Lon. - Invocare
self.callback_on_click(lat, lon)invece di chiamareelevation_manager.
- Definire una proprietà
Fase 4: Creazione del debug_tool.py
Uno strumento essenziale per garantire che il modulo funzioni "out of the box".
- Creare
debug_tool.pynella root del repository. - 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).
- Istanziare
- 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.
- In
geoelevation, rimuovere la cartellamap_vieweresistente. - Aggiungere il submodule:
git submodule add -b master <URL_REPO> external/python-map-manager - Configurare i path in
geoelevation/__init__.py(o file di setup path dedicato) per includere il submodule. - Modificare
geoelevation/process_targets.py(o dove risiede il processo mappa):- Importare
MapEngineeMapVisualizerdal submodule. - Nel processo dedicato alla mappa, definire la funzione di callback reale che interroga
ElevationManager. - Passare questa callback al
MapVisualizer.
- Importare
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 ImportErrorper nascondere dipendenze mancanti all'interno del modulo. SeMapVisualizerrichiede OpenCV, l'import deve fallire esplicitamente se manca, o essere gestito a livello di__init__.pyper esporre le funzionalità disponibili. - Il file
requirements.txtdeve elencare le versioni minime testate.
- Non usare
6. Risultato Atteso
Al termine di questo processo, avremo:
- Un repository
python-map-managerautonomo. - La possibilità di sviluppare e migliorare la gestione mappe lanciando solo
python debug_tool.py. - L'applicazione
geoelevationpiù 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).