Mappers#
Mappers are the ground / surface model used by images and batches to intersect rays or sample heights. They work in their own CRS and expose a small, consistent API.
Core interfaces#
map_coordinates_from_rays(ray_vectors, ray_starts, crs_s=None, transformer=None): intersects rays with the surface and returns aMappingResult(coordinates + mask + issues).map_heights_from_coordinates(coordinates, crs_s=None, transformer=None): returns 3D coordinates with heights injected/interpolated from the surface model.param_dict/from_dict: serialize and reconstruct mapper configuration.crs/crs_wkt: mapper CRS; inputs are transformed automatically whencrs_sdiffers.
Available mappers#
MappingHorizontalPlane: constant-altitude plane; fastest for flat scenes.MappingRaster: samples a raster DEM/DSM (rasterio-based); good for terrain.MappingGeorefArray: in-memory height grid (often produced viaMappingRaster.load_window(...)).MappingTrimesh: ray intersections with a 3D mesh viatrimesh; supports complex surfaces.
When to choose which#
Flat site / sea surface / quick tests →
MappingHorizontalPlanewith a known altitude.Terrain from DEM/DSM →
MappingRaster(disk-backed; bilinear height sampling).In-memory raster subset →
MappingGeorefArray(fast repeated operations, no disk IO once loaded).Detailed surface mesh →
MappingTrimesh(ray–triangle hits, optional coordinate shift).
Using the core methods#
# Rays (e.g. from ImagePerspective.pixel_to_ray_vector) to ground
result = mapper.map_coordinates_from_rays(ray_vecs, ray_starts, crs_s=image.crs)
if result.ok:
ground_pts = result.coordinates[result.mask]
else:
print("Failed:", result.error, "Issues:", result.issues)
# Heights at XY positions
result_h = mapper.map_heights_from_coordinates(xy, crs_s=target_crs)
if result_h.ok:
pts_with_z = result_h.coordinates[result_h.mask]
Notes & tips#
Align mapper CRS with your images when possible; otherwise always pass
crs_s(or reuse atransformer).Expect partial success: check
result.okand filter withresult.mask; inspectissuesfor warnings likeWRONG_DIRECTION,OUTSIDE_RASTER,RASTER_NO_DATA,MAX_ITTERATION, orNO_INTERSECTION.Heavy mappers (rasters/meshes) typically open external resources at construction—reuse them across many images/batches.
For
MappingRaster, raster data is read lazily during runtime operations by default; it is only loaded into memory when you enablepreload_full_raster/preload_windowor callload_window().
Raster backend selection (MappingRaster)#
MappingRaster has two internal backends:
disk-backed (default): samples/intersects directly from the raster file via
rasterioin-memory (optional): a cached
MappingGeorefArraystored inmapper.georef_array
When an in-memory backend is present, MappingRaster.map_coordinates_from_rays and
MappingRaster.map_heights_from_coordinates automatically delegate to it.
Load a cached window / full raster#
from pyproj import CRS
from weitsicht import MappingRaster
mapper = MappingRaster(
raster_path="dem.tif",
crs=CRS.from_epsg(32633),
preload_window=(600_000, 5_340_000, 602_000, 5_342_000),
)
# Uses MappingGeorefArray because a window is cached
res = mapper.map_heights_from_coordinates([[601_000, 5_341_000]], crs_s=mapper.crs)
# You can also cache after construction (returns the MappingGeorefArray)
georef = mapper.load_window((600_000, 5_340_000, 602_000, 5_342_000))
assert georef is mapper.georef_array
# Optional helpers
backend = mapper.backend # MappingGeorefArray if loaded, else MappingRaster
georef2 = mapper.georef_mapper # raises if not loaded
Important
If you cache only a window, mapping operations are limited to that window extent. Points/rays outside the cached
extent will return Issue.OUTSIDE_RASTER.