frontpage.
newsnewestaskshowjobs

Made with ♥ by @iamnishanth

Open Source @Github

fp.

Open in hackernews

I built a real-time AR plane spotter, here's the math that makes it work

3•ananddhruv29•6h ago
I've been building an Android app that identifies aircraft overhead when you point your phone at the sky. The app fetches live ADS-B data and overlays aircraft labels on the camera feed, but getting the math right took much longer than I expected, so I wrote it all up.

The problem sounds simple, you have a GPS coordinate in the sky and a GPS coordinate in your hand. You want a pixel. But there are four distinct coordinate spaces between those two things, and the transitions between them have sign conventions that fail silently, wrong output with no error.

The pipeline:

  Geodetic (lat, lon, alt)
    ↓  flat-earth approx — valid <100 km, error <2 px at 50 nm range
  ENU — East, North, Up (metres)
    ↓  R⊤ from Android TYPE_ROTATION_VECTOR sensor
  Device frame (dX, dY, dZ)
    ↓  one sign flip: Cz = −dZ
  Camera frame (Cx, Cy, Cz)
    ↓  perspective divide + FOV normalisation
  Screen pixels (Xpx, Ypx)
Why each transition is non-obvious:

Geodetic → ENU. The East component has a cosine factor that most implementations miss: E = Δλ × (π·RE/180) × cos(φ_user). Meridians converge toward the poles, one degree of longitude is fewer metres at latitude 25° than at the equator. Without it, East-West positions look correct near the equator and quietly diverge as latitude increases.

ENU → Device frame. Android's rotation matrix R maps device axes to ENU world axes. To go the other direction you use R⊤. In Android's row-major FloatArray(9), this means column indices, not row indices:

  R  (forward): dX = R[0]·E + R[1]·N + R[2]·U
  R⊤ (inverse): dX = R[0]·E + R[3]·N + R[6]·U
These produce completely different results. Both compile without complaint.

Device → Camera frame. Android's sensor defines +Zd as pointing out of the screen toward your face. The camera convention requires +Cz to point into the scene. So Cz = −dZ, always. This is the only correction needed for portrait mode.

Camera → Screen. After the perspective divide and FOV normalisation, the Y axis flips: Ypx = (1 − NDCy) × H/2. Camera +Cy is up; screen y=0 is at the top. If we miss this, the aircraft above the horizon appears below screen centre.

Real captured values (ATR72, 18,000 ft):

  User:     24.8600°N, 80.9813°E
  Aircraft: 24.9321°N, 81.0353°E

  ENU:  E=6,010 m  N=8,014 m  U=5,486 m
  Bearing 34.2° (NNE),  Elevation 29.5°,  Range 11.1 km

  Camera frame (after R⊤ + sign fix): (729, 4692, 10077)
  Magnitude: 11,140 m ≈ 11,138 m (ENU range) 

  Screen (1080×1997, θH=66°, θV=50°): (600 px, 1 px)
Phone azimuth 33.0°, aircraft bearing 34.2° → 1.2° right of centre. Phone pitched −4.3°, elevation 29.5° → net 33.8° up, just inside the top edge of the frustum. Physically consistent throughout.

Happy to answer questions about any stage of the pipeline or about anything else, whatever is interesting to anyone.

Comments

surajguptayc•37m ago
cool

Ask HN: How did you land your first projects as a solo engineer/consultant?

118•modelcroissant•5h ago•58 comments

I built a real-time AR plane spotter, here's the math that makes it work

3•ananddhruv29•6h ago•1 comments

Ask HN: Who is using OpenClaw?

335•misterchocolat•3d ago•384 comments

Ask HN: Building a solo business is impossible?

56•fnoef•2d ago•80 comments

Tell HN: Fiverr left customer files public and searchable

824•morpheuskafka•4d ago•231 comments

Why don't we just ask AI to write assembler?

8•canterburry•1d ago•12 comments

Ask HN: Anyone know of that "levels of AI programming" blog post?

5•tuvix•20h ago•5 comments

Ask HN: Does magic link authentication use HTML canvassing?

2•trinsic2•21h ago•5 comments

Tell HN: 48 absurd web projects – one every month

78•absurdwebsite•3d ago•26 comments

Ask HN: ChatAi web-based session notation?

2•xtiansimon•23h ago•0 comments

Ask HN: Getting depressed day by day, how to cope?

23•throwaw12•2d ago•19 comments

Ask HN: How did you get your first users with zero audience?

16•arikusi•2d ago•12 comments

Ask HN: How do you maintain flow when vibe coding?

31•fny•2d ago•29 comments

Ask HN: How do you find motivation to do stuff?

25•RockstarSprain•3d ago•25 comments

Aliens.gov Resolves – To a WordPress "Site Not Found" Error

13•ascarola•2d ago•6 comments

Do I Stop Learning Coding? DSA?

6•s_u_d_o•1d ago•15 comments

Tell HN: Security Incident at Porter (YC S20)

6•leetrout•1d ago•0 comments

Ask HN: How do you search the web programmatically these days?

6•coreyp_1•1d ago•7 comments

Ask HN: How are you using LLMs in production?

13•Anon84•3d ago•12 comments

Ask HN: Teaching life skills through games, am I crazy?

2•shivaniShimpi_•1d ago•2 comments

Durable Object alarm loop: $34k in 8 days, zero users, no platform warning

30•thewillmoss•3d ago•3 comments

Advice for tracking down a listening device?

9•comrade1234•3d ago•5 comments

Ask HN: Who is your favourite Entrepreneur/Visionary?

13•wasimsk•3d ago•32 comments

Tell HN: Anthropic no longer allows you to fix to specific model version

27•baobabKoodaa•4d ago•2 comments

Ask HN: Is Claude Getting Worse?

9•sahli•4d ago•19 comments

Ask HN: How are you actively keeping your thinking sharp while using LLMs daily?

16•smonk108•3d ago•10 comments

Ask HN: How can I support the AI resistance movement financially?

12•roschdal•18h ago•8 comments

Ask HN: How to highlight talent from untraditional backgrounds?

6•etherus•3d ago•5 comments

Opus 4.7 is horrible at writing

18•limalabs•2d ago•25 comments

GitHub gave webhook secrets away in webhook call

12•time4tea•4d ago•1 comments