Skip to main content

path_traits/transform/
reverse.rs

1//! Traverse a path in the reverse direction.
2//!
3//! [`Reverse`] wraps a path and samples it backwards: `sample_at(s)`
4//! delegates to `inner.sample_at(length - s)`. Tangent vectors are negated
5//! and (signed) curvature is negated.
6
7use crate::{Curved, Path, Point, Scalar, Tangent};
8
9/// A path traversed in the opposite direction.
10///
11/// Sampling at arc-length `s` returns the position the inner path would have
12/// at `length - s`. Tangent vectors are negated; signed curvature is negated.
13pub struct Reverse<P> {
14    /// The inner path being reversed.
15    inner: P,
16}
17
18impl<P> Reverse<P> {
19    /// Create a new reversed path.
20    pub fn new(inner: P) -> Self {
21        Self { inner }
22    }
23}
24
25impl<P: Path> Path for Reverse<P> {
26    type Scalar = P::Scalar;
27    type Point = P::Point;
28    type Error = P::Error;
29
30    fn length(&self) -> Self::Scalar {
31        self.inner.length()
32    }
33
34    fn sample_at(&self, s: Self::Scalar) -> Result<Self::Point, Self::Error> {
35        self.inner.sample_at(self.inner.length() - s)
36    }
37}
38
39impl<P: Tangent> Tangent for Reverse<P> {
40    fn tangent_at(&self, s: Self::Scalar) -> Result<<Self::Point as Point>::Vector, Self::Error> {
41        let t = self.inner.tangent_at(self.inner.length() - s)?;
42        let neg_one = P::Scalar::zero() - P::Scalar::one();
43        Ok(t * neg_one)
44    }
45}
46
47impl<P: Curved> Curved for Reverse<P>
48where
49    P::Curvature: core::ops::Neg<Output = P::Curvature>,
50{
51    type Curvature = P::Curvature;
52
53    fn curvature_at(&self, s: Self::Scalar) -> Result<Self::Curvature, Self::Error> {
54        let k = self.inner.curvature_at(self.inner.length() - s)?;
55        Ok(-k)
56    }
57}