#!/usr/bin/env python3 """Gera plugin/contents/ui/milkyway.jpg a partir do mapa all-sky do Gaia. Fonte: "Gaia's sky in colour" (ESA/Gaia/DPAC, CC BY-SA 3.0 IGO), 8000x4000, projeção HAMMER em coordenadas galácticas (elipse, centro l=0/b=0, l crescendo para a esquerda, b=+90 no topo). Este script reprojeta para plate carrée (mesma convenção de l/b) e reduz para textura leve. O dancer.html amostra a textura por pixel via (l, b) reais — a banda é a Via Láctea fotografada de verdade, projetada em tempo real. Requer Pillow e numpy. Uso: python3 tools/build_skymap.py """ import io import math import urllib.request from pathlib import Path import numpy as np from PIL import Image URL = ("https://upload.wikimedia.org/wikipedia/commons/e/ea/" "Gaia%E2%80%99s_sky_in_colour_ESA393127.png") CACHE = Path.home() / ".cache/skeledance/gaia_allsky.png" OUT = Path(__file__).resolve().parent.parent / "plugin/contents/ui/milkyway.jpg" SIZE = (3072, 1536) # textura final (plate carrée 2:1) OVERSAMPLE = 2 # reprojeta a 2x e reduz com LANCZOS (anti-aliasing) QUALITY = 85 def fetch() -> bytes: if CACHE.exists(): print(f"Usando cache {CACHE}") return CACHE.read_bytes() print(f"Baixando {URL} ...") req = urllib.request.Request(URL, headers={"User-Agent": "skeledance-build/1.0"}) raw = urllib.request.urlopen(req, timeout=180).read() CACHE.parent.mkdir(parents=True, exist_ok=True) CACHE.write_bytes(raw) print(f" {len(raw) / 1e6:.1f} MB (cacheado)") return raw def main(): Image.MAX_IMAGE_PIXELS = None src = np.asarray(Image.open(io.BytesIO(fetch())).convert("RGB")) sh, sw = src.shape[:2] tw, th = SIZE[0] * OVERSAMPLE, SIZE[1] * OVERSAMPLE # Grade de saída plate carrée: l = 180 -> -180 (esq -> dir), b = 90 -> -90 l = np.deg2rad(180 - (np.arange(tw) + 0.5) * 360 / tw) b = np.deg2rad(90 - (np.arange(th) + 0.5) * 180 / th) L, B = np.meshgrid(l, b) # Projeção Hammer direta -> posição na imagem-fonte denom = np.sqrt(1 + np.cos(B) * np.cos(L / 2)) x = 2 * math.sqrt(2) * np.cos(B) * np.sin(L / 2) / denom # + = esquerda y = math.sqrt(2) * np.sin(B) / denom # + = cima sx = np.clip(((1 - x / (2 * math.sqrt(2))) * sw / 2).astype(int), 0, sw - 1) sy = np.clip(((1 - y / math.sqrt(2)) * sh / 2).astype(int), 0, sh - 1) out = Image.fromarray(src[sy, sx]) out = out.resize(SIZE, Image.LANCZOS) out.save(OUT, "JPEG", quality=QUALITY, optimize=True) print(f"{OUT} ({OUT.stat().st_size / 1024:.0f} KB, {SIZE[0]}x{SIZE[1]})") if __name__ == "__main__": main()