#!/usr/bin/env python3 import argparse, sqlite3, sys def fetch_one(cur, sql, args=()): row = cur.execute(sql, args).fetchone() return row[0] if row else None def main(): ap = argparse.ArgumentParser( description="Normalizza bounds (W,S,E,N) e imposta center/minzoom/maxzoom in un MBTiles." ) ap.add_argument("mbtiles", help="Percorso al file .mbtiles") ap.add_argument("--zoom", type=int, default=None, help="Zoom del center da impostare (default: usa center esistente o media min/max dalle tile)") ap.add_argument("--minzoom", type=int, default=None, help="Forza minzoom (default: dai livelli in 'tiles')") ap.add_argument("--maxzoom", type=int, default=None, help="Forza maxzoom (default: dai livelli in 'tiles')") args = ap.parse_args() conn = sqlite3.connect(args.mbtiles) cur = conn.cursor() # --- 1) leggi bounds correnti b_raw = fetch_one(cur, "SELECT value FROM metadata WHERE name='bounds';") if not b_raw: sys.exit("ERRORE: 'bounds' mancante nella tabella metadata.") try: x1, y1, x2, y2 = [float(t) for t in b_raw.split(",")] except Exception: sys.exit(f"ERRORE: bounds non parseable: {b_raw}") # normalizza ordine W,S,E,N (min/max su lon e lat) W, E = sorted((x1, x2)) S, N = sorted((y1, y2)) bounds = f"{W:.6f},{S:.6f},{E:.6f},{N:.6f}" # --- 2) min/max zoom: da tiles salvo override minz = fetch_one(cur, "SELECT MIN(zoom_level) FROM tiles;") maxz = fetch_one(cur, "SELECT MAX(zoom_level) FROM tiles;") # fallback se tiles non esiste o vuota try: minz = int(minz) if minz is not None else None maxz = int(maxz) if maxz is not None else None except Exception: minz = maxz = None if args.minzoom is not None: minz = int(args.minzoom) if args.maxzoom is not None: maxz = int(args.maxzoom) # --- 3) center: lon/lat dal bbox; zoom = argomento > zoom esistente > media min/max > 0 center_existing = fetch_one(cur, "SELECT value FROM metadata WHERE name='center';") center_z_existing = None if center_existing: parts = [p.strip() for p in center_existing.split(",")] if len(parts) >= 3 and parts[2] != "": center_z_existing = parts[2] if args.zoom is not None: z = int(args.zoom) elif center_z_existing is not None: try: z = int(center_z_existing) except Exception: z = None else: z = int((minz + maxz) // 2) if (minz is not None and maxz is not None) else 0 ctr_lon = (W + E) / 2.0 ctr_lat = (S + N) / 2.0 center = f"{ctr_lon:.6f},{ctr_lat:.6f},{z}" # --- 4) scrittura: crea metadata se manca, REPLACE dei valori cur.execute("CREATE TABLE IF NOT EXISTS metadata (name TEXT PRIMARY KEY, value TEXT)") cur.execute("REPLACE INTO metadata(name,value) VALUES(?,?)", ("bounds", bounds)) cur.execute("REPLACE INTO metadata(name,value) VALUES(?,?)", ("center", center)) if minz is not None: cur.execute("REPLACE INTO metadata(name,value) VALUES(?,?)", ("minzoom", str(minz))) if maxz is not None: cur.execute("REPLACE INTO metadata(name,value) VALUES(?,?)", ("maxzoom", str(maxz))) conn.commit() # --- 5) stampa riepilogo print("OK") for k in ("bounds","center","minzoom","maxzoom"): v = fetch_one(cur, "SELECT value FROM metadata WHERE name=?", (k,)) print(f"{k} = {v}") zminmax = cur.execute("SELECT MIN(zoom_level), MAX(zoom_level) FROM tiles;").fetchone() if zminmax and all(v is not None for v in zminmax): print(f"zoom (tiles) = {zminmax[0]}..{zminmax[1]}") conn.close() if __name__ == "__main__": main()