DTED terrain loading and elevation lookup.
Summary
Types
Horizontal datum a DTED tile's DSI record states: :wgs84, :wgs72,
:unstated for a blank or zero-filled field (read as WGS84), or
{:other, text} with the field as read.
Why a terrain lookup has no height although the query is valid.
Why a DTED tile could not be read or queried, one tag per core
DtedTileError variant with its fields. {:null_posting, fields} is a
posting holding the DTED null value, an unknown elevation rather than a
height. The UHL metadata refusals (:coordinate_out_of_range,
:wrong_hemisphere, :origin_not_whole_degree, :interval_count_mismatch,
:profile_longitude_count_mismatch, :unsupported_partial_profile) name the
metadata the reader places postings by.
Functions
Open a DTED terrain directory.
Open a DTED terrain directory or raise.
Look up terrain height at {longitude_deg, latitude_deg}.
Look up one ORTHOMETRIC terrain height in meters or raise.
Look up a batch of terrain heights.
Look up a batch of ORTHOMETRIC terrain heights in meters or raise.
Alias for height/4, matching the Rust/Python/WASM height_m name.
Look up terrain height with explicit lookup options.
Load one DTED tile from disk.
Load one DTED tile or raise.
Read the nearest posting elevation from a loaded DTED tile.
Read one ORTHOMETRIC tile posting height in meters or raise.
Return the horizontal datum a loaded DTED tile's DSI record states.
Types
@type horizontal_datum() :: :wgs84 | :wgs72 | :unstated | {:other, String.t()}
Horizontal datum a DTED tile's DSI record states: :wgs84, :wgs72,
:unstated for a blank or zero-filled field (read as WGS84), or
{:other, text} with the field as read.
@type interpolation() :: :bilinear | :nearest_posting
@type lookup_error() :: {:unknown_terrain_elevation, %{ lat_index: integer(), lon_index: integer(), latitude_posting: non_neg_integer(), longitude_posting: non_neg_integer() }} | {:non_wgs84_terrain_tile, %{lat_index: integer(), lon_index: integer(), datum: horizontal_datum()}} | {:missing_terrain_tile, %{lat_index: integer(), lon_index: integer()}} | {:terrain_tile, %{lat_index: integer(), lon_index: integer(), error: tile_error()}} | {:terrain_tile_origin, %{ path: String.t(), lat_index: integer(), lon_index: integer(), origin_latitude: integer(), origin_longitude: integer() }} | {:invalid_input, %{message: String.t()}} | {:parse, String.t()}
Why a terrain lookup has no height although the query is valid.
{:unknown_terrain_elevation, fields}- the lookup gives nonzero weight to a posting holding the DTED null value (MIL-PRF-89020B 3.11.3.1), and no neighbouring tile knows the height at the same place.fieldsnames the tile (lat_index,lon_index) and the zero-based posting (latitude_posting,longitude_posting).{:non_wgs84_terrain_tile, fields}- the tile states a horizontal datum other than WGS84 (datum), so it does not answer a WGS84 query; no datum transformation is performed.{:missing_terrain_tile, fields}- the store holds no tile for the cell.{:parse, message}- a DTED tile parse failure not represented by the typed:terrain_tileor:terrain_tile_origincases below.{:terrain_tile, fields}- a stored DTED tile could not be read;fieldsretains its indices and complete typed:errorreason.{:terrain_tile_origin, fields}- a tile's parsed origin disagrees with its indexed origin;fieldsretains the path and both tile identities.{:invalid_input, fields}- a coordinate or other lookup input was refused;fields.messageretains the core reason.
@type lookup_options() :: keyword() | Sidereon.Terrain.DtedLookupOptions.t()
@type tile_error() :: {:io, %{path: String.t(), message: String.t()}} | {:too_short, %{path: String.t()}} | {:missing_uhl1, %{path: String.t()}} | {:invalid_encoding, String.t()} | {:invalid_field, String.t()} | {:invalid_dimensions, %{ path: String.t(), lon_count: non_neg_integer(), lat_count: non_neg_integer() }} | {:truncated, %{path: String.t(), actual: non_neg_integer(), expected: non_neg_integer()}} | {:outside, %{ longitude: float(), latitude: float(), origin_longitude: float(), origin_latitude: float() }} | {:posting_index_out_of_bounds, %{longitude_index: non_neg_integer(), latitude_index: non_neg_integer()}} | {:missing_data_sentinel, %{longitude_index: non_neg_integer()}} | {:checksum, %{longitude_index: non_neg_integer(), checksum: integer(), sum: integer()}} | :empty_coordinate | {:invalid_hemisphere, %{hemisphere: String.t()}} | {:negative_posting_index, %{index: integer()}} | {:coordinate_out_of_range, %{field: String.t(), text: String.t()}} | {:wrong_hemisphere, %{field: String.t(), hemisphere: String.t(), expected: String.t()}} | {:origin_not_whole_degree, %{field: String.t(), text: String.t()}} | {:interval_count_mismatch, %{ field: String.t(), interval_tenths_arcsec: non_neg_integer(), count: non_neg_integer() }} | {:profile_longitude_count_mismatch, %{longitude_index: non_neg_integer(), declared: integer()}} | {:unsupported_partial_profile, %{longitude_index: non_neg_integer(), first_latitude_index: integer()}} | {:null_posting, %{longitude_index: non_neg_integer(), latitude_index: non_neg_integer()}} | {:other, String.t()}
Why a DTED tile could not be read or queried, one tag per core
DtedTileError variant with its fields. {:null_posting, fields} is a
posting holding the DTED null value, an unknown elevation rather than a
height. The UHL metadata refusals (:coordinate_out_of_range,
:wrong_hemisphere, :origin_not_whole_degree, :interval_count_mismatch,
:profile_longitude_count_mismatch, :unsupported_partial_profile) name the
metadata the reader places postings by.
Functions
@spec dted(String.t()) :: {:ok, Sidereon.Terrain.Dted.t()} | {:error, term()}
Open a DTED terrain directory.
The returned handle loads tiles lazily as lookups request them.
Open a DTED terrain directory or raise.
@spec height(Sidereon.Terrain.Dted.t(), number(), number(), lookup_options()) :: {:ok, float()} | {:error, lookup_error() | atom() | Sidereon.argument_error()}
Look up terrain height at {longitude_deg, latitude_deg}.
Returns {:ok, height_m} in meters above the DTED ORTHOMETRIC vertical datum,
or {:error, reason}. Points outside cached DTED coverage return 0.0 from
the core terrain model. Longitude is first by design.
A lookup that gives nonzero weight to a null posting returns
{:error, {:unknown_terrain_elevation, fields}} unless a neighbouring tile
knows the height at the same place, and a tile whose DSI names a horizontal
datum other than WGS84 returns {:error, {:non_wgs84_terrain_tile, fields}};
see lookup_error/0. A query the lookup refuses, such as a non-finite
coordinate, returns {:error, {:invalid_input, fields}} with the core reason
in fields.message.
Look up one ORTHOMETRIC terrain height in meters or raise.
@spec height_batch( Sidereon.Terrain.Dted.t(), [{number(), number()}], lookup_options() ) :: [ok: float(), error: lookup_error() | atom()] | {:error, term()}
Look up a batch of terrain heights.
points is a list of {longitude_deg, latitude_deg} pairs. The returned list
has one {:ok, height_m} or {:error, reason} entry per input, preserving
order, with the reasons height/4 returns. Heights are meters above the DTED
ORTHOMETRIC vertical datum.
Look up a batch of ORTHOMETRIC terrain heights in meters or raise.
@spec height_m(Sidereon.Terrain.Dted.t(), number(), number(), lookup_options()) :: {:ok, float()} | {:error, lookup_error() | atom() | Sidereon.argument_error()}
Alias for height/4, matching the Rust/Python/WASM height_m name.
@spec height_m_with_options( Sidereon.Terrain.Dted.t(), number(), number(), lookup_options() ) :: {:ok, float()} | {:error, lookup_error() | atom() | Sidereon.argument_error()}
Look up terrain height with explicit lookup options.
@spec load_tile(String.t()) :: {:ok, Sidereon.Terrain.DtedTile.t()} | {:error, tile_error() | term()}
Load one DTED tile from disk.
Returns {:ok, %DtedTile{}} or {:error, reason} with a tile_error/0.
A tile is checked against the metadata the reader places postings by: UHL
origins must be whole degrees inside their axis with that axis's hemisphere
letters, a stated UHL data interval must span one degree over the posting
count, and each data record must declare the longitude count of its position
and latitude count zero. A tile on any horizontal datum loads; see
tile_horizontal_datum/1.
Load one DTED tile or raise.
@spec tile_elevation(Sidereon.Terrain.DtedTile.t(), number(), number()) :: {:ok, integer()} | {:error, tile_error() | Sidereon.argument_error()}
Read the nearest posting elevation from a loaded DTED tile.
Returns an integer height in meters above the DTED ORTHOMETRIC vertical datum.
Longitude is first. A posting holding the DTED null value is an unknown
elevation, {:error, {:null_posting, %{longitude_index: i, latitude_index: j}}};
a point outside the tile is {:error, {:outside, fields}}.
Read one ORTHOMETRIC tile posting height in meters or raise.
@spec tile_horizontal_datum(Sidereon.Terrain.DtedTile.t()) :: horizontal_datum()
Return the horizontal datum a loaded DTED tile's DSI record states.
DtedTerrain lookups answer only from a tile whose datum is :wgs84 or
:unstated, since queries are WGS84 positions.