Skip to content

annotate: max labelling distance follows zfar instead of a hardcoded 100km - #8

Open
thannart wants to merge 5 commits into
dkogan:masterfrom
thannart:annotator-max-marker-dist
Open

thannart wants to merge 5 commits into
dkogan:masterfrom
thannart:annotator-max-marker-dist

Conversation

@thannart

@thannart thannart commented Sep 4, 2026

Copy link
Copy Markdown

MAX_MARKER_DIST was a #define fixed at 100000.0, independent of --zfar. A POI farther than 100km was silently never labelled even if actually rendered and visible (e.g. Mont Blanc, 158km from Lyon). annotate() now takes max_marker_dist_m explicitly; standalone passes zfar. Builds on #4, #5, #6, #7.

thannart and others added 5 commits September 3, 2026 21:48
Lets you account for the fact that the viewer isn't standing at ground
level (e.g. an apartment floor), by reusing horizonator_move() to
reposition the camera at ground_elevation + viewer_height after the
usual auto-selected ground elevation is computed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…correction

The renderer worked entirely in the tangent plane at the viewer, ignoring
Earth's curvature. This is a good approximation at short range, but at
the 100-150km distances relevant for viewing the Alps from Lyon, a
distant peak's apparent elevation angle can be off by more than a
kilometer of apparent height.

Add the standard geodetic "curvature and refraction" correction:
  drop = (1-k) * distance^2 / (2*Rearth)
subtracted from each vertex's apparent height, where k is the
atmospheric refraction coefficient (k=0.13, the Gaussian refraction
coefficient used by udeuschle.de, is the default).

New horizonator_set_curvature() API, and --curvature / --refraction-k
flags on standalone. Off by default, so existing behavior is unchanged
unless --curvature is explicitly requested; this lets the flat-plane and
curved renders be compared directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…n use

The renderer always built a mesh covering the full 360-degree circle of
loaded DEM data, even for a render that only ever looks at a narrow
azimuth wedge (e.g. a fixed 110-degree panorama). Most of that geometry
was never visible and cost triangle-generation/vertex-shader time every
frame for nothing.

horizonator_init() takes 3 new parameters: restrict_mesh_azimuth,
mesh_az_deg0, mesh_az_deg1. When set, only cells within that azimuth
range (plus a 5-degree margin, plus a small radius always meshed near
the viewer where per-cell azimuth changes too fast to test reliably)
are triangulated; the rest of the loaded square is skipped in the index
buffer. Vertex generation, DEM sampling and the shaders are untouched.

standalone (a single fixed-wedge render per invocation) enables this by
default, since the meshed wedge always matches the rendered wedge
exactly -- verified pixel-identical output on 3 different az/height
combinations, 36-44% faster wall-clock render time. Pass
--no-restrict-mesh-azimuth to fall back to the old full-circle mesh.

The interactive horizonator tool and the Python bindings pass
restrict_mesh_azimuth=false, since they let the viewer pan around after
the data is loaded, potentially outside whatever wedge was meshed at
init time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…s the render

horizonator_project() (used by annotator.c to predict where a named POI
should land on screen) computed the apparent elevation from a raw
lat/lon/ele difference, with no Earth-curvature/refraction correction.
When a render was made with horizonator_set_curvature() enabled, the
actual terrain in that render sits lower than this flat-plane
projection predicts -- by over a kilometer of apparent height at
100+km. annotator.c's occlusion/matching search (a small pixel-radius,
range-difference fuzz match) can't bridge that gap, so with
--curvature, no POIs were ever found: every one looked occluded.

horizonator_project() now takes curvature_enabled/refraction_k and
applies the same drop = (1-k)*d^2/(2*Rearth) subtracted from the
apparent height, matching vertex.glsl. annotate() takes and forwards
the same two values, which must match whatever was passed to
horizonator_set_curvature() for the render being annotated.
horizonator_unproject() needs no equivalent change: it derives lat/lon
from the already-rendered (already curvature-corrected, if enabled)
range image, not from an independently-computed real-world height.

Also fixes query-peaks-from-osm.py, which the Overpass API was
rejecting (HTTP 406) or timing out on: switch to https, add an
identifying User-Agent and an explicit query timeout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…100km

MAX_MARKER_DIST was a #define fixed at 100000.0, independent of the
render's own --zfar. Any POI farther than 100km was silently never
labelled, even if it was actually rendered and clearly visible (e.g.
Mont Blanc, 158km from Lyon, with a --zfar of 150km+).

annotate() now takes max_marker_dist_m explicitly; standalone passes
zfar, since there's no point labelling something farther than what was
actually rendered.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant