Terrain and elevation
OpenBikeComputer uses one terrain raster for all elevation functions. The source is Copernicus DEM GLO-30. The obc-dem tool converts this source to the OBCT format.
Terrain cells have a separate catalog revision from map cells. The assembler copies selected terrain cells into the terrain region of the .obcm file. The packer and device use the same no_std sampler. Thus, all consumers use the same elevation values.
Data flow
Peak View surface data
The production terrain baker writes a geographic surface index for Peak View. Native heights remain unchanged and are stored once. Coarser height levels and conservative maximum-height bounds let the renderer skip hidden terrain. Baked height and gradient error bounds also let it draw large smooth patches without visiting each small source cell. The extra coarse levels keep those patches' corner reads close together in storage. The data contains no stored viewpoints or images.
Peak View uses the loaded map and the current GPS position. It reads nearby named summits from that map, projects their geographic coordinates, and checks their visibility against the terrain. Each bearing sector keeps its tallest summit and one strong height-and-distance candidate. This prevents nearby lower hills from using both slots before a distant landmark can be checked. Before a GPS fix it waits. The renderer prepares the current field of view first, then fills the rest of the circle in the background, extending a buffer on both sides of the view. Static dots show that background work remains. Turning toward an unfinished view gives that view priority. After the first view appears, completed terrain continues to follow the heading. A light hatch marks pending parts until they are ready. Completed views reuse the panorama in RAM. Movement above 20 m starts another panorama after the current job finishes. Back cancels generation and releases the arena. The vertical scale is chosen once per observer from the catalogue elevation angles. Shallow relief receives up to 3× vertical exaggeration; steep views keep 1.25×. Missing height metadata keeps the ordinary scale. Terrain and labels share the projection, while bearings, elevations, distances and visibility stay geographic. Turning changes neither the scale nor the horizon position. Lighting has a fixed northwest world direction, so turning does not change the shading.
The renderer requests terrain out to 100 km. Missing distant coverage is marked with dashed bearing segments. Missing terrain at the observer or a storage read failure makes the view unavailable. Absent geographic cells are skipped without traversing their individual samples.
At the standard posting and cell size, an indexed cell occupies 3,149,824 bytes instead of 2,097,152 bytes. The assembler enforces a 10% limit on growth of the complete map, including summit data and alignment. It rejects a map that exceeds this limit before writing it. Terrain itself grows about 50.2%, so terrain-heavy sparse selections can exceed the complete-map budget. The limit does not guarantee that every selection can include the surface index.
The normal map bakery writes indexed terrain and named summit records directly. Re-bake all published terrain and geometry cells before publication. Catalog generation rejects mixed native and indexed terrain blocks. Standalone DEM baking produces native terrain; its surface conversion command adds the index without changing native heights.
Distance bands follow the source posting, so a finer source uses its fine cells over a shorter range. Smooth open terrain can merge into large patches. Rough mountain faces require more individual cells. Performance must therefore be checked at varied observer positions on the device. See OBCT section 8 for the byte layout and complete-map size rule.
One sampling truth
The packer samples OBCT tiles to calculate navigation-edge ascent. It also uses them to trace contour lines. The device samples the embedded raster for route heights and altimeter fusion. Route profiles, climb detection, and elevation statistics use these route heights.
The shared obc-elevation crate implements all sampling. The packer does not decode GeoTIFF data. Only obc-dem decodes the source DEM.
OBCT section 5 specifies integer bilinear interpolation. The calculation uses 64-bit integers and half-away-from-zero rounding. Independent implementations must return the same whole-meter height.
The sampler uses half-open cell ownership at seams. It reads a sample from the cell that owns that sample. It clamps the last sample at the outer coverage edge.
Terrain artifacts and map assembly
Published terrain cells use this identity tuple:
dataset_versionposting_log2cell_log2terrain_revision
The tuple does not contain an OBCM schema revision. Thus, a map schema change does not require a new terrain bake. See OBCC section 13 for the catalog contract.
The assembler verifies each selected cell against the catalog. It copies the cells into one OBCT container. The assembler puts this container in the map terrain region. The device reads terrain only from this region.
obc-pack --terrain has a different function. It samples OBCT input for contours and navigation-edge ascent. It does not put that input in its output map.
Navigation coupling
Navigation-edge ascent depends on a terrain revision. The catalog records this revision as network_terrain_revision. The bake guard rejects a network that uses a different terrain revision. This check keeps routing costs and route profiles on the same terrain surface.
Raster layout and resource use
The current published raster uses these values:
| Item | Value |
|---|---|
| Posting | 2^9 microdegrees |
| Terrain cell side | 2^19 microdegrees |
| Samples per cell | 1024 × 1024 |
| Tile size | 16 × 16 samples, 512 bytes |
| Sample type | Little-endian signed 16-bit meters |
NODATA value | -32768 |
| Default tile cache | Four tiles, approximately 2.1 KiB |
The posting and cell size are OBCT header fields. A change to either value requires a terrain bake, not an OBCT version change. See the OBCT specification for all limits and byte layouts.
Routing ascent
Each navigation adjacency stores directional ascent_m. The value is the accumulated ascent along the edge polyline. It is not the elevation difference between the endpoints.
The packer samples each edge at intervals of at most 50 m. It applies the shared 3 m elevation dead band. The reverse adjacency stores the ascent for the reverse direction.
The router uses this cost:
cost = weighted_distance + ascent_m × climb_weight
A descent does not reduce the cost. See Weighting the climb for profile behavior.
Missing terrain
The sampler returns None when terrain is unavailable. It also returns None if a required sample is NODATA. Consumers must not replace None with zero elevation. Zero meters is a valid height.
For packer edge-ascent integration, None pauses the shared 3 m dead band. The next valid sample starts a new segment. Thus, a coverage gap contributes no ascent. Valid samples on each side can still contribute ascent in their segments.
| Function | Behavior without terrain |
|---|---|
| Map rendering | Rendering continues. Baked contour geometry does not require the raster. |
| Routing | Routing continues with the graph's baked ascent values. |
| Imported GPX route | The route keeps its supplied heights. |
| Device-planned route | Before the first valid sample, the route uses zero heights. After that sample, it carries the last valid height across gaps. |
| Detour | The splice interpolates between the seam elevations. |
| Ride recording | The recorder stores the barometer measurement. |
| Current elevation | The UI uses the raw barometric estimate. |
| Time estimate | The model uses zero remaining ascent. |
Coverage and NODATA
A bilinear query needs four sample corners. If one corner is NODATA, the query returns None. The sampler does not estimate a missing corner.
Route elevation parity requires terrain coverage for the complete route. OBCR has no per-point unknown-height value. Points before coverage starts use zero height. The route integrator does not use these placeholder points as an ascent anchor. The packer applies the pause rule at coverage boundaries and NODATA gaps. Device route filling carries the last valid height after coverage starts. A resumed sample can add ascent from that carried height.
Attribution
The data requires this attribution:
produced using Copernicus WorldDEM-30 © DLR e.V. 2010-2014 and © Airbus Defence and Space GmbH 2014-2018 provided under COPERNICUS by the European Union and ESA; all rights reserved
The source code stores this text in COPERNICUS_ATTRIBUTION. The bakery copies it to the catalog terrain block. Consumers read the text from the catalog. A map with derived contour geometry also requires this attribution.
Map data remains © OpenStreetMap contributors.
Implementation
- OBCT contract:
OBCT_Spec.md - OBCT constants:
obct.rs - Reader and sampler:
obc-elevation - DEM converter:
obc-dem - Terrain publisher:
terrain.rs - Map assembly:
terrain.rs - Edge ascent:
nav.rs - Route planning:
nav.rs - Altimeter fusion:
altitude.rs