mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
- City engine: Esri ground, OSM buildings that rise with the scan, road ribbons carrying modelled traffic coloured by congestion, NYC DOT cameras, real ADS-B, MBTA GTFS lines + realtime vehicles, LAX runways with approach strobes, Fort Bragg restricted volumes, Everest terrain with contours. - Indexing keeps accelerating into a 260-capture global sweep while the planet whips a full turn. - The eye opens: aperture blades, sensor array waking, optics calibration, radar sweep, orbiting coordinate ring. - Camera wall with YOLOv8n detections and a city-pulse trace. - Ends on GOD'S EYE VIEW / OMNISCIENCE. - audio/sfx.py: sound design only, built to sit under a music track. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KqP857pippaUs6konSDfe8
73 lines
4.1 KiB
Python
73 lines
4.1 KiB
Python
"""Poll live ADS-B (adsb.lol, fallback adsb.fi) around each scene 3x, 20 s apart.
|
|
Writes city/<slug>/air.json with latest sample per aircraft + short track history."""
|
|
import json, os, sys, time, requests
|
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
from common import SCENES, enu
|
|
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
|
RAD = {'nyc': 25, 'lax': 25, 'bragg': 25, 'boston': 20}
|
|
HELI_TYPES = {'EC35','EC30','EC45','EC55','EC20','EC25','EC75','EC13','EC40','AS50','AS55','AS65','AS32','AS3B','H125','H130','H135','H145','H160','H175','B06','B06T','B407','B412','B427','B429','B430','B47G','B505','B212','B222','B230','B105','BK17','R22','R44','R66','S76','S92','S61','S64','S70','H60','UH60','MH60','HH60','H47','CH47','H53','A109','A119','A139','A169','A189','AW09','MI8','MI17','UH1','UH1Y','AH1','AH64','H64','V22','MV22','CABR','G2CA','EN28','EN48','H269','H500','MD52','MD60','NH90','LYNX','PUMA','GAZL','EH10','H1','B505'}
|
|
H = {'User-Agent': 'gods-eye-view-intro/1.0 (film research)'}
|
|
def fetch(slug):
|
|
lat, lon, _ = SCENES[slug]; nm = RAD[slug]
|
|
for url, key in ((f'https://api.adsb.lol/v2/point/{lat}/{lon}/{nm}', 'ac'),
|
|
(f'https://opendata.adsb.fi/api/v2/lat/{lat}/lon/{lon}/dist/{nm}', 'aircraft')):
|
|
try:
|
|
r = requests.get(url, headers=H, timeout=20); r.raise_for_status(); j = r.json()
|
|
ac = j.get('ac') or j.get('aircraft') or []
|
|
now = j.get('now') or time.time() * 1000
|
|
return url, now / 1000 if now > 1e11 else now, ac
|
|
except Exception as e:
|
|
print(slug, 'fail', url, e, file=sys.stderr)
|
|
return None, time.time(), []
|
|
def num(v):
|
|
try: return float(v)
|
|
except Exception: return None
|
|
def conv(slug, a):
|
|
lat, lon = num(a.get('lat')), num(a.get('lon'))
|
|
if lat is None or lon is None:
|
|
lp = a.get('lastPosition') or {}
|
|
lat, lon = num(lp.get('lat')), num(lp.get('lon'))
|
|
if lat is None: return None
|
|
x, y = enu(slug, lat, lon)
|
|
ab = a.get('alt_baro')
|
|
if ab == 'ground': alt = 0.0
|
|
else:
|
|
v = num(ab)
|
|
if v is None: v = num(a.get('alt_geom'))
|
|
alt = round(v * 0.3048, 1) if v is not None else None
|
|
trk = num(a.get('track')); trk = num(a.get('true_heading')) if trk is None else trk
|
|
gs = num(a.get('gs')); gs = round(gs * 0.514444, 1) if gs is not None else None
|
|
vr = num(a.get('baro_rate')); vr = num(a.get('geom_rate')) if vr is None else vr
|
|
vr = round(vr * 0.00508, 2) if vr is not None else None
|
|
return [x, y, alt, trk, gs, vr, (a.get('flight') or '').strip(), a.get('t') or '', a.get('category') or '']
|
|
def main():
|
|
polls = {s: [] for s in SCENES}
|
|
for i in range(3):
|
|
t0 = time.time()
|
|
for s in SCENES:
|
|
url, t, ac = fetch(s); polls[s].append((url, t, ac)); print(i, s, len(ac), url, flush=True)
|
|
if i < 2: time.sleep(max(0, 20 - (time.time() - t0)))
|
|
summary = {}
|
|
for s in SCENES:
|
|
latest, tracks, src = {}, {}, set()
|
|
tlast = 0
|
|
for url, t, ac in polls[s]:
|
|
if url: src.add(url.split('/')[2])
|
|
tlast = max(tlast, t)
|
|
for a in ac:
|
|
hx = a.get('hex'); row = conv(s, a)
|
|
if not hx or row is None: continue
|
|
if (num(a.get('seen_pos')) or 0) > 60: continue
|
|
latest[hx] = row
|
|
tr = tracks.setdefault(hx, [])
|
|
p = [row[0], row[1], row[2]]
|
|
if not tr or tr[-1][:2] != p[:2]: tr.append(p)
|
|
heli = [h for h, r in latest.items() if r[8] == 'A7' or r[7] in HELI_TYPES]
|
|
out = {'t': int(tlast), 'source': sorted(src), 'radius_nm': RAD[s], 'hex': list(latest.keys()),
|
|
'a': list(latest.values()), 'tracks': {h: v for h, v in tracks.items() if len(v) > 1}}
|
|
json.dump(out, open(os.path.join(ROOT, 'city', s, 'air.json'), 'w'), separators=(',', ':'))
|
|
summary[s] = {'aircraft': len(latest), 'with_track': len(out['tracks']), 'heli': len(heli),
|
|
'heli_list': [[latest[h][6], latest[h][7], latest[h][8], latest[h][2]] for h in heli]}
|
|
print(json.dumps(summary, indent=1))
|
|
if __name__ == '__main__': main()
|