Skip to main content

Module terrain

Module terrain 

Source
Expand description

One-shot heightmap → quantized-mesh (.terrain) encoding.

This module ties together the three crates that otherwise have to be wired up by hand:

  1. martini generates an adaptive RTIN mesh from the elevation grid.
  2. The mesh’s (u, v, height) are quantised to the 0..=32767 range.
  3. quantized_mesh encodes the header, vertices, edge indices and optional extensions into the quantized-mesh-1.0 byte stream.

The fiddly bits it handles for you:

  • Re-sampling each mesh vertex’s height (martini discards heights once the error pyramid is built, so the transform has to recover the grid coordinate from (u, v) and read the DEM again).
  • Computing the encoded height range from the mesh vertices (what is actually stored), not the full grid.
  • Streaming the mesh vertices through QuantizedMeshHeader::from_bounds_with_vertices_iter for a tight horizon-occlusion point.
  • Vertex normals via the NormalMode of your choice.
  • Folding the ellipsoid curvature_bulge into the error pyramid so nearly-flat tiles keep enough triangles to track the globe at low zoom (the bulge feeds error estimation only, never the emitted heights).

§Grid orientation

elevations (and the get_height closure’s y) are row-major, north → south: row 0 is the northern edge, row grid_size - 1 the southern edge. This matches crate::normals::BufferedElevations, so a buffered grid can be reused directly for NormalMode::BufferedGradient.

§Seamless tiling — the caller supplies the halo

These functions encode one tile in isolation; they never fetch neighbouring tiles. For gap-free, seam-free output the caller must widen the input to overlap the neighbours — fetch the halo cells along with the tile and stitch them in before calling:

  • Geometry seam. martini needs a 2^n + 1 grid, so an N-post DEM tile needs one extra post on its east and south edges. That +1 post is the neighbour tile’s first post for the shared edge — read it from the neighbour, don’t edge-replicate, or adjacent tiles won’t agree on the boundary and the globe cracks along tile seams.
  • Normal seam. NormalMode::BufferedGradient needs a buffer-cell halo of neighbour samples on every side (see BufferedElevations). Edge vertices read their ±1 neighbours out of that halo, so the same physical edge gets identical normals from either tile and lighting stays continuous.

Gathering that neighbour data (over HTTP, from disk, from a cache, …) is deliberately left to the caller — hence this module takes an already-assembled grid rather than fetching tiles itself, which also keeps it free of any async/runtime assumptions.

§Example

use terrain_codec::quantized_mesh::TileBounds;
use terrain_codec::terrain::{encode_terrain, TerrainOptions};

let grid_size = 65; // 2^6 + 1
let elevations = vec![0.0f32; (grid_size * grid_size) as usize];
let bounds = TileBounds::new(139.0, 35.0, 139.01, 35.01);

let terrain: Vec<u8> = encode_terrain(
    &elevations,
    grid_size,
    &bounds,
    &TerrainOptions {
        max_error: 1.0,
        ..Default::default()
    },
);
assert!(terrain.starts_with(&[0x1f, 0x8b])); // gzip magic (default level 6)

Structs§

TerrainOptions
Options controlling encode_terrain and the other encode functions in this module.

Enums§

NormalMode
How (and whether) per-vertex normals are computed for the oct-encoded vertex-normals extension.

Functions§

curvature_bulge
Radial deviation (metres) of the WGS84 ellipsoid surface above the flat bilinear interpolation of the tile’s four corners, evaluated at grid cell (x, y). The encode functions in this module always add this to the height field that drives martini’s error pyramid (never to the stored heights), so nearly-flat tiles still tessellate enough to track the globe’s curvature instead of collapsing to a flat quad that cuts under the ellipsoid at low zoom. Exposed so callers can reason about / reproduce the subdivision.
encode_terrain
Encode a flat row-major (north → south) f32 elevation grid to a quantized-mesh .terrain byte vector.
encode_terrain_from_fn
Encode a heightmap to a quantized-mesh .terrain byte vector, sampling elevations through a closure.
encode_terrain_from_fn_to
Like encode_terrain_from_fn, but streams the encoded bytes to a writer instead of allocating a Vec.
encode_terrain_to
Like encode_terrain, but streams the encoded bytes to a writer.