Terrain¶
Download DEM tiles, merge them into local rasters, and compute where a sensor’s field of view intersects the ground surface. The module docstring below documents assumptions, limitations, and the public API.
Terrain analysis using Copernicus DEM data.
Downloads, caches, and queries 30-meter Copernicus GLO-30 DEM tiles from AWS. Provides bulk elevation lookup, DEM tile merging via rasterio, and a vectorized ray-terrain intersection algorithm for computing off-nadir ground intersection points.
Assumptions and limitations¶
- DEM is treated as static.
Tiles are downloaded once and cached indefinitely. There is no versioning or temporal awareness — the DEM is assumed to represent a fixed surface for the duration of a planning session.
- Nearest-neighbor elevation sampling.
get_elevationsrounds query coordinates to the nearest pixel center and returns that pixel’s value. There is no bilinear or bicubic interpolation. At 30 m resolution this introduces up to ~15 m of horizontal positioning error, which is negligible for flight planning but would matter for sub-pixel terrain modeling.- No nodata masking.
Pixels with nodata values (e.g. ocean voids) are returned as-is. Callers that operate over coastlines or data gaps should check for nodata sentinels (available via
DEMGrid.nodata) themselves.- Out-of-bounds queries clamp to edge pixels.
Query points outside the DEM extent return the elevation of the nearest edge pixel rather than NaN. A warning is logged.
- Ray-terrain intersection uses fixed-step marching.
ray_terrain_intersectionsteps along the slant range at a fixed interval (default 10 m) and detects the first range step where the DEM surface rises above the ray altitude. This is not a root-finding algorithm — the intersection point is located to within one step of the true crossing. Smallerprecisionvalues improve accuracy at the cost of a larger search grid.- Surface normals use 3x3 central differences.
surface_normal_atestimates slope from the two adjacent pixels in each direction, converted to metric gradients using a latitude-dependent meters-per-degree approximation. There is no sub-pixel terrain modeling or higher-order surface fitting.- Ellipsoidal altitude only.
All altitudes are heights above the WGS84 ellipsoid. The module does not apply geoid corrections (EGM96/EGM2008). For most flight-planning purposes the ~20 m geoid-ellipsoid separation is small relative to typical AGL flight altitudes (hundreds to thousands of meters).
Terrain references¶
Data source: Copernicus DEM GLO-30, European Space Agency, distributed via AWS Open Data (s3://copernicus-dem-30m).
- class DEMGrid[source]¶
Bases:
objectBackend-independent DEM raster.
All terrain math consumes
DEMGridinstead of live rasterio datasets. Thegeotransformuses the GDAL convention:(origin_x, pixel_width, x_skew, origin_y, y_skew, pixel_height)wherepixel_heightis typically negative (north-up).- Variables:
array – 2-D elevation array (rows, cols) in meters.
geotransform – 6-element affine transform tuple.
bounds –
(west, south, east, north)in degrees.nodata – No-data sentinel value, or
None.
- clear_cache()[source]¶
Clears the entire cache directory after confirming it is safe to do so.
- Return type:
- clear_localdem_cache(confirm=True)[source]¶
Clears the local DEM cache directory.
This removes all files in the ‘localdem’ subdirectory of the cache root, which stores downloaded DEM tiles.
- build_tile_index(tile_list_file)[source]¶
Build an R-tree spatial index for DEM tiles from a tile list file.
Each line in the file is a tile name encoding lat/lon in the filename. Tiles are parsed into 1x1 degree bounding boxes and indexed spatially.
- download_dem_files(lon_min, lat_min, lon_max, lat_max, aws_dir)[source]¶
Download DEM tile files covering a geographic bounding box.
Tiles are downloaded from the specified AWS directory and cached locally. Already-downloaded tiles are reused from the cache.
- Parameters:
- Returns:
List of local file paths to the downloaded DEM tiles.
- Return type:
List[str]
- merge_tiles(output_filename, tile_file_list)[source]¶
Merge multiple DEM tile files into a single GeoTIFF using rasterio.
- Parameters:
- Raises:
ValueError – If tile_file_list is empty or contains invalid paths.
RuntimeError – If merge operation fails.
- Return type:
- generate_demfile(latitude, longitude, aws_dir='https://copernicus-dem-30m.s3.amazonaws.com/')[source]¶
Generate a DEM file covering the specified latitude and longitude extents.
- load_dem(dem_file)[source]¶
Load a DEM file and return a cached
DEMGrid.Handles mtime lookup so callers don’t have to.
- get_elevations(lats, lons, dem_file)[source]¶
Extract elevation values for given latitudes and longitudes from a DEM file.
Reads the entire raster band once and indexes it in bulk, rather than querying pixel-by-pixel. The raster is cached per
(path, mtime)so repeated calls against the same DEM (the common case in flight planning) pay the read cost only once.
- get_elevations_from_grid(lats, lons, dem)[source]¶
Extract elevation values from a
DEMGrid(no file I/O).
- get_min_max_elevations(dem_file)[source]¶
Get the minimum and maximum elevation values from a DEM file.
- ray_terrain_intersection(lat0, lon0, h0, az, tilt, precision=10.0, dem_file=None)[source]¶
Batch computation of ray-terrain intersections using a DEM for multiple observer positions. Vectorized to handle multiple observers efficiently.
- Parameters:
lat0 (np.ndarray) – Array of observer latitudes (degrees).
lon0 (np.ndarray) – Array of observer longitudes (degrees).
h0 (float) – Altitude of the observer above the ellipsoid (meters).
az (np.ndarray) – Azimuth angle of the ray (degrees).
tilt (np.ndarray) – Off-nadir tilt angle from vertical (degrees, 0-90), where
0is nadir and90is horizontal.precision (float) – Precision of the slant range sampling (meters).
dem_file (str) – Path to the DEM file. If None, one will be generated.
- Returns:
- (intersection_lats, intersection_lons,
intersection_alts). Observers with no terrain intersection have NaN in all three arrays.
- Return type:
Tuple[np.ndarray, np.ndarray, np.ndarray]
- Raises:
ValueError – If tilt or azimuth values are out of range, or if tilt is too close to horizontal (90 deg) where slant-range geometry is undefined.
- terrain_elevation_along_track(flight_line, dem_file, precision=100.0)[source]¶
Min, mean, and max terrain elevation (m MSL) along a flight line’s nadir track.
Samples the DEM at evenly-spaced points along the flight line and returns summary statistics useful for Mode 3 per-line altitude planning.
- Parameters:
- Return type:
- Returns:
Dict with keys
"min","mean", and"max"(all in meters MSL).
- terrain_aspect_azimuth(polygon, dem_file=None)[source]¶
Dominant terrain gradient direction (degrees from north) for a polygon.
Computes the dominant downslope azimuth from the DEM gradient over the polygon area. To minimise altitude variation along each flight line (as recommended by Zhao et al. 2021 for Mode 3), orient flight lines perpendicular to the returned azimuth:
flight_azimuth = (terrain_aspect_azimuth(polygon) + 90) % 360
- Parameters:
- Return type:
- Returns:
Dominant downslope azimuth in degrees clockwise from true north (range 0-360).