dem_skyline — GEOCAM skyline op

• Data kinds: depth → table

• Call: import fullseye as fs; fs.ledger.dem_skyline(dem, cell_size, observer_rc, eye_height=1.5, az_step_deg=1.0, max_distance=None, earth_curvature=True) (to call the implementation directly, import geocam; geocam.dem_skyline(dem, cell_size, observer_rc, eye_height=1.5, az_step_deg=1.0, max_distance=None, earth_curvature=True); from the registry, opsgeocam.get("dem_skyline"))

Usage

Omnidirectional skyline seen from 1 point of the DEM (horizon elevation per azimuth) → table.

dem_horizon_angle is "all cells × 1 azimuth"; this is "1 point × all azimuths" -- what you need to determine the orientation of a fixed camera is the latter. The line of sight is advanced in each azimuth in steps of cell_size / 2 (elevation by bilinear interpolation), and the maximum of atan((z_j − z_0 − drop(d)) / d) becomes the elevation angle of that azimuth. drop(d) = d² / (2 R_eff) is how much distant mountains sink due to the Earth's curvature and atmospheric refraction (effective radius R / (1 − 0.13)). When the line of sight leaves the DEM it stops there (it also stops at max_distance). Outside the DEM it is assumed that "the plane at the DEM's lowest elevation continues to the horizon", and the lower bound of the elevation angle is set to the horizon dip −sqrt(2 h / R_eff) (h = height of the observer above the lowest elevation) -- so that, by happening to see a low point at the edge of a finite DEM, a "hole" such as −7°, which in reality is invisible because of the Earth's curvature, is not turned into sky (returned in horizon_dip_deg).

Args:

dem: (H, W) elevation [m]. Row 0 is the north edge.

cell_size: [m/cell].

observer_rc: observation point (row, col). float allowed (standing inside a cell).

eye_height: camera height above the ground [m].

az_step_deg: azimuth step [deg].

max_distance: maximum distance of the line of sight [m] (None = up to the edge of the DEM).

earth_curvature: False means a flat Earth.

Returns:

table: azimuth_deg (M,) / elevation_deg (M,) / distance_m (M,) (distance to the point

that determined the elevation angle) / observer_elevation_m / horizon_dip_deg / n. Azimuth is at least 0 and

less than 360, ascending.

Detailed usage guide

• geocam family guide

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

• The canonical algorithm (author, year) and its uses are named in the family usage guide above.

Runnable examples (verified samples that actually call this op)

• poc_public_camera_heading — py -3.11 examples/poc_public_camera_heading.py

Ops the type connects to (they accept table as input)

render_skyline_view · camera_orientation_from_skyline

Same category (skyline)

skyline_extract · render_skyline_view


*Provenance: geocam.py — GEOCAM operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.