Terrain

Choose the scenery and location in your Python schematic. Prepare ground heights from the same terrain when your simulation needs them.

Scenery

ModeterrainDisplay
LegacyNoneThe existing GLB or world mesh defined in your schematic.
Aerialel.Terrain.aerial()Streamed terrain with aerial images.
Photo 3Del.Terrain()Streamed photogrammetry, including buildings where covered.

The editor streams aerial terrain and Photo 3D through Bevy-Cesium. Local models are loaded by the schematic, as in RC-jet's Mojave terrain.

Startup and outages

When elodin editor launches a simulation with streamed terrain, the simulation stays at t=0 until the initial terrain is ready. Loading has no interactive deadline. If Cesium reports an error, the editor disables streamed terrain, restores the schematic's fallback scenery, and starts the simulation. Reload the schematic to retry.

Live connections are never paused. Automated fixed-view captures remain strict: ELODIN_CESIUM_CAPTURE_TIMEOUT bounds terrain loading, and an error or timeout exits without writing a terrain screenshot.

import elodin as el
import elodin.ui as ui

location = ui.coordinate(
    frame="ECEF",
    lat=28.60839, lon=-80.60433,
    alt=-7.063,
)
terrain = el.Terrain()

scene = ui.schematic(
    ui.viewport(name="Flight"),
    coordinate=location,
    terrain=terrain,
)
world = el.World()
world.schematic(scene)

Latitude and longitude are in degrees; altitude is in meters above the WGS84 ellipsoid.

Terrain Heights

Prepare a grid from the selected aerial terrain or Photo 3D before running the simulation:

import jax.numpy as jnp
from elodin.geodesy import geodetic_to_ecef

location = geodetic_to_ecef(
    jnp.deg2rad(28.485738),
    jnp.deg2rad(-80.542948),
    0.0,
)
heights = terrain.heightmap(
    location, dimensions=(200.0, 200.0), spacing=10.0,
)

Dimensions and spacing are in meters. The grid is cached and reused on later runs. No editor is needed.

During the simulation:

sample = heights.sample(position_ecef)
# sample.height_m, sample.normal_ecef, sample.valid

Use sample.height_m and sample.normal_ecef in your ground-contact model, after checking sample.valid. Heights are above the WGS84 ellipsoid; normals are in ECEF. Queries work inside JAX systems.

See API Reference for parameters and return values.

Caching

The native editor and height preparation use a local terrain cache automatically. Available tiles are reused; missing or expired data is fetched and cached as you explore new areas. Cache misses produce a terminal warning and loading continues. Provider cache rules apply to terrain and imagery responses.

Prepared height grids are also saved and reused on subsequent runs. Use offline=True when preparing heights only if the grid must already exist and network access is not allowed.

Tiles are stored in $XDG_CACHE_HOME/bevy-cesium/terrain, or ~/.cache/bevy-cesium/terrain. Height grids are stored in $XDG_CACHE_HOME/elodin/terrain-heights, or ~/.cache/elodin/terrain-heights.

Run Falcon 9

elodin editor examples/falcon9/main.py

Falcon 9 flies from LC-39A to Landing Zone 1 at Cape Canaveral. See its README for the simulation and reference flights.

In examples/falcon9/constants.py, set TERRAIN_MODE to "legacy", "aerial" or "photo3d". This selects both the scenery and the matching launch and landing ground heights. "legacy" uses Falcon 9's original globe. Photo 3D is the default.

API Reference

class elodin.Terrain

Terrain(asset_id=2275207)

ParameterDefaultDescription
asset_id2275207Positive signed 64-bit ion asset ID. The default is Google Photorealistic 3D Tiles; 1 selects Cesium World Terrain with Bing aerial imagery in the editor.

Constructing a Terrain performs no network or disk access.

  • Terrain.aerial() → Terrain

    Select Cesium World Terrain with aerial imagery. Heights come from Cesium World Terrain; imagery does not change the surface used for height queries.

  • heightmap(center_ecef, dimensions, spacing, *, cache_dir=None, offline=False, timeout=600) → TerrainHeightmap

    Prepare a grid from this terrain before running the simulation.

    ParameterDefaultDescription
    center_ecefRequiredThree-element WGS84 ECEF position, in meters.
    dimensionsRequired(east_west, north_south) coverage in meters; both lengths must be positive.
    spacingRequiredMaximum sample spacing in meters at the grid center; must be positive.
    cache_dirNoneDirectory for saved height grids. Defaults to $XDG_CACHE_HOME/elodin/terrain-heights, or ~/.cache/elodin/terrain-heights. Accepts a string or Path.
    offlineFalseRequire an existing cached grid; raise FileNotFoundError on a cache miss.
    timeout600Integer seconds per native batch, from 1 to 3600. Failed preparation is retried up to twice.

    The grid includes both edges and contains at least two samples along each axis. Coverage must not cross a pole or the antimeridian. Grids are limited to 25 million samples. An existing cached grid is reused; preparation needs the Elodin CLI on a cache miss. The editor does not need to be open.

    elodin.terrain_heightmap(center_ecef, dimensions, spacing, *, asset_id=2275207, cache_dir=None, offline=False, timeout=600) provides the same operation with an explicit asset ID.

class elodin.TerrainHeightmap

  • TerrainHeightmap.load(path) → TerrainHeightmap

    Load a saved JSON grid without network access. path accepts a string or Path.

  • TerrainHeightmap(data) → TerrainHeightmap

    Construct from a decoded grid dictionary. Required fields are version=1, ellipsoid="WGS84", asset_id, bounds_degrees=[west, south, east, north], rows, columns, and heights_m in row-major order from south to north. Heights must be finite, with rows * columns values.

  • sample(position_ecef) → TerrainSample

    Query a three-element ECEF position in meters. Compatible with jax.jit and jax.vmap; performs no I/O.

  • sample_geodetic(latitude, longitude) → TerrainSample

    Query geodetic latitude and longitude in radians.

Queries interpolate heights bilinearly. Outside coverage, values are clamped to the grid boundary and valid is false. Invalid input positions also return valid=False; check it before using the height or normal.

Prepared and loaded grids expose path (absolute file path) and sha256 (file checksum). asset_id identifies the dataset; bounds contains west, south, east and north limits in degrees; heights is the two-dimensional JAX height array.

class elodin.TerrainSample

FieldDescription
height_mSurface altitude in meters above the WGS84 ellipsoid.
normal_ecefOutward unit surface normal in ECEF coordinates.
validWhether the input position is valid and inside the grid coverage.