============ Top-Tips ============ PyProj ======== If special transformation grids are included in the coordinate transformation use: .. code-block:: python # PROJ activate network grid/data pyproj.network.set_network_enabled(True) # pyright: ignore[reportPrivateImportUsage] Or specify data-dir via .. code-block:: python pyproj.datadir.set_data_dir(proj_data_dir) Results ======== The most important functions, mapping(``mapper.map_points``, ``mapper.map_footprint``, ``mapper.map_center_point``) and coordinate projections (``image.project``) return ``MappingResult`` and ``ProjectionResult`` - ``MappingResult`` is either ``ResultFailure`` or ``MappingResultSuccess`` - ``ProjectionResult`` is either ``ResultFailure`` or ``ProjectionResultSuccess`` You can test whether it's Success or Failure be checking ``.ok``. **The results will always be in the same order as the input pixel/coordinates.** Always check for issues to catch reasons for invalid results .. tip:: Most mapping functions return results with a CRS attached (``res.crs``). You can use that CRS to transform the mapped output (e.g. footprint coordinates) to another coordinate system via :class:`~weitsicht.transform.CoordinateTransformer`. .. code-block:: python from pyproj import CRS from weitsicht.transform import CoordinateTransformer res = image.map_footprint() if res.ok and res.crs is not None: crs_target = CRS.from_epsg(4979) # WGS84 ell with ellipsoid heights transformer = CoordinateTransformer.from_crs(res.crs, crs_target) coords_src = res.coordinates[res.mask] # Always check that transfomer is not None which is the case if source and target crs are equal coords_target = coords_src if transformer is None else transformer.transform(coords_src) Errors ====== Most functions either raise a :class:`~weitsicht.exceptions.WeitsichtError` (invalid inputs / missing state) **or** return a result object (``MappingResult`` / ``ProjectionResult``) that can be a ``ResultFailure``. .. code-block:: python from weitsicht import WeitsichtError try: res = image.map_points([[200, 300], [50, 50]]) except WeitsichtError as err: print("weitsicht error:", err) else: if not res.ok: print("mapping failed:", res.error, "issues:", res.issues) else: coords_valid = res.coordinates[res.mask] # keep input order See :doc:`error_handling` for more patterns and the exception hierarchy. Perspective Images ================== .. tip:: For drone photos, prefer building your ``ImagePerspective`` from EXIF/XMP metadata (e.g. ExifTool -> ``PyExifToolTags`` -> ``image_from_meta()``) or use ``ImageFromMetaBuilder`` if you want IOR/EOR separately. See :doc:`metadata` and :ref:`example-0401`. ''image_from_meta()'' and other EOR related functions feature an input parameter ``to_utm=True`` which will convert EOR (position and orientation) to WGS84/UTM. Otherwise standard output of images loaded by meta builder are in WGS84 geocentric (EPG:4978) coordiantes CRS quick reference ------------------- .. list-table:: CRS overview (rows) vs. weitsicht components (columns) :header-rows: 1 :stub-columns: 1 * - CRS / units - Perspective Image (EOR) - Coordiantes for Projection - Orthophoto CRS - Mapper Horizontal - MapperRaster GeorefArray - Mapper Trimesh * - ``None`` (local coordinates, no transforms) - OK - OK - OK - OK - OK (``force_no_crs=True``) - OK * - Projected (e.g., UTM) **(0)** - OK - OK - OK - OK - OK - OK * - Geocentric Cartesian (ECEF) (e.g. ``EPSG:4978``) - OK - OK - Not possible - Rare (never seen such thing) - Limited **(1)** - Not possible - Rare (never seen such thing) - OK * - Geodetic lon/lat (degrees) (e.g. ``EPSG:4326`` / ``EPSG:4979``) - Not working **(2)** - OK - Possible (but units for gsd/area are degrees) - Possible **(3)** - Possible (only with 3D CRS) **(4)** - Not working (would need transformation first) | **(0)** has to be 3D CRS or compound, meters (e.g. UTM / ``EPSG:25833+3855``) | **(1)** ECEF and plane working mathematically but plane normal 0,0,1 makes no sense here. Will implement nonHorizontal plane soon. | **(2)** use as input CRS and transform to a metric CRS first, also orientation needs to be transformed | **(3)** using this a lot for sea-side EPSG:4326+3855 -> WGS84 (Lat/Lon) + EGM2008 | **(4)** beware units/vertical datum, very large raster resolutions may lead to problems Mapping ============ For raster-based mapping you can trade disk IO for memory: - ``MappingRaster`` (default) keeps the raster on disk and reads only the needed values. - If you cache a window/full raster (``preload_window``, ``preload_full_raster`` or ``load_window``), :class:`~weitsicht.MappingRaster` automatically uses an in-memory :class:`~weitsicht.MappingGeorefArray` backend. .. tip:: With ``MappingRaster`` in default mode, you can use extremely large raster datasets (e.g. a DTM of your whole country) without loading the full raster into RAM. .. code-block:: python 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), ) # mapper.map_* now uses the cached backend res = mapper.map_heights_from_coordinates([[601_000, 5_341_000]], crs_s=mapper.crs) # Or cache later (returns MappingGeorefArray) georef = mapper.load_window((600_000, 5_340_000, 602_000, 5_342_000)) .. important:: If you cache only a window, mapping is limited to that cached extent (outside points/rays will report ``Issue.OUTSIDE_RASTER``).