Skip to main content

path_traits/transform/
offset.rs

1//! Offset a path by a constant distance.
2//!
3//! [`Offset`] wraps a path and displaces every sampled point by a fixed
4//! distance. Requires the inner path to implement
5//! [`Tangent`](crate::Tangent) and [`Heading`](crate::Heading).
6
7use crate::{Heading, Path, Point, Tangent};
8
9/// A path displaced by a constant distance from the original.
10///
11/// Every sampled point is shifted by `distance` units. The offset direction
12/// is derived from the path's heading; in 2D this produces a parallel curve.
13///
14/// **Note:** The current implementation offsets along the tangent direction as
15/// a placeholder. A proper 2D-specific implementation should offset along the
16/// surface normal (heading + π/2).
17pub struct Offset<P, S> {
18    /// The inner path being offset.
19    inner: P,
20    /// The constant offset distance.
21    distance: S,
22}
23
24impl<P, S> Offset<P, S> {
25    /// Create a new offset path.
26    ///
27    /// The `distance` is in the same units as the path's scalar type.
28    pub fn new(inner: P, distance: S) -> Self {
29        Self { inner, distance }
30    }
31}
32
33impl<P: Path + Tangent + Heading> Path for Offset<P, P::Scalar> {
34    type Scalar = P::Scalar;
35    type Point = P::Point;
36    type Error = P::Error;
37
38    fn length(&self) -> Self::Scalar {
39        self.inner.length()
40    }
41
42    fn sample_at(&self, s: Self::Scalar) -> Result<Self::Point, Self::Error> {
43        let pos = self.inner.sample_at(s)?;
44        let tan = self.inner.tangent_at(s)?;
45        let offset_vec = tan * self.distance;
46        Ok(pos.translate(offset_vec))
47    }
48}