Source code for pystac.extensions.view

"""Implement the :stac-ext:`View Geometry Extension <view>`."""

from __future__ import annotations

from collections.abc import Iterable
from typing import Any, Generic, Literal, TypeVar, Union, cast

import pystac
from pystac.extensions import item_assets
from pystac.extensions.base import (
    ExtensionManagementMixin,
    PropertiesExtension,
    SummariesExtension,
)
from pystac.extensions.hooks import ExtensionHooks
from pystac.summaries import RangeSummary

T = TypeVar("T", pystac.Item, pystac.Asset, item_assets.AssetDefinition)

SCHEMA_URI: str = "https://stac-extensions.github.io/view/v1.0.0/schema.json"
PREFIX: str = "view:"

OFF_NADIR_PROP: str = PREFIX + "off_nadir"
INCIDENCE_ANGLE_PROP: str = PREFIX + "incidence_angle"
AZIMUTH_PROP: str = PREFIX + "azimuth"
SUN_AZIMUTH_PROP: str = PREFIX + "sun_azimuth"
SUN_ELEVATION_PROP: str = PREFIX + "sun_elevation"


[docs]class ViewExtension( Generic[T], PropertiesExtension, ExtensionManagementMixin[Union[pystac.Item, pystac.Collection]], ): """An abstract class that can be used to extend the properties of an :class:`~pystac.Item` with properties from the :stac-ext:`View Geometry Extension <view>`. This class is generic over the type of STAC Object to be extended (e.g. :class:`~pystac.Item`, :class:`~pystac.Asset`). To create a concrete instance of :class:`ViewExtension`, use the :meth:`ViewExtension.ext` method. For example: .. code-block:: python >>> item: pystac.Item = ... >>> view_ext = ViewExtension.ext(item) """ name: Literal["view"] = "view"
[docs] def apply( self, off_nadir: float | None = None, incidence_angle: float | None = None, azimuth: float | None = None, sun_azimuth: float | None = None, sun_elevation: float | None = None, ) -> None: """Applies View Geometry extension properties to the extended :class:`~pystac.Item`. Args: off_nadir : The angle from the sensor between nadir (straight down) and the scene center. Measured in degrees (0-90). incidence_angle : The incidence angle is the angle between the vertical (normal) to the intercepting surface and the line of sight back to the satellite at the scene center. Measured in degrees (0-90). azimuth : Viewing azimuth angle. The angle measured from the sub-satellite point (point on the ground below the platform) between the scene center and true north. Measured clockwise from north in degrees (0-360). sun_azimuth : Sun azimuth angle. From the scene center point on the ground, this is the angle between truth north and the sun. Measured clockwise in degrees (0-360). sun_elevation : Sun elevation angle. The angle from the tangent of the scene center point to the sun. Measured from the horizon in degrees (0-90). """ self.off_nadir = off_nadir self.incidence_angle = incidence_angle self.azimuth = azimuth self.sun_azimuth = sun_azimuth self.sun_elevation = sun_elevation
@property def off_nadir(self) -> float | None: """Get or sets the angle from the sensor between nadir (straight down) and the scene center. Measured in degrees (0-90). """ return self._get_property(OFF_NADIR_PROP, float) @off_nadir.setter def off_nadir(self, v: float | None) -> None: self._set_property(OFF_NADIR_PROP, v) @property def incidence_angle(self) -> float | None: """Get or sets the incidence angle is the angle between the vertical (normal) to the intercepting surface and the line of sight back to the satellite at the scene center. Measured in degrees (0-90). """ return self._get_property(INCIDENCE_ANGLE_PROP, float) @incidence_angle.setter def incidence_angle(self, v: float | None) -> None: self._set_property(INCIDENCE_ANGLE_PROP, v) @property def azimuth(self) -> float | None: """Get or sets the viewing azimuth angle. The angle measured from the sub-satellite point (point on the ground below the platform) between the scene center and true north. Measured clockwise from north in degrees (0-360). """ return self._get_property(AZIMUTH_PROP, float) @azimuth.setter def azimuth(self, v: float | None) -> None: self._set_property(AZIMUTH_PROP, v) @property def sun_azimuth(self) -> float | None: """Get or sets the sun azimuth angle. From the scene center point on the ground, this is the angle between truth north and the sun. Measured clockwise in degrees (0-360). """ return self._get_property(SUN_AZIMUTH_PROP, float) @sun_azimuth.setter def sun_azimuth(self, v: float | None) -> None: self._set_property(SUN_AZIMUTH_PROP, v) @property def sun_elevation(self) -> float | None: """Get or sets the sun elevation angle. The angle from the tangent of the scene center point to the sun. Measured from the horizon in degrees (0-90). """ return self._get_property(SUN_ELEVATION_PROP, float) @sun_elevation.setter def sun_elevation(self, v: float | None) -> None: self._set_property(SUN_ELEVATION_PROP, v)
[docs] @classmethod def get_schema_uri(cls) -> str: return SCHEMA_URI
[docs] @classmethod def ext(cls, obj: T, add_if_missing: bool = False) -> ViewExtension[T]: """Extends the given STAC Object with properties from the :stac-ext:`View Geometry Extension <scientific>`. This extension can be applied to instances of :class:`~pystac.Item` or :class:`~pystac.Asset`. Raises: pystac.ExtensionTypeError : If an invalid object type is passed. """ if isinstance(obj, pystac.Item): cls.ensure_has_extension(obj, add_if_missing) return cast(ViewExtension[T], ItemViewExtension(obj)) elif isinstance(obj, pystac.Asset): cls.ensure_owner_has_extension(obj, add_if_missing) return cast(ViewExtension[T], AssetViewExtension(obj)) elif isinstance(obj, item_assets.AssetDefinition): cls.ensure_owner_has_extension(obj, add_if_missing) return cast(ViewExtension[T], ItemAssetsViewExtension(obj)) else: raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
[docs] @classmethod def summaries( cls, obj: pystac.Collection, add_if_missing: bool = False ) -> SummariesViewExtension: """Returns the extended summaries object for the given collection.""" cls.ensure_has_extension(obj, add_if_missing) return SummariesViewExtension(obj)
[docs]class ItemViewExtension(ViewExtension[pystac.Item]): """A concrete implementation of :class:`ViewExtension` on an :class:`~pystac.Item` that extends the properties of the Item to include properties defined in the :stac-ext:`View Geometry Extension <view>`. This class should generally not be instantiated directly. Instead, call :meth:`ViewExtension.ext` on an :class:`~pystac.Item` to extend it. """ item: pystac.Item """The :class:`~pystac.Item` being extended.""" properties: dict[str, Any] """The :class:`~pystac.Item` properties, including extension properties.""" def __init__(self, item: pystac.Item): self.item = item self.properties = item.properties def __repr__(self) -> str: return f"<ItemViewExtension Item id={self.item.id}>"
[docs]class AssetViewExtension(ViewExtension[pystac.Asset]): """A concrete implementation of :class:`ViewExtension` on an :class:`~pystac.Asset` that extends the Asset fields to include properties defined in the :stac-ext:`View Geometry Extension <view>`. This class should generally not be instantiated directly. Instead, call :meth:`ViewExtension.ext` on an :class:`~pystac.Asset` to extend it. """ asset_href: str """The ``href`` value of the :class:`~pystac.Asset` being extended.""" properties: dict[str, Any] """The :class:`~pystac.Asset` fields, including extension properties.""" additional_read_properties: Iterable[dict[str, Any]] | None = None """If present, this will be a list containing 1 dictionary representing the properties of the owning :class:`~pystac.Item`.""" def __init__(self, asset: pystac.Asset): self.asset_href = asset.href self.properties = asset.extra_fields if asset.owner and isinstance(asset.owner, pystac.Item): self.additional_read_properties = [asset.owner.properties] def __repr__(self) -> str: return f"<AssetViewExtension Asset href={self.asset_href}>"
[docs]class ItemAssetsViewExtension(ViewExtension[item_assets.AssetDefinition]): properties: dict[str, Any] asset_defn: item_assets.AssetDefinition def __init__(self, item_asset: item_assets.AssetDefinition): self.asset_defn = item_asset self.properties = item_asset.properties
[docs]class SummariesViewExtension(SummariesExtension): """A concrete implementation of :class:`~SummariesExtension` that extends the ``summaries`` field of a :class:`~pystac.Collection` to include properties defined in the :stac-ext:`View Object Extension <view>`. """ @property def off_nadir(self) -> RangeSummary[float] | None: """Get or sets the summary of :attr:`ViewExtension.off_nadir` values for this Collection. """ return self.summaries.get_range(OFF_NADIR_PROP) @off_nadir.setter def off_nadir(self, v: RangeSummary[float] | None) -> None: self._set_summary(OFF_NADIR_PROP, v) @property def incidence_angle(self) -> RangeSummary[float] | None: """Get or sets the summary of :attr:`ViewExtension.incidence_angle` values for this Collection. """ return self.summaries.get_range(INCIDENCE_ANGLE_PROP) @incidence_angle.setter def incidence_angle(self, v: RangeSummary[float] | None) -> None: self._set_summary(INCIDENCE_ANGLE_PROP, v) @property def azimuth(self) -> RangeSummary[float] | None: """Get or sets the summary of :attr:`ViewExtension.azimuth` values for this Collection. """ return self.summaries.get_range(AZIMUTH_PROP) @azimuth.setter def azimuth(self, v: RangeSummary[float] | None) -> None: self._set_summary(AZIMUTH_PROP, v) @property def sun_azimuth(self) -> RangeSummary[float] | None: """Get or sets the summary of :attr:`ViewExtension.sun_azimuth` values for this Collection. """ return self.summaries.get_range(SUN_AZIMUTH_PROP) @sun_azimuth.setter def sun_azimuth(self, v: RangeSummary[float] | None) -> None: self._set_summary(SUN_AZIMUTH_PROP, v) @property def sun_elevation(self) -> RangeSummary[float] | None: """Get or sets the summary of :attr:`ViewExtension.sun_elevation` values for this Collection. """ return self.summaries.get_range(SUN_ELEVATION_PROP) @sun_elevation.setter def sun_elevation(self, v: RangeSummary[float] | None) -> None: self._set_summary(SUN_ELEVATION_PROP, v)
[docs]class ViewExtensionHooks(ExtensionHooks): schema_uri = SCHEMA_URI prev_extension_ids = {"view"} stac_object_types = {pystac.STACObjectType.ITEM}
VIEW_EXTENSION_HOOKS: ExtensionHooks = ViewExtensionHooks()