Skip to content

Linear Spline

Curve class useful to describe any kind of curves

LinearSpline

Bases: LinearEntity

Curve class

Source code in otary/geometry/discrete/linear/linear_spline.py
class LinearSpline(LinearEntity):
    """Curve class"""

    def __init__(self, points: NDArray | list, is_cast_int: bool = False) -> None:
        if len(points) < 2:
            raise ValueError(
                "Cannot create a LinearSpline since it must have 2 or more points"
            )
        super().__init__(points=points, is_cast_int=is_cast_int)

    @property
    def curvature(self) -> float:
        """Get the curvature of the linear spline as-if it had a well-defined
        curvature, meaning as-if it were a continuous curve.

        Returns:
            float: curvature value
        """
        # TODO
        raise NotImplementedError

    @property
    def centroid(self) -> NDArray:
        """Returns the center point that is within the linear spline.
        This means that this points necessarily belongs to the linear spline.

        This can be useful when the centroid is not a good representation of what
        is needed as 'center'.

        Returns:
            NDArray: point of shape (1, 2)
        """
        total_length: float = 0.0
        cx: float = 0.0
        cy: float = 0.0

        for i in range(len(self.points) - 1):
            p1, p2 = self.points[i], self.points[i + 1]
            mid = (p1 + p2) / 2
            length = float(np.linalg.norm(p2 - p1))
            cx += mid[0] * length
            cy += mid[1] * length
            total_length += length

        if total_length == 0:
            return self.points[0]  # or handle degenerate case
        return np.asarray([cx / total_length, cy / total_length])

    @property
    def midpoint(self) -> NDArray:
        """Returns the center point that is within the linear spline.
        This means that this points necessarily belongs to the linear spline.

        This can be useful when the centroid is not a good representation of what
        is needed as 'center'.

        Returns:
            NDArray: point of shape (1, 2)
        """
        return self.find_interpolated_point(pct_dist=0.5)

    def find_interpolated_point_and_prev_ix(
        self, pct_dist: float
    ) -> tuple[NDArray, int]:
        """Return a point along the curve at a relative distance pct_dist ∈ [0, 1]

        Parameters:
            pct_dist (float): Value in [0, 1], 0 returns start, 1 returns end.
                Any value in [0, 1] returns a point between start and end that is
                pct_dist along the path.

        Returns:
            tuple[NDArray, int]: Interpolated point [x, y] and previous index in path.
        """
        if not 0 <= pct_dist <= 1:
            raise ValueError("pct_dist must be in [0, 1]")

        if self.length == 0 or pct_dist == 0:
            return self[0], 0
        if pct_dist == 1:
            return self[-1], len(self) - 1

        # Walk along the path to find the point at pct_dist * total_dist
        target_dist = pct_dist * self.length
        accumulated = 0
        for i in range(len(self.edges)):
            cur_edge_length = self.lengths[i]
            if accumulated + cur_edge_length >= target_dist:
                remain = target_dist - accumulated
                direction = self[i + 1] - self[i]
                unit_dir = direction / cur_edge_length
                return self[i] + remain * unit_dir, i
            accumulated += cur_edge_length

        # Fallback
        return self[-1], i

    def find_interpolated_point(self, pct_dist: float) -> NDArray:
        """Return a point along the curve at a relative distance pct_dist ∈ [0, 1]

        Parameters:
            pct_dist (float): Value in [0, 1], 0 returns start, 1 returns end.
                Any value in [0, 1] returns a point between start and end that is
                pct_dist along the path.

        Returns:
            NDArray: Interpolated point [x, y]
        """
        return self.find_interpolated_point_and_prev_ix(pct_dist)[0]

centroid property

Returns the center point that is within the linear spline. This means that this points necessarily belongs to the linear spline.

This can be useful when the centroid is not a good representation of what is needed as 'center'.

Returns:

Name Type Description
NDArray NDArray

point of shape (1, 2)

curvature property

Get the curvature of the linear spline as-if it had a well-defined curvature, meaning as-if it were a continuous curve.

Returns:

Name Type Description
float float

curvature value

midpoint property

Returns the center point that is within the linear spline. This means that this points necessarily belongs to the linear spline.

This can be useful when the centroid is not a good representation of what is needed as 'center'.

Returns:

Name Type Description
NDArray NDArray

point of shape (1, 2)

find_interpolated_point(pct_dist)

Return a point along the curve at a relative distance pct_dist ∈ [0, 1]

Parameters:

Name Type Description Default
pct_dist float

Value in [0, 1], 0 returns start, 1 returns end. Any value in [0, 1] returns a point between start and end that is pct_dist along the path.

required

Returns:

Name Type Description
NDArray NDArray

Interpolated point [x, y]

Source code in otary/geometry/discrete/linear/linear_spline.py
def find_interpolated_point(self, pct_dist: float) -> NDArray:
    """Return a point along the curve at a relative distance pct_dist ∈ [0, 1]

    Parameters:
        pct_dist (float): Value in [0, 1], 0 returns start, 1 returns end.
            Any value in [0, 1] returns a point between start and end that is
            pct_dist along the path.

    Returns:
        NDArray: Interpolated point [x, y]
    """
    return self.find_interpolated_point_and_prev_ix(pct_dist)[0]

find_interpolated_point_and_prev_ix(pct_dist)

Return a point along the curve at a relative distance pct_dist ∈ [0, 1]

Parameters:

Name Type Description Default
pct_dist float

Value in [0, 1], 0 returns start, 1 returns end. Any value in [0, 1] returns a point between start and end that is pct_dist along the path.

required

Returns:

Type Description
tuple[NDArray, int]

tuple[NDArray, int]: Interpolated point [x, y] and previous index in path.

Source code in otary/geometry/discrete/linear/linear_spline.py
def find_interpolated_point_and_prev_ix(
    self, pct_dist: float
) -> tuple[NDArray, int]:
    """Return a point along the curve at a relative distance pct_dist ∈ [0, 1]

    Parameters:
        pct_dist (float): Value in [0, 1], 0 returns start, 1 returns end.
            Any value in [0, 1] returns a point between start and end that is
            pct_dist along the path.

    Returns:
        tuple[NDArray, int]: Interpolated point [x, y] and previous index in path.
    """
    if not 0 <= pct_dist <= 1:
        raise ValueError("pct_dist must be in [0, 1]")

    if self.length == 0 or pct_dist == 0:
        return self[0], 0
    if pct_dist == 1:
        return self[-1], len(self) - 1

    # Walk along the path to find the point at pct_dist * total_dist
    target_dist = pct_dist * self.length
    accumulated = 0
    for i in range(len(self.edges)):
        cur_edge_length = self.lengths[i]
        if accumulated + cur_edge_length >= target_dist:
            remain = target_dist - accumulated
            direction = self[i + 1] - self[i]
            unit_dir = direction / cur_edge_length
            return self[i] + remain * unit_dir, i
        accumulated += cur_edge_length

    # Fallback
    return self[-1], i