fix map with grey band
This commit is contained in:
parent
e46b86aea5
commit
7934fc8d2c
@ -157,34 +157,44 @@ class MapCanvasManager:
|
|||||||
self.update_map_view_for_bbox(new_bbox_dict, preserve_current_zoom_if_possible=False)
|
self.update_map_view_for_bbox(new_bbox_dict, preserve_current_zoom_if_possible=False)
|
||||||
|
|
||||||
def update_map_view_for_bbox(self, target_bbox_dict: Dict[str, float], preserve_current_zoom_if_possible: bool = False):
|
def update_map_view_for_bbox(self, target_bbox_dict: Dict[str, float], preserve_current_zoom_if_possible: bool = False):
|
||||||
|
# Questa funzione ora calcola il centro e lo zoom OTTIMALI
|
||||||
|
# per visualizzare target_bbox_dict e poi chiama recenter_and_redraw.
|
||||||
if not target_bbox_dict:
|
if not target_bbox_dict:
|
||||||
logger.warning("update_map_view_for_bbox called with no target_bbox_dict.")
|
logger.warning("update_map_view_for_bbox called with no target_bbox_dict.")
|
||||||
return
|
return
|
||||||
|
|
||||||
self._target_bbox_input = target_bbox_dict.copy()
|
self._target_bbox_input = target_bbox_dict.copy() # Memorizza il BBox utente
|
||||||
|
|
||||||
|
# Se questa chiamata deriva da un'impostazione esplicita del BBox (non da pan/zoom interattivo),
|
||||||
|
# aggiorna anche il BBox di riferimento per i voli.
|
||||||
|
if not preserve_current_zoom_if_possible:
|
||||||
|
self._active_api_bbox_for_flights = target_bbox_dict.copy()
|
||||||
|
|
||||||
|
|
||||||
lat_min = target_bbox_dict['lat_min']
|
lat_min = target_bbox_dict['lat_min']
|
||||||
lon_min = target_bbox_dict['lon_min']
|
lon_min = target_bbox_dict['lon_min']
|
||||||
lat_max = target_bbox_dict['lat_max']
|
lat_max = target_bbox_dict['lat_max']
|
||||||
lon_max = target_bbox_dict['lon_max']
|
lon_max = target_bbox_dict['lon_max']
|
||||||
|
|
||||||
center_lat = (lat_min + lat_max) / 2.0
|
# Il centro della mappa sarà il centro del BBox utente
|
||||||
center_lon = (lon_min + lon_max) / 2.0
|
view_center_lat = (lat_min + lat_max) / 2.0
|
||||||
if lon_min > lon_max:
|
view_center_lon = (lon_min + lon_max) / 2.0
|
||||||
|
if lon_min > lon_max: # Antimeridian
|
||||||
center_lon_adjusted = (lon_min + (lon_max + 360.0)) / 2.0
|
center_lon_adjusted = (lon_min + (lon_max + 360.0)) / 2.0
|
||||||
center_lon = center_lon_adjusted - 360.0 if center_lon_adjusted >= 180.0 else center_lon_adjusted
|
view_center_lon = center_lon_adjusted - 360.0 if center_lon_adjusted >= 180.0 else center_lon_adjusted
|
||||||
|
|
||||||
logger.info(f"Updating map view for target BBox: {self._target_bbox_input}. Calculated center: ({center_lat:.4f}, {center_lon:.4f})")
|
logger.info(f"Updating map view for target BBox: {self._target_bbox_input}. Target view center: ({view_center_lat:.4f}, {view_center_lon:.4f})")
|
||||||
|
|
||||||
new_zoom_level_to_use = self._current_zoom if self._current_zoom is not None and preserve_current_zoom_if_possible else DEFAULT_INITIAL_ZOOM
|
# Lo zoom da usare. Se preserviamo, usiamo il corrente, altrimenti calcoliamo.
|
||||||
|
zoom_to_use = self._current_zoom if self._current_zoom is not None and preserve_current_zoom_if_possible else DEFAULT_INITIAL_ZOOM
|
||||||
|
|
||||||
if not preserve_current_zoom_if_possible:
|
if not preserve_current_zoom_if_possible:
|
||||||
calculated_zoom_val = DEFAULT_INITIAL_ZOOM
|
calculated_zoom_for_target_bbox = DEFAULT_INITIAL_ZOOM
|
||||||
if PYPROJ_MODULE_LOCALLY_AVAILABLE and pyproj is not None:
|
if PYPROJ_MODULE_LOCALLY_AVAILABLE and pyproj is not None:
|
||||||
try:
|
try:
|
||||||
geod = pyproj.Geod(ellps="WGS84")
|
geod = pyproj.Geod(ellps="WGS84")
|
||||||
_, _, height_m = geod.inv(center_lon, lat_min, center_lon, lat_max)
|
_, _, height_m = geod.inv(view_center_lon, lat_min, view_center_lon, lat_max)
|
||||||
_, _, width_m = geod.inv(lon_min, center_lat, lon_max, center_lat)
|
_, _, width_m = geod.inv(lon_min, view_center_lat, lon_max, view_center_lat)
|
||||||
height_m = abs(height_m)
|
height_m = abs(height_m)
|
||||||
width_m = abs(width_m)
|
width_m = abs(width_m)
|
||||||
logger.debug(f"Geographic dimensions of target BBox: Width={width_m:.0f}m, Height={height_m:.0f}m")
|
logger.debug(f"Geographic dimensions of target BBox: Width={width_m:.0f}m, Height={height_m:.0f}m")
|
||||||
@ -207,54 +217,56 @@ class MapCanvasManager:
|
|||||||
if res_needed_for_height != float('inf') and res_needed_for_height > 0:
|
if res_needed_for_height != float('inf') and res_needed_for_height > 0:
|
||||||
target_resolution_m_px = res_needed_for_height
|
target_resolution_m_px = res_needed_for_height
|
||||||
valid_res_found = True
|
valid_res_found = True
|
||||||
# Modifica qui per usare max correttemente
|
|
||||||
if res_needed_for_width != float('inf') and res_needed_for_width > 0:
|
if res_needed_for_width != float('inf') and res_needed_for_width > 0:
|
||||||
if valid_res_found:
|
current_target_res = target_resolution_m_px if valid_res_found else float('inf') # Inizializza con l'altezza se valida
|
||||||
target_resolution_m_px = max(target_resolution_m_px, res_needed_for_width)
|
target_resolution_m_px = max(current_target_res, res_needed_for_width) # Prendi la risoluzione maggiore (zoom minore)
|
||||||
else:
|
|
||||||
target_resolution_m_px = res_needed_for_width
|
|
||||||
valid_res_found = True
|
valid_res_found = True
|
||||||
|
|
||||||
if not valid_res_found: target_resolution_m_px = float('inf')
|
if not valid_res_found and target_resolution_m_px == float('inf'): # Se nessuna dimensione valida
|
||||||
|
logger.warning("Could not determine valid target resolution from BBox dimensions or canvas size.")
|
||||||
|
target_resolution_m_px = 0 # Per forzare fallback
|
||||||
|
|
||||||
logger.debug(f"Canvas: {current_canvas_width}x{current_canvas_height}. Resolutions needed H,W (m/px): {res_needed_for_height:.2f}, {res_needed_for_width:.2f}. Target res: {target_resolution_m_px:.2f} m/px")
|
logger.debug(f"Canvas: {current_canvas_width}x{current_canvas_height}. Resolutions needed for target BBox (H,W) (m/px): {res_needed_for_height:.2f}, {res_needed_for_width:.2f}. Final Target res: {target_resolution_m_px:.2f} m/px")
|
||||||
|
|
||||||
if target_resolution_m_px > 0 and target_resolution_m_px != float('inf'):
|
if target_resolution_m_px > 0 and target_resolution_m_px != float('inf'):
|
||||||
EARTH_CIRCUMFERENCE_METERS = 40075016.686
|
EARTH_CIRCUMFERENCE_METERS = 40075016.686
|
||||||
clamped_center_lat_for_cos = max(-85.05, min(85.05, center_lat))
|
clamped_center_lat_for_cos = max(-85.05, min(85.05, view_center_lat)) # Usa il centro del BBox per il calcolo dello zoom
|
||||||
cos_val = math.cos(math.radians(clamped_center_lat_for_cos))
|
cos_val = math.cos(math.radians(clamped_center_lat_for_cos))
|
||||||
if cos_val > 1e-9 and self.tile_manager.tile_size > 0:
|
if cos_val > 1e-9 and self.tile_manager.tile_size > 0:
|
||||||
term_for_log = (EARTH_CIRCUMFERENCE_METERS * cos_val) / \
|
term_for_log = (EARTH_CIRCUMFERENCE_METERS * cos_val) / \
|
||||||
(self.tile_manager.tile_size * target_resolution_m_px)
|
(self.tile_manager.tile_size * target_resolution_m_px)
|
||||||
if term_for_log > 0:
|
if term_for_log > 0:
|
||||||
precise_zoom = math.log2(term_for_log)
|
precise_zoom = math.log2(term_for_log)
|
||||||
calculated_zoom_val = int(round(precise_zoom))
|
calculated_zoom_for_target_bbox = int(round(precise_zoom))
|
||||||
max_zoom_limit = self.map_service.max_zoom if self.map_service else DEFAULT_MAX_ZOOM_FALLBACK
|
max_zoom_limit = self.map_service.max_zoom if self.map_service else DEFAULT_MAX_ZOOM_FALLBACK
|
||||||
new_zoom_level_to_use = max(MIN_ZOOM_LEVEL, min(calculated_zoom_val, max_zoom_limit))
|
zoom_to_use = max(MIN_ZOOM_LEVEL, min(calculated_zoom_for_target_bbox, max_zoom_limit))
|
||||||
logger.info(f"Calculated zoom {new_zoom_level_to_use} to fit BBox (precise float: {precise_zoom:.2f}).")
|
logger.info(f"Calculated zoom {zoom_to_use} to fit target BBox (precise float: {precise_zoom:.2f}).")
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Cannot calculate zoom for BBox: term for log2 is non-positive ({term_for_log}). Using zoom {DEFAULT_INITIAL_ZOOM}.")
|
logger.warning(f"Cannot calculate zoom for BBox: term for log2 non-positive. Using zoom {DEFAULT_INITIAL_ZOOM}.")
|
||||||
new_zoom_level_to_use = DEFAULT_INITIAL_ZOOM
|
zoom_to_use = DEFAULT_INITIAL_ZOOM
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Cannot calculate zoom for BBox: cosine of latitude or tile_size is problematic. Using zoom {DEFAULT_INITIAL_ZOOM}.")
|
logger.warning(f"Cannot calculate zoom for BBox: cosine of latitude or tile_size problematic. Using zoom {DEFAULT_INITIAL_ZOOM}.")
|
||||||
new_zoom_level_to_use = DEFAULT_INITIAL_ZOOM
|
zoom_to_use = DEFAULT_INITIAL_ZOOM
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Cannot calculate zoom for BBox: target resolution is invalid or zero. Using zoom {DEFAULT_INITIAL_ZOOM}.")
|
logger.warning(f"Cannot calculate zoom for BBox: target resolution invalid. Using zoom {DEFAULT_INITIAL_ZOOM}.")
|
||||||
new_zoom_level_to_use = DEFAULT_INITIAL_ZOOM
|
zoom_to_use = DEFAULT_INITIAL_ZOOM
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error calculating zoom for BBox using pyproj: {e}. Using zoom {DEFAULT_INITIAL_ZOOM}.", exc_info=True)
|
logger.error(f"Error calculating zoom for BBox using pyproj: {e}. Using zoom {DEFAULT_INITIAL_ZOOM}.", exc_info=True)
|
||||||
new_zoom_level_to_use = DEFAULT_INITIAL_ZOOM
|
zoom_to_use = DEFAULT_INITIAL_ZOOM
|
||||||
else:
|
else:
|
||||||
logger.warning("Pyproj module not available in MapCanvasManager, cannot accurately calculate zoom for BBox. Using default zoom.")
|
logger.warning("Pyproj module not available. Using default zoom.")
|
||||||
new_zoom_level_to_use = DEFAULT_INITIAL_ZOOM
|
zoom_to_use = DEFAULT_INITIAL_ZOOM
|
||||||
|
|
||||||
self.recenter_and_redraw(center_lat, center_lon, new_zoom_level_to_use, ensure_bbox_is_covered=self._target_bbox_input)
|
# recenter_and_redraw userà view_center_lat, view_center_lon e zoom_to_use.
|
||||||
|
# Non passerà più `ensure_bbox_is_covered` perché il centro e lo zoom
|
||||||
|
# sono già stati calcolati per mostrare il _target_bbox_input.
|
||||||
|
self.recenter_and_redraw(view_center_lat, view_center_lon, zoom_to_use)
|
||||||
|
|
||||||
def recenter_and_redraw(self, center_lat: float, center_lon: float, zoom_level: int,
|
def recenter_and_redraw(self, center_lat: float, center_lon: float, zoom_level: int,
|
||||||
ensure_bbox_is_covered: Optional[Dict[str,float]] = None):
|
ensure_bbox_is_covered_dict: Optional[Dict[str, float]] = None):
|
||||||
logger.info(f"Recentering map. Target Center: ({center_lat:.4f}, {center_lon:.4f}), Zoom: {zoom_level}")
|
logger.info(f"Recentering map. Target View Center: ({center_lat:.4f}, {center_lon:.4f}), Zoom: {zoom_level}")
|
||||||
if ensure_bbox_is_covered:
|
if ensure_bbox_is_covered_dict:
|
||||||
logger.debug(f"This redraw will ensure BBox is covered: {ensure_bbox_is_covered}")
|
logger.debug(f"This redraw must ensure BBox is fully visible: {ensure_bbox_is_covered_dict}")
|
||||||
|
|
||||||
self._current_center_lat = center_lat
|
self._current_center_lat = center_lat
|
||||||
self._current_center_lon = center_lon
|
self._current_center_lon = center_lon
|
||||||
@ -262,54 +274,62 @@ class MapCanvasManager:
|
|||||||
|
|
||||||
current_canvas_width = self.canvas.winfo_width()
|
current_canvas_width = self.canvas.winfo_width()
|
||||||
current_canvas_height = self.canvas.winfo_height()
|
current_canvas_height = self.canvas.winfo_height()
|
||||||
if current_canvas_width <=1 : current_canvas_width = self.canvas_width
|
if current_canvas_width <= 1: current_canvas_width = self.canvas_width
|
||||||
if current_canvas_height <=1 : current_canvas_height = self.canvas_height
|
if current_canvas_height <= 1: current_canvas_height = self.canvas_height
|
||||||
|
|
||||||
map_fetch_geo_bounds_for_tiles: Optional[Tuple[float, float, float, float]]
|
map_fetch_geo_bounds_for_tiles_tuple: Optional[Tuple[float, float, float, float]]
|
||||||
|
|
||||||
if ensure_bbox_is_covered:
|
if ensure_bbox_is_covered_dict:
|
||||||
# Logica per calcolare un BBox di tile che copra `ensure_bbox_is_covered`
|
# Caso 1: Dobbiamo visualizzare un BBox specifico (_target_bbox_input)
|
||||||
# E che sia anche centrato su `center_lat`, `center_lon` e riempia il canvas
|
# Lo zoom e il centro sono già stati calcolati da update_map_view_for_bbox
|
||||||
# Questo è il caso più complesso: vogliamo vedere un BBox specifico E riempire il canvas.
|
# per far entrare questo BBox nel canvas.
|
||||||
# Lo zoom è già stato calcolato in `update_map_view_for_bbox` per far entrare `ensure_bbox_is_covered`.
|
# Ora dobbiamo determinare le tile da scaricare.
|
||||||
# Quindi, i `map_fetch_geo_bounds_for_tiles` dovrebbero essere quelli che, a questo zoom e centro,
|
# Il BBox delle tile deve coprire almeno ensure_bbox_is_covered_dict.
|
||||||
# riempiono il canvas. Se questi bounds sono più piccoli di `ensure_bbox_is_covered`,
|
# E, per evitare barre grigie, dovrebbe anche cercare di riempire il canvas
|
||||||
# allora lo zoom calcolato non era sufficientemente basso.
|
# mantenendo il centro e lo zoom calcolati.
|
||||||
# Per ora, semplifichiamo: il BBox per le tile sarà quello che riempie il canvas
|
|
||||||
# al centro/zoom calcolati (che dovrebbero già tenere conto di far entrare `ensure_bbox_is_covered`).
|
user_bb = ensure_bbox_is_covered_dict
|
||||||
map_fetch_geo_bounds_for_tiles = calculate_geographic_bbox_from_pixel_size_and_zoom(
|
|
||||||
self._current_center_lat, self._current_center_lon,
|
# Calcola il BBox che riempirebbe il canvas a questo centro e zoom
|
||||||
|
canvas_fill_bbox = calculate_geographic_bbox_from_pixel_size_and_zoom(
|
||||||
|
self._current_center_lat, self._current_center_lon, # Centro del BBox utente
|
||||||
current_canvas_width, current_canvas_height,
|
current_canvas_width, current_canvas_height,
|
||||||
self._current_zoom, self.tile_manager.tile_size
|
self._current_zoom, self.tile_manager.tile_size
|
||||||
)
|
)
|
||||||
if map_fetch_geo_bounds_for_tiles:
|
|
||||||
logger.debug(f"Tile fetching for BBox coverage, calculated canvas fill bounds: {map_fetch_geo_bounds_for_tiles} at zoom {self._current_zoom}")
|
if not canvas_fill_bbox:
|
||||||
|
logger.error("Failed to calculate canvas_fill_bbox even when ensure_bbox_is_covered was set. Using user_bbox directly.")
|
||||||
|
map_fetch_geo_bounds_for_tiles_tuple = (
|
||||||
|
user_bb['lon_min'], user_bb['lat_min'],
|
||||||
|
user_bb['lon_max'], user_bb['lat_max']
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
logger.error("Failed to calculate canvas filling BBox even when ensure_bbox_is_covered was set.")
|
# Ora crea un BBox che sia l'unione del BBox utente e del BBox che riempie il canvas.
|
||||||
# Fallback: usa direttamente ensure_bbox_is_covered per le tile, potrebbe non riempire il canvas
|
# Questo assicura che il BBox utente sia dentro E che il canvas sia riempito.
|
||||||
map_fetch_geo_bounds_for_tiles = (
|
final_west = min(user_bb['lon_min'], canvas_fill_bbox[0])
|
||||||
ensure_bbox_is_covered['lon_min'], ensure_bbox_is_covered['lat_min'],
|
final_south = min(user_bb['lat_min'], canvas_fill_bbox[1])
|
||||||
ensure_bbox_is_covered['lon_max'], ensure_bbox_is_covered['lat_max']
|
final_east = max(user_bb['lon_max'], canvas_fill_bbox[2])
|
||||||
)
|
final_north = max(user_bb['lat_max'], canvas_fill_bbox[3])
|
||||||
logger.warning(f"Falling back to fetching tiles strictly for ensure_bbox_is_covered: {map_fetch_geo_bounds_for_tiles}")
|
map_fetch_geo_bounds_for_tiles_tuple = (final_west, final_south, final_east, final_north)
|
||||||
|
logger.debug(f"Combined BBox (user & canvas fill) for tile fetching: {map_fetch_geo_bounds_for_tiles_tuple} at zoom {self._current_zoom}")
|
||||||
|
|
||||||
else: # Pan/Zoom interattivo
|
else: # Caso 2: Pan/Zoom interattivo, non c'è un "ensure_bbox_is_covered_dict"
|
||||||
map_fetch_geo_bounds_for_tiles = calculate_geographic_bbox_from_pixel_size_and_zoom(
|
map_fetch_geo_bounds_for_tiles_tuple = calculate_geographic_bbox_from_pixel_size_and_zoom(
|
||||||
self._current_center_lat, self._current_center_lon,
|
self._current_center_lat, self._current_center_lon,
|
||||||
current_canvas_width, current_canvas_height,
|
current_canvas_width, current_canvas_height,
|
||||||
self._current_zoom, self.tile_manager.tile_size
|
self._current_zoom, self.tile_manager.tile_size
|
||||||
)
|
)
|
||||||
if map_fetch_geo_bounds_for_tiles:
|
if map_fetch_geo_bounds_for_tiles_tuple:
|
||||||
logger.debug(f"Tile fetching for interactive pan/zoom (canvas-fill): {map_fetch_geo_bounds_for_tiles} at zoom {self._current_zoom}")
|
logger.debug(f"Tile fetching for interactive pan/zoom (canvas-fill): {map_fetch_geo_bounds_for_tiles_tuple} at zoom {self._current_zoom}")
|
||||||
|
|
||||||
if not map_fetch_geo_bounds_for_tiles:
|
if not map_fetch_geo_bounds_for_tiles_tuple:
|
||||||
logger.error("Failed to determine geographic bounds for tile fetching. Cannot draw map.")
|
logger.error("Failed to determine geographic bounds for tile fetching. Cannot draw map.")
|
||||||
self._clear_canvas_content()
|
self._clear_canvas_content()
|
||||||
return
|
return
|
||||||
|
|
||||||
tile_xy_ranges = get_tile_ranges_for_bbox(map_fetch_geo_bounds_for_tiles, self._current_zoom)
|
tile_xy_ranges = get_tile_ranges_for_bbox(map_fetch_geo_bounds_for_tiles_tuple, self._current_zoom)
|
||||||
if not tile_xy_ranges:
|
if not tile_xy_ranges:
|
||||||
logger.error(f"Failed to get tile ranges for fetch_bounds {map_fetch_geo_bounds_for_tiles}. Cannot draw map.")
|
logger.error(f"Failed to get tile ranges for fetch_bounds {map_fetch_geo_bounds_for_tiles_tuple}. Cannot draw map.")
|
||||||
self._clear_canvas_content()
|
self._clear_canvas_content()
|
||||||
return
|
return
|
||||||
logger.debug(f"Tile ranges for current view: X={tile_xy_ranges[0]}, Y={tile_xy_ranges[1]}")
|
logger.debug(f"Tile ranges for current view: X={tile_xy_ranges[0]}, Y={tile_xy_ranges[1]}")
|
||||||
@ -326,13 +346,13 @@ class MapCanvasManager:
|
|||||||
actual_stitched_geo_bounds = self.tile_manager._get_bounds_for_tile_range(self._current_zoom, tile_xy_ranges)
|
actual_stitched_geo_bounds = self.tile_manager._get_bounds_for_tile_range(self._current_zoom, tile_xy_ranges)
|
||||||
if not actual_stitched_geo_bounds:
|
if not actual_stitched_geo_bounds:
|
||||||
logger.error("Failed to get actual geographic bounds of stitched tiles. Using calculated fetch_bounds as fallback.")
|
logger.error("Failed to get actual geographic bounds of stitched tiles. Using calculated fetch_bounds as fallback.")
|
||||||
self._current_map_geo_bounds = map_fetch_geo_bounds_for_tiles
|
self._current_map_geo_bounds = map_fetch_geo_bounds_for_tiles_tuple
|
||||||
else:
|
else:
|
||||||
self._current_map_geo_bounds = actual_stitched_geo_bounds
|
self._current_map_geo_bounds = actual_stitched_geo_bounds
|
||||||
|
|
||||||
logger.debug(f"Actual geographic bounds of final stitched map: {self._current_map_geo_bounds}")
|
logger.debug(f"Actual geographic bounds of final stitched map (self._current_map_geo_bounds): {self._current_map_geo_bounds}")
|
||||||
self._map_pil_image = stitched_map_pil
|
self._map_pil_image = stitched_map_pil
|
||||||
self._redraw_canvas_content()
|
self._redraw_canvas_content()
|
||||||
|
|
||||||
def _redraw_canvas_content(self):
|
def _redraw_canvas_content(self):
|
||||||
logger.debug(f"_redraw_canvas_content called. Current zoom: {self._current_zoom}, Flights to draw: {len(self._current_flights_to_display)}")
|
logger.debug(f"_redraw_canvas_content called. Current zoom: {self._current_zoom}, Flights to draw: {len(self._current_flights_to_display)}")
|
||||||
@ -517,28 +537,74 @@ class MapCanvasManager:
|
|||||||
|
|
||||||
if new_zoom != self._current_zoom:
|
if new_zoom != self._current_zoom:
|
||||||
logger.info(f"Zoom changed from {self._current_zoom} to {new_zoom}")
|
logger.info(f"Zoom changed from {self._current_zoom} to {new_zoom}")
|
||||||
# Durante lo zoom interattivo, non c'è un "ensure_bbox_is_covered" fisso.
|
self.recenter_and_redraw(target_center_lat, target_center_lon, new_zoom)
|
||||||
# Il _target_bbox_input (contorno blu) rimane, ma la vista si adatta.
|
|
||||||
self.recenter_and_redraw(target_center_lat, target_center_lon, new_zoom, ensure_bbox_is_covered=None)
|
|
||||||
else:
|
else:
|
||||||
logger.debug(f"Zoom unchanged (already at min/max: {self._current_zoom})")
|
logger.debug(f"Zoom unchanged (already at min/max: {self._current_zoom})")
|
||||||
|
|
||||||
def _on_mouse_button_press(self, event: tk.Event):
|
def _on_mouse_button_press(self, event: tk.Event):
|
||||||
if not self.canvas.winfo_exists(): return
|
if not self.canvas.winfo_exists(): return
|
||||||
self._drag_start_x = event.x
|
# Salva il punto di inizio del drag in coordinate CANVAS
|
||||||
self._drag_start_y = event.y
|
self._drag_start_x_canvas = event.x
|
||||||
self._is_dragging = True
|
self._drag_start_y_canvas = event.y
|
||||||
|
# Salva anche il centro geografico corrente all'inizio del drag
|
||||||
|
if self._current_center_lat is not None and self._current_center_lon is not None:
|
||||||
|
self._drag_start_center_lon = self._current_center_lon
|
||||||
|
self._drag_start_center_lat = self._current_center_lat
|
||||||
|
else: # Non dovrebbe succedere se la mappa è visualizzata
|
||||||
|
self._drag_start_center_lon = None
|
||||||
|
self._drag_start_center_lat = None
|
||||||
|
|
||||||
|
self._is_dragging = False # Non considerarlo un drag finché non c'è movimento
|
||||||
self.canvas.config(cursor="fleur")
|
self.canvas.config(cursor="fleur")
|
||||||
logger.debug(f"Mouse button press at ({event.x}, {event.y}) for panning.")
|
logger.debug(f"Mouse button press at ({event.x}, {event.y}). Ready for potential pan.")
|
||||||
|
|
||||||
def _on_mouse_drag(self, event: tk.Event):
|
def _on_mouse_drag(self, event: tk.Event):
|
||||||
if not self._is_dragging or self._drag_start_x is None or self._drag_start_y is None or \
|
if self._drag_start_x_canvas is None or self._drag_start_y_canvas is None or \
|
||||||
self._current_map_geo_bounds is None or not self.canvas.winfo_exists() or \
|
self._drag_start_center_lon is None or self._drag_start_center_lat is None or \
|
||||||
self._current_center_lat is None or self._current_center_lon is None or self._current_zoom is None:
|
self._current_map_geo_bounds is None or not self.canvas.winfo_exists() or self._current_zoom is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
dx_pixel = event.x - self._drag_start_x
|
self._is_dragging = True # Il mouse si è mosso mentre era premuto
|
||||||
dy_pixel = event.y - self._drag_start_y
|
|
||||||
|
# --- Logica per visualizzare un'anteprima del pan (OPZIONALE e più complesso) ---
|
||||||
|
# Si potrebbe spostare l'immagine PhotoImage esistente sul canvas SPOSTANDO l'item_id
|
||||||
|
# self.canvas.move(self._canvas_image_id, dx_pixel, dy_pixel)
|
||||||
|
# Questo però non ricarica le tile, mostra solo la stessa immagine spostata.
|
||||||
|
# Per ora, omettiamo l'anteprima per semplicità e ridisegniamo solo al rilascio.
|
||||||
|
# Potremmo cambiare il cursore per indicare il drag.
|
||||||
|
# logger.debug(f"Dragging to ({event.x}, {event.y})") # Troppo verboso
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _on_mouse_button_release(self, event: tk.Event):
|
||||||
|
if not self.canvas.winfo_exists():
|
||||||
|
self.canvas.config(cursor="")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.canvas.config(cursor="") # Ripristina cursore
|
||||||
|
|
||||||
|
if not self._is_dragging: # Se non c'è stato drag, è stato un click semplice
|
||||||
|
logger.debug("Mouse button release without dragging (simple click). Action handled by specific button bindings (e.g., right-click).")
|
||||||
|
self._drag_start_x_canvas = None # Resetta per sicurezza
|
||||||
|
self._drag_start_y_canvas = None
|
||||||
|
self._drag_start_center_lon = None
|
||||||
|
self._drag_start_center_lat = None
|
||||||
|
self._is_dragging = False
|
||||||
|
return
|
||||||
|
|
||||||
|
# Se c'è stato un drag (self._is_dragging è True)
|
||||||
|
logger.debug(f"Mouse button release after drag to ({event.x}, {event.y}). Finalizing pan.")
|
||||||
|
|
||||||
|
if self._drag_start_x_canvas is None or self._drag_start_y_canvas is None or \
|
||||||
|
self._drag_start_center_lon is None or self._drag_start_center_lat is None or \
|
||||||
|
self._current_map_geo_bounds is None or self._current_zoom is None :
|
||||||
|
logger.warning("Cannot finalize pan: drag start state or map context is missing.")
|
||||||
|
self._is_dragging = False
|
||||||
|
self._drag_start_x_canvas = None
|
||||||
|
self._drag_start_y_canvas = None
|
||||||
|
return
|
||||||
|
|
||||||
|
dx_pixel = event.x - self._drag_start_x_canvas
|
||||||
|
dy_pixel = event.y - self._drag_start_y_canvas
|
||||||
|
|
||||||
map_width_deg = self._current_map_geo_bounds[2] - self._current_map_geo_bounds[0]
|
map_width_deg = self._current_map_geo_bounds[2] - self._current_map_geo_bounds[0]
|
||||||
map_height_deg = self._current_map_geo_bounds[3] - self._current_map_geo_bounds[1]
|
map_height_deg = self._current_map_geo_bounds[3] - self._current_map_geo_bounds[1]
|
||||||
@ -550,33 +616,34 @@ class MapCanvasManager:
|
|||||||
if current_canvas_height <=1 : current_canvas_height = self.canvas_height
|
if current_canvas_height <=1 : current_canvas_height = self.canvas_height
|
||||||
|
|
||||||
if current_canvas_width <= 0 or current_canvas_height <= 0:
|
if current_canvas_width <= 0 or current_canvas_height <= 0:
|
||||||
logger.warning("Cannot pan, canvas dimensions are zero.")
|
logger.warning("Cannot finalize pan, canvas dimensions are zero.")
|
||||||
|
self._is_dragging = False
|
||||||
return
|
return
|
||||||
|
|
||||||
deg_per_pixel_lon = map_width_deg / current_canvas_width
|
deg_per_pixel_lon = map_width_deg / current_canvas_width
|
||||||
deg_per_pixel_lat = map_height_deg / current_canvas_height
|
deg_per_pixel_lat = map_height_deg / current_canvas_height
|
||||||
|
|
||||||
delta_lon = -dx_pixel * deg_per_pixel_lon
|
delta_lon = -dx_pixel * deg_per_pixel_lon
|
||||||
delta_lat = dy_pixel * deg_per_pixel_lat
|
delta_lat = dy_pixel * deg_per_pixel_lat
|
||||||
|
|
||||||
new_center_lon = self._current_center_lon + delta_lon
|
# Il nuovo centro è calcolato rispetto al centro che avevamo ALL'INIZIO del drag
|
||||||
new_center_lat = self._current_center_lat + delta_lat
|
new_center_lon = self._drag_start_center_lon + delta_lon
|
||||||
|
new_center_lat = self._drag_start_center_lat + delta_lat
|
||||||
|
|
||||||
new_center_lon = (new_center_lon + 180) % 360 - 180
|
new_center_lon = (new_center_lon + 180) % 360 - 180
|
||||||
new_center_lat = max(-85.05112878, min(85.05112878, new_center_lat)) # Limiti Web Mercator
|
new_center_lat = max(-85.05112878, min(85.05112878, new_center_lat))
|
||||||
|
|
||||||
self.recenter_and_redraw(new_center_lat, new_center_lon, self._current_zoom, ensure_bbox_is_covered=None)
|
logger.info(f"Pan finalized. Old center: ({self._drag_start_center_lat:.4f}, {self._drag_start_center_lon:.4f}), New center: ({new_center_lat:.4f}, {new_center_lon:.4f})")
|
||||||
|
|
||||||
|
# Ridisegna la mappa con il nuovo centro, mantenendo lo zoom.
|
||||||
|
# Non c'è un "ensure_bbox_is_covered" specifico per il pan.
|
||||||
|
self.recenter_and_redraw(new_center_lat, new_center_lon, self._current_zoom, ensure_bbox_is_covered_dict=None) #MODIFICATO nome parametro
|
||||||
|
|
||||||
self._drag_start_x = event.x
|
|
||||||
self._drag_start_y = event.y
|
|
||||||
|
|
||||||
def _on_mouse_button_release(self, event: tk.Event):
|
|
||||||
if not self.canvas.winfo_exists(): return
|
|
||||||
self._is_dragging = False
|
self._is_dragging = False
|
||||||
self._drag_start_x = None
|
self._drag_start_x_canvas = None
|
||||||
self._drag_start_y = None
|
self._drag_start_y_canvas = None
|
||||||
self.canvas.config(cursor="")
|
self._drag_start_center_lon = None
|
||||||
logger.debug("Mouse button release, panning finished.")
|
self._drag_start_center_lat = None
|
||||||
|
|
||||||
def _on_right_click(self, event: tk.Event):
|
def _on_right_click(self, event: tk.Event):
|
||||||
if not self.canvas.winfo_exists(): return
|
if not self.canvas.winfo_exists(): return
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user