#!/usr/bin/env python3 """ Sovereign 3D DEM Tile Seeder for Jordan (سيرفر سيادي لتخزين تضاريس الأردن ثلاثية الأبعاد) Downloads Terrarium 3D DEM elevation tiles for the Jordan National Bounding Box and packages them into a sovereign MBTiles SQLite database and/or local tile directory. Bounding Box (Jordan): West: 34.8°, South: 29.1°, East: 39.3°, North: 33.4° Zoom Levels: 0 to 14 (overscaled to z20 by MapLibre GPU) """ import os import sys import math import sqlite3 import argparse import time import urllib.request import urllib.error from concurrent.futures import ThreadPoolExecutor, as_completed # National Jordan Geographic Envelope JORDAN_BBOX = { 'min_lon': 34.8, 'min_lat': 29.1, 'max_lon': 39.3, 'max_lat': 33.4 } DEM_URL_TEMPLATE = "https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png" def deg2num(lat_deg, lon_deg, zoom): lat_rad = math.radians(lat_deg) n = 2.0 ** zoom xtile = int((lon_deg + 180.0) / 360.0 * n) ytile = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n) return (xtile, ytile) def init_mbtiles(db_path, min_zoom, max_zoom): conn = sqlite3.connect(db_path) cur = conn.cursor() cur.execute("PRAGMA synchronous = NORMAL") cur.execute("PRAGMA journal_mode = WAL") cur.execute(""" CREATE TABLE IF NOT EXISTS metadata ( name TEXT PRIMARY KEY, value TEXT ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS tiles ( zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_data BLOB, PRIMARY KEY (zoom_level, tile_column, tile_row) ); """) meta = [ ('name', 'Jordan Sovereign 3D Elevation DEM (Terrarium)'), ('type', 'baselayer'), ('version', '1.0'), ('description', 'High-accuracy Sovereign 3D DEM Terrarium Tiles for the Hashemite Kingdom of Jordan'), ('format', 'png'), ('bounds', f"{JORDAN_BBOX['min_lon']},{JORDAN_BBOX['min_lat']},{JORDAN_BBOX['max_lon']},{JORDAN_BBOX['max_lat']}"), ('minzoom', str(min_zoom)), ('maxzoom', str(max_zoom)), ('attribution', '© Intaleq Sovereign Spatial Engine | Mapzen Terrarium') ] for k, v in meta: cur.execute("INSERT OR REPLACE INTO metadata (name, value) VALUES (?, ?)", (k, v)) conn.commit() return conn def download_tile(z, x, y, retries=3): url = DEM_URL_TEMPLATE.format(z=z, x=x, y=y) req = urllib.request.Request( url, headers={'User-Agent': 'Intaleq-Sovereign-Map-Seeder/1.0'} ) for attempt in range(retries): try: with urllib.request.urlopen(req, timeout=10) as response: if response.status == 200: return (z, x, y, response.read(), None) except Exception as e: if attempt == retries - 1: return (z, x, y, None, str(e)) time.sleep(0.5 * (attempt + 1)) return (z, x, y, None, "Timeout") def main(): parser = argparse.ArgumentParser(description="Jordan Sovereign 3D DEM Tile Seeder") parser.add_argument("--min-zoom", type=int, default=0, help="Minimum zoom level (default: 0)") parser.add_argument("--max-zoom", type=int, default=14, help="Maximum zoom level (default: 14)") parser.add_argument("--output-mbtiles", type=str, default="data/jordan-dem.mbtiles", help="Output MBTiles path") parser.add_argument("--output-dir", type=str, default="", help="Optional output directory for raw {z}/{x}/{y}.png files") parser.add_argument("--workers", type=int, default=16, help="Concurrent worker threads (default: 16)") args = parser.parse_args() os.makedirs(os.path.dirname(os.path.abspath(args.output_mbtiles)), exist_ok=True) if args.output_dir: os.makedirs(args.output_dir, exist_ok=True) print(f"🚀 Initializing Sovereign 3D DEM Tile Seeder for Jordan...") print(f"📍 Geographic Bounding Box: {JORDAN_BBOX}") print(f"🔍 Zoom range: {args.min_zoom} -> {args.max_zoom}") print(f"💾 Target MBTiles: {args.output_mbtiles}") conn = init_mbtiles(args.output_mbtiles, args.min_zoom, args.max_zoom) cursor = conn.cursor() # Pre-calculate tile list tiles_to_download = [] for z in range(args.min_zoom, args.max_zoom + 1): x1, y2 = deg2num(JORDAN_BBOX['min_lat'], JORDAN_BBOX['min_lon'], z) x2, y1 = deg2num(JORDAN_BBOX['max_lat'], JORDAN_BBOX['max_lon'], z) min_x, max_x = min(x1, x2), max(x1, x2) min_y, max_y = min(y1, y2), max(y1, y2) for x in range(min_x, max_x + 1): for y in range(min_y, max_y + 1): # Check if tile already exists in MBTiles # Note: MBTiles uses TMS y-coordinates: tms_y = (2^z - 1) - y tms_y = (1 << z) - 1 - y cursor.execute("SELECT 1 FROM tiles WHERE zoom_level=? AND tile_column=? AND tile_row=?", (z, x, tms_y)) if not cursor.fetchone(): tiles_to_download.append((z, x, y)) total = len(tiles_to_download) print(f"📦 Total new tiles to fetch: {total:,}") if total == 0: print("✅ All tiles are already cached and present in the sovereign database!") conn.close() return downloaded = 0 errors = 0 batch = [] start_time = time.time() with ThreadPoolExecutor(max_workers=args.workers) as executor: futures = {executor.submit(download_tile, z, x, y): (z, x, y) for z, x, y in tiles_to_download} for future in as_completed(futures): z, x, y, data, err = future.result() if data: tms_y = (1 << z) - 1 - y batch.append((z, x, tms_y, data)) downloaded += 1 # If raw dir specified, also save file if args.output_dir: tile_file_dir = os.path.join(args.output_dir, str(z), str(x)) os.makedirs(tile_file_dir, exist_ok=True) with open(os.path.join(tile_file_dir, f"{y}.png"), "wb") as f: f.write(data) else: errors += 1 if len(batch) >= 200: cursor.executemany("INSERT OR REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES (?, ?, ?, ?)", batch) conn.commit() batch.clear() elapsed = time.time() - start_time speed = downloaded / elapsed if elapsed > 0 else 0 pct = (downloaded + errors) / total * 100 print(f"⏳ Progress: {downloaded:,}/{total:,} ({pct:.1f}%) | Speed: {speed:.1f} tiles/s | Errors: {errors}") if batch: cursor.executemany("INSERT OR REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES (?, ?, ?, ?)", batch) conn.commit() conn.close() elapsed = time.time() - start_time print(f"\n🎉 Finished! Downloaded: {downloaded:,} tiles in {elapsed:.1f}s. Errors: {errors}.") print(f"🛡️ Sovereign MBTiles stored at: {args.output_mbtiles}") if __name__ == "__main__": main()