Skip to content

Positions

positions

Positions

Positions(
    xyz: Union[ndarray, list],
    epsg: int = 0,
    local_transformer: Transformer = None,
    init_local_transformer: bool = True,
    epsg_local_cart: int = 4936,
    epsg_local_geod: int = 4937,
)

Class representing (georeferenced) positions.

The Positions class can hold one or multiple 3d positions with a corresponding EPSG code for datum information. When creating a Positions instance, a transformation pipeline is created based on the passed points, which can transform the points into a local system tangent to the ellipsoid (grs80). Such a local datum is represented within this class with an EPSG code of 0 and is mainly suitable for local calculations within the Positions.

All transformations, including the local transformation, are carried out using pyproj, a python toolbox for projections and transformations.

Initialize Positions and create local transformer.

If a Positions instance is initialized directly with an EPSG code of 0, such a local transformer cannot be constructed, and a transformation into other EPSG codes is therefore not possible. Use this setting if you don't have any information about the geodetic datum of the passed points. However, if the local transformer is already known, it can be provided during the initialization of the Positions object using the local_transformer variable.

Parameters:

  • xyz (ndarray | list) –

    1- / 2- dimensional numpy array containing the coordinates of the input positions.

  • epsg (int, default: 0 ) –

    EPSG code of the datum of the input positions. Defaults to 0.

  • local_transformer (Transformer, default: None ) –

    pyproj transformer that describes the transformation to a local coordinate system. Defaults to None.

  • init_local_transformer (bool, default: True ) –

    Specifies if a local transformer should be initialized. Defaults to True.

  • epsg_local_cart (int, default: 4936 ) –

    EPSG code of the earth-centered datum that is used to construct the local transformation pipeline. In a first step, the coordinates are transformed to this coordinate frame. In this coordinate frame they are reduced by their mean position. Defaults to 4936.

  • epsg_local_geod (int, default: 4937 ) –

    In the final step of the local transformation pipeline, the positions reduced by their mean are rotated into a local system tangent to the ellipsoid. The ellipsoid is defined by this parameter using an EPSG code. Both EPSG codes, epsg_local_cart and epsg_local_geod should refer to the same datum (here ETRS89). Defaults to 4937.

Raises:

  • PointSetError

    Gets raised if input xyz is not a numpy array.

Source code in trajectopy\core\positions.py
def __init__(
    self,
    xyz: Union[np.ndarray, list],
    epsg: int = 0,
    local_transformer: Transformer = None,
    init_local_transformer: bool = True,
    epsg_local_cart: int = 4936,
    epsg_local_geod: int = 4937,
) -> None:
    """Initialize Positions and create local transformer.

    If a Positions instance is initialized directly with an EPSG code of 0, such a local transformer
    cannot be constructed, and a transformation into other EPSG codes is therefore not possible.
    Use this setting if you don't have any information about the geodetic datum of the passed points.
    However, if the local transformer is already known, it can be provided during the
    initialization of the Positions object using the local_transformer variable.

    Args:
        xyz (np.ndarray | list): 1- / 2- dimensional numpy array containing the coordinates
            of the input positions.
        epsg (int, optional): EPSG code of the datum of the input positions. Defaults to 0.
        local_transformer (Transformer, optional): pyproj transformer that describes the
            transformation to a local coordinate system. Defaults to None.
        init_local_transformer (bool, optional): Specifies if a local transformer should be
            initialized. Defaults to True.
        epsg_local_cart (int, optional): EPSG code of the earth-centered datum that is used
            to construct the local transformation pipeline. In a first step, the coordinates
            are transformed to this coordinate frame. In this coordinate frame they are reduced
            by their mean position. Defaults to 4936.
        epsg_local_geod (int, optional): In the final step of the local transformation pipeline,
            the positions reduced by their mean are rotated into a local system tangent to the
            ellipsoid. The ellipsoid is defined by this parameter using an EPSG code. Both EPSG
            codes, epsg_local_cart and epsg_local_geod should refer to the same datum (here ETRS89).
            Defaults to 4937.

    Raises:
        PointSetError: Gets raised if input xyz is not a numpy array.
    """

    if not isinstance(xyz, np.ndarray):
        xyz = np.array(xyz)

    if (len(xyz.shape) == 1 and len(xyz) != 3) or (len(xyz.shape) == 2 and xyz.shape[1] != 3):
        raise PointSetError("Input must be nx3 or 3xNone array!")

    self.xyz = xyz
    self.epsg = epsg
    self.local_transformer = local_transformer
    self.epsg_local_geod = epsg_local_geod
    self.epsg_local_cart = epsg_local_cart
    self.pipeline_str = ""

    if self.epsg == 0:
        return

    # Create CRS and local transformer
    if local_transformer or not init_local_transformer:
        return

    self.build_local_transformer()

xyz property writable

xyz: ndarray

Returns the points within the Positions object.

Returns:

  • ndarray

    np.ndarray: 2-dimensional numpy array.

x property writable

x: Union[int, float, ndarray]

Returns x coordinate(s).

The x/y/z properties will either return a one-dimensional numpy array or a single float / int depending on whether there is more than one point in the Positions object.

Returns:

  • Union[int, float, ndarray]

    Union[int, float, np.ndarray]: X coordinate(s).

y property writable

y: Union[int, float, ndarray]

Returns y coordinate(s).

The x/y/z properties will either return a one-dimensional numpy array or a single float / int depending on whether there is more than one point in the Positions object.

Returns:

  • Union[int, float, ndarray]

    Union[int, float, np.ndarray]: Y coordinate(s).

z property writable

z: Union[int, float, ndarray]

Returns z coordinate(s).

The x/y/z properties will either return a one-dimensional numpy array or a single float / int depending on whether there is more than one point in the Positions object.

Returns:

  • Union[int, float, ndarray]

    Union[int, float, np.ndarray]: Z coordinate(s).

crs property

crs: CRS

Returns the Coordinate Reference System.

Returns:

  • CRS ( CRS ) –

    pyproj CRS object that represents the current coordinate system.

__len__

__len__() -> int

Returns number of points

Source code in trajectopy\core\positions.py
def __len__(self) -> int:
    """Returns number of points"""
    return len(self.xyz)

copy

copy() -> Positions

Deep copy

Source code in trajectopy\core\positions.py
def copy(self) -> "Positions":
    """Deep copy"""
    return copy.deepcopy(self)

__get_column

__get_column(idx: int) -> Union[int, float, ndarray]

Internal method to extract a column from xyz

This method will return one column specified by idx from the xyz array. It distinguishes between the number of points and returns either a single float or a 1-d numpy array.

Parameters:

  • idx (int) –

    index of the desired column

Returns:

  • Union[int, float, ndarray]

    Union[int, float, np.ndarray]: Value / array of that column

Source code in trajectopy\core\positions.py
def __get_column(self, idx: int) -> Union[int, float, np.ndarray]:
    """Internal method to extract a column from xyz

    This method will return one column specified by idx from the
    xyz array.
    It distinguishes between the number of points and returns
    either a single float or a 1-d numpy array.

    Args:
        idx (int): index of the desired column

    Returns:
        Union[int, float, np.ndarray]: Value / array of that column
    """
    return self.xyz[:, idx] if len(self.xyz) > 1 else self.xyz[0][idx]

__set_column

__set_column(
    v: Union[int, float, ndarray], idx: int
) -> None

Internal method to change a column of xyz

This method will set a column of xyz to v.

Parameters:

  • v (Union[int, float, ndarray]) –

    Value(s) with which the column is to be filled. Either a single value or an array of exactly the same length as xyz.

  • idx (int) –

    column index in xyz

Source code in trajectopy\core\positions.py
def __set_column(self, v: Union[int, float, np.ndarray], idx: int) -> None:
    """Internal method to change a column of xyz

    This method will set a column of xyz to v.

    Args:
        v (Union[int, float, np.ndarray]): Value(s) with which the
                                           column is to be filled.
                                           Either a single value or
                                           an array of exactly the
                                           same length as xyz.
        idx (int): column index in xyz
    """
    self.xyz[:, idx] = v

to_epsg

to_epsg(
    target_epsg: int, inplace: bool = True
) -> Positions

Performs a coordinate transformation using a target CRS.

This method will construct the required pyproj transformer and applies it in order to transform the positions to the target EPSG code.

Parameters:

  • target_epsg (int) –

    EPSG code of target CRS.

  • inplace (bool, default: True ) –

    Perform transformation in place. Defaults to True.

Raises:

  • PointSetError

    Gets raised if it is not possible to recover from a local datum since local transformer is unknown.

Returns:

  • Positions ( Positions ) –

    Transformed positions.

Source code in trajectopy\core\positions.py
def to_epsg(self, target_epsg: int, inplace: bool = True) -> "Positions":
    """Performs a coordinate transformation using a target CRS.

    This method will construct the required pyproj transformer and applies it in order to
    transform the positions to the target EPSG code.

    Args:
        target_epsg (int): EPSG code of target CRS.
        inplace (bool, optional): Perform transformation in place. Defaults to True.

    Raises:
        PointSetError: Gets raised if it is not possible to recover from a local datum
            since local transformer is unknown.

    Returns:
        Positions: Transformed positions.
    """
    pointset = self if inplace else self.copy()

    # 0) already there
    if pointset.epsg == target_epsg:
        return pointset

    # currently in unknown frame
    if pointset.epsg == 0 and pointset.local_transformer is None:
        raise PointSetError("Unable to recover from local frame since definition is unknown!")

    # 1) from non-local to local
    if target_epsg == 0:
        # geocentric cartesian (ITRF2014)
        pointset.to_epsg(target_epsg=pointset.epsg_local_cart)

        # apply local transformer
        x, y, z = pointset.local_transformer.transform(xx=pointset.x, yy=pointset.y, zz=pointset.z)

        pointset.xyz = np.c_[x, y, z]
        pointset.epsg = target_epsg

        return pointset

    # 2) from local to non-local (intermediate step)
    if pointset.epsg == 0:
        # undo local transformation
        x, y, z = pointset.local_transformer.transform(
            xx=pointset.x,
            yy=pointset.y,
            zz=pointset.z,
            direction=TransformDirection.INVERSE,
        )
        xyz = np.c_[x, y, z]
        crs = CRS.from_epsg(pointset.epsg_local_cart)
    else:
        xyz = pointset.xyz
        crs = pointset.crs

    # 3) from non-local to non-local
    transformer = Transformer.from_crs(crs, CRS.from_epsg(code=target_epsg))

    x, y, z = transformer.transform(xx=xyz[:, 0], yy=xyz[:, 1], zz=xyz[:, 2])

    pointset.xyz = np.c_[x, y, z]
    pointset.epsg = target_epsg

    return pointset

to_local

to_local(inplace: bool = True) -> Positions

Transform positions to a local frame tangential to the (grs80) ellipsoid.

This is equivalent to a transformation to an EPSG of 0.

Parameters:

  • inplace (bool, default: True ) –

    Perform transformation in place. Defaults to True.

Returns:

  • Positions ( Positions ) –

    2-dimensional object containing xyz of the transformed points.

Source code in trajectopy\core\positions.py
def to_local(self, inplace: bool = True) -> "Positions":
    """Transform positions to a local frame tangential to the (grs80) ellipsoid.

    This is equivalent to a transformation to an EPSG of 0.

    Args:
        inplace (bool, optional): Perform transformation in place. Defaults to True.

    Returns:
        Positions: 2-dimensional object containing xyz of the transformed points.
    """
    return self.to_epsg(target_epsg=0, inplace=inplace)

mean

mean(inplace: bool = False) -> Positions

Computes the mean of all points within the Positions object.

Parameters:

  • inplace (bool, default: False ) –

    If true, the positions object gets replaced by a single mean position. Defaults to False.

Returns:

  • Positions ( Positions ) –

    Contains the mean position.

Source code in trajectopy\core\positions.py
def mean(self, inplace: bool = False) -> "Positions":
    """Computes the mean of all points within the Positions object.

    Args:
        inplace (bool, optional): If true, the positions object gets replaced by a single mean
            position. Defaults to False.

    Returns:
        Positions: Contains the mean position.
    """
    mean_xyz = np.mean(self.xyz, axis=0)

    if inplace:
        self.xyz = mean_xyz
    return Positions(xyz=mean_xyz, epsg=self.epsg, local_transformer=self.local_transformer)

round_to

round_to(prec: float) -> Positions

Rounds all points to a given precision.

Parameters:

  • prec (float) –

    Desired rounding precision.

Returns:

  • Positions ( Positions ) –

    Contains the rounded positions.

Source code in trajectopy\core\positions.py
def round_to(self, prec: float) -> "Positions":
    """Rounds all points to a given precision.

    Args:
        prec (float): Desired rounding precision.

    Returns:
        Positions: Contains the rounded positions.
    """
    rounded = self.copy()
    rounded.xyz = np.round(rounded.xyz / prec) * prec
    return rounded

__add__

__add__(other: Positions) -> Positions

Plus operator.

Parameters:

Returns:

  • Positions ( Positions ) –

    Sum of positions.

Source code in trajectopy\core\positions.py
def __add__(self, other: "Positions") -> "Positions":
    """Plus operator.

    Args:
        other (Positions): Positions to add.

    Returns:
        Positions: Sum of positions.
    """
    xyz_add = self.xyz + other.xyz
    return Positions(xyz=xyz_add, epsg=self.epsg, local_transformer=self.local_transformer)

__sub__

__sub__(other: Positions) -> Positions

Minus operator.

Parameters:

  • other (Positions) –

    Positions to subtract.

Returns:

  • Positions ( Positions ) –

    Difference of positions.

Source code in trajectopy\core\positions.py
def __sub__(self, other: "Positions") -> "Positions":
    """Minus operator.

    Args:
        other (Positions): Positions to subtract.

    Returns:
        Positions: Difference of positions.
    """
    xyz_sub = self.xyz - other.xyz
    return Positions(xyz=xyz_sub, epsg=self.epsg, local_transformer=self.local_transformer)

__key

__key() -> tuple

Key generation used for hash generation.

Returns:

  • tuple ( tuple ) –

    Key tuple for hashing.

Source code in trajectopy\core\positions.py
def __key(self) -> tuple:
    """Key generation used for hash generation.

    Returns:
        tuple: Key tuple for hashing.
    """
    return (
        self.epsg,
        self.xyz[:, 0] @ self.xyz[:, 0],
        self.xyz[:, 1] @ self.xyz[:, 1],
        self.xyz[:, 2] @ self.xyz[:, 2],
        self.pipeline_str,
    )

__eq__

__eq__(other: Positions) -> bool

Equality comparison.

Parameters:

  • other (Positions) –

    Object to compare with.

Returns:

  • bool ( bool ) –

    True if equal, False otherwise.

Raises:

  • NotImplementedError

    If comparing with incompatible type.

Source code in trajectopy\core\positions.py
def __eq__(self, other: "Positions") -> bool:
    """Equality comparison.

    Args:
        other: Object to compare with.

    Returns:
        bool: True if equal, False otherwise.

    Raises:
        NotImplementedError: If comparing with incompatible type.
    """
    if isinstance(other, Positions):
        return self.__key() == other.__key()
    raise NotImplementedError(f"Cannot compare {type(self)} with {type(other)}!")