path_traits/path.rs
1//! Core traits for parametric curves.
2//!
3//! This module defines the two foundational traits of the crate:
4//!
5//! - [`Path`] - the core trait for arc-length-parameterized curves. It requires
6//! `length()`, `sample_at(s)`, and provides `start()`, `end()`, `domain()`.
7//! - [`ParametricPath`] - extends [`Path`] with normalized-parameter sampling
8//! `sample_t(t) ∈ [0, 1]`, plus conversion helpers `t_to_s` / `s_to_t`.
9
10use crate::PathError;
11use crate::Point;
12use crate::Scalar;
13
14/// A curve that can be sampled by arc-length `s`.
15///
16/// Every path has a total `length`, and `sample_at(s)` returns a [`Point`](crate::Point)
17/// for `s ∈ [0, length]`. The trait provides convenience methods `start()`, `end()`,
18/// and `domain()`.
19pub trait Path {
20 /// The scalar type for arc-length, parameter, and distance computations.
21 type Scalar: Scalar;
22 /// The point type representing positions on the path.
23 type Point: Point<Scalar = Self::Scalar>;
24 /// The error type for fallible operations. Must be convertible from [`PathError<Self::Scalar>`].
25 type Error: From<PathError<Self::Scalar>>;
26
27 /// Total arc-length of the path.
28 fn length(&self) -> Self::Scalar;
29
30 /// Sample the path at arc-length `s ∈ [0, length]`.
31 ///
32 /// Returns an error when `s` is outside the valid domain.
33 fn sample_at(&self, s: Self::Scalar) -> Result<Self::Point, Self::Error>;
34
35 /// The start point of the path, equivalent to `sample_at(0)`.
36 fn start(&self) -> Result<Self::Point, Self::Error> {
37 self.sample_at(Self::Scalar::zero())
38 }
39
40 /// The end point of the path, equivalent to `sample_at(length)`.
41 fn end(&self) -> Result<Self::Point, Self::Error> {
42 self.sample_at(self.length())
43 }
44
45 /// The valid domain for arc-length sampling: `[0, length]`.
46 fn domain(&self) -> core::ops::RangeInclusive<Self::Scalar> {
47 Self::Scalar::zero()..=self.length()
48 }
49}
50
51/// A curve that also supports sampling by a normalized parameter `t ∈ [0, 1]`.
52///
53/// Extends [`Path`] with `sample_t(t)`. Default implementations of `t_to_s` and
54/// `s_to_t` use linear conversion (`s = t * length`), which is exact only for
55/// arc-length-parameterized paths. Implementers may override these for exact
56/// conversions.
57pub trait ParametricPath: Path {
58 /// Sample the path at normalized parameter `t ∈ [0, 1]`.
59 ///
60 /// Returns an error when `t` is outside the valid domain.
61 fn sample_t(&self, t: Self::Scalar) -> Result<Self::Point, Self::Error>;
62
63 /// Convert normalized parameter `t` to arc-length `s`.
64 ///
65 /// Default: `t * length()`. Override for exact conversions.
66 fn t_to_s(&self, t: Self::Scalar) -> Self::Scalar {
67 t * self.length()
68 }
69
70 /// Convert arc-length `s` to normalized parameter `t`.
71 ///
72 /// Default: `s / length()`. Override for exact conversions.
73 fn s_to_t(&self, s: Self::Scalar) -> Self::Scalar {
74 s / self.length()
75 }
76}