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 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).