pub trait CurveExt<T>: Sized + Curve<T> {
Show 18 methods
// Provided methods
fn sample_iter(
&self,
iter: impl IntoIterator<Item = f32>,
) -> impl Iterator<Item = Option<T>> { ... }
fn sample_iter_unchecked(
&self,
iter: impl IntoIterator<Item = f32>,
) -> impl Iterator<Item = T> { ... }
fn sample_iter_clamped(
&self,
iter: impl IntoIterator<Item = f32>,
) -> impl Iterator<Item = T> { ... }
fn map<S, F>(self, f: F) -> MapCurve<T, S, Self, F>
where F: Fn(T) -> S { ... }
fn reparametrize<F>(
self,
domain: Interval,
f: F,
) -> ReparamCurve<T, Self, F>
where F: Fn(f32) -> f32 { ... }
fn reparametrize_linear(
self,
domain: Interval,
) -> Result<LinearReparamCurve<T, Self>, LinearReparamError> { ... }
fn reparametrize_by_curve<C>(
self,
other: C,
) -> CurveReparamCurve<T, Self, C>
where C: Curve<f32> { ... }
fn graph(self) -> GraphCurve<T, Self> { ... }
fn zip<S, C>(
self,
other: C,
) -> Result<ZipCurve<T, S, Self, C>, InvalidIntervalError>
where C: Curve<S> { ... }
fn chain<C>(self, other: C) -> Result<ChainCurve<T, Self, C>, ChainError>
where C: Curve<T> { ... }
fn reverse(self) -> Result<ReverseCurve<T, Self>, ReverseError> { ... }
fn repeat(self, count: usize) -> Result<RepeatCurve<T, Self>, RepeatError> { ... }
fn forever(self) -> Result<ForeverCurve<T, Self>, RepeatError> { ... }
fn ping_pong(self) -> Result<PingPongCurve<T, Self>, PingPongError> { ... }
fn chain_continue<C>(
self,
other: C,
) -> Result<ContinuationCurve<T, Self, C>, ChainError>
where T: VectorSpace,
C: Curve<T> { ... }
fn samples(
&self,
samples: usize,
) -> Result<impl Iterator<Item = T>, ResamplingError> { ... }
fn by_ref(&self) -> &Self { ... }
fn flip<U, V>(self) -> impl Curve<(V, U)>
where Self: CurveExt<(U, V)> { ... }
}
Expand description
Extension trait implemented by curves, allowing access to a number of adaptors and convenience methods.
This trait is automatically implemented for all curves that are Sized
. In particular,
it is implemented for types like Box<dyn Curve<T>>
. CurveExt
is not dyn-compatible
itself.
For more information, see the module-level documentation.
Provided Methods§
Sourcefn sample_iter(
&self,
iter: impl IntoIterator<Item = f32>,
) -> impl Iterator<Item = Option<T>>
fn sample_iter( &self, iter: impl IntoIterator<Item = f32>, ) -> impl Iterator<Item = Option<T>>
Sample a collection of n >= 0
points on this curve at the parameter values t_n
,
returning None
if the point is outside of the curve’s domain.
The samples are returned in the same order as the parameter values t_n
were provided and
will include all results. This leaves the responsibility for things like filtering and
sorting to the user for maximum flexibility.
Sourcefn sample_iter_unchecked(
&self,
iter: impl IntoIterator<Item = f32>,
) -> impl Iterator<Item = T>
fn sample_iter_unchecked( &self, iter: impl IntoIterator<Item = f32>, ) -> impl Iterator<Item = T>
Sample a collection of n >= 0
points on this curve at the parameter values t_n
,
extracting the associated values. This is the unchecked version of sampling, which should
only be used if the sample times t_n
are already known to lie within the curve’s domain.
Values sampled from outside of a curve’s domain are generally considered invalid; data which is nonsensical or otherwise useless may be returned in such a circumstance, and extrapolation beyond a curve’s domain should not be relied upon.
The samples are returned in the same order as the parameter values t_n
were provided and
will include all results. This leaves the responsibility for things like filtering and
sorting to the user for maximum flexibility.
Sourcefn sample_iter_clamped(
&self,
iter: impl IntoIterator<Item = f32>,
) -> impl Iterator<Item = T>
fn sample_iter_clamped( &self, iter: impl IntoIterator<Item = f32>, ) -> impl Iterator<Item = T>
Sample a collection of n >= 0
points on this curve at the parameter values t_n
,
clamping t_n
to lie inside the domain of the curve.
The samples are returned in the same order as the parameter values t_n
were provided and
will include all results. This leaves the responsibility for things like filtering and
sorting to the user for maximum flexibility.
Sourcefn map<S, F>(self, f: F) -> MapCurve<T, S, Self, F>where
F: Fn(T) -> S,
fn map<S, F>(self, f: F) -> MapCurve<T, S, Self, F>where
F: Fn(T) -> S,
Create a new curve by mapping the values of this curve via a function f
; i.e., if the
sample at time t
for this curve is x
, the value at time t
on the new curve will be
f(x)
.
Sourcefn reparametrize<F>(self, domain: Interval, f: F) -> ReparamCurve<T, Self, F>
fn reparametrize<F>(self, domain: Interval, f: F) -> ReparamCurve<T, Self, F>
Create a new Curve
whose parameter space is related to the parameter space of this curve
by f
. For each time t
, the sample from the new curve at time t
is the sample from
this curve at time f(t)
. The given domain
will be the domain of the new curve. The
function f
is expected to take domain
into self.domain()
.
Note that this is the opposite of what one might expect intuitively; for example, if this
curve has a parameter domain of [0, 1]
, then stretching the parameter domain to
[0, 2]
would be performed as follows, dividing by what might be perceived as the scaling
factor rather than multiplying:
let my_curve = ConstantCurve::new(Interval::UNIT, 1.0);
let scaled_curve = my_curve.reparametrize(interval(0.0, 2.0).unwrap(), |t| t / 2.0);
This kind of linear remapping is provided by the convenience method
CurveExt::reparametrize_linear
, which requires only the desired domain for the new curve.
§Examples
// Reverse a curve:
let my_curve = ConstantCurve::new(Interval::UNIT, 1.0);
let domain = my_curve.domain();
let reversed_curve = my_curve.reparametrize(domain, |t| domain.end() - (t - domain.start()));
// Take a segment of a curve:
let curve_segment = my_curve.reparametrize(interval(0.0, 0.5).unwrap(), |t| 0.5 + t);
Sourcefn reparametrize_linear(
self,
domain: Interval,
) -> Result<LinearReparamCurve<T, Self>, LinearReparamError>
fn reparametrize_linear( self, domain: Interval, ) -> Result<LinearReparamCurve<T, Self>, LinearReparamError>
Sourcefn reparametrize_by_curve<C>(self, other: C) -> CurveReparamCurve<T, Self, C>
fn reparametrize_by_curve<C>(self, other: C) -> CurveReparamCurve<T, Self, C>
Reparametrize this Curve
by sampling from another curve.
The resulting curve samples at time t
by first sampling other
at time t
, which produces
another sample time s
which is then used to sample this curve. The domain of the resulting
curve is the domain of other
.
Sourcefn graph(self) -> GraphCurve<T, Self>
fn graph(self) -> GraphCurve<T, Self>
Create a new Curve
which is the graph of this one; that is, its output echoes the sample
time as part of a tuple.
For example, if this curve outputs x
at time t
, then the produced curve will produce
(t, x)
at time t
. In particular, if this curve is a Curve<T>
, the output of this method
is a Curve<(f32, T)>
.
Sourcefn zip<S, C>(
self,
other: C,
) -> Result<ZipCurve<T, S, Self, C>, InvalidIntervalError>where
C: Curve<S>,
fn zip<S, C>(
self,
other: C,
) -> Result<ZipCurve<T, S, Self, C>, InvalidIntervalError>where
C: Curve<S>,
Create a new Curve
by zipping this curve together with another.
The sample at time t
in the new curve is (x, y)
, where x
is the sample of self
at
time t
and y
is the sample of other
at time t
. The domain of the new curve is the
intersection of the domains of its constituents.
§Errors
If the domain intersection would be empty, an error is returned instead.
Sourcefn chain<C>(self, other: C) -> Result<ChainCurve<T, Self, C>, ChainError>where
C: Curve<T>,
fn chain<C>(self, other: C) -> Result<ChainCurve<T, Self, C>, ChainError>where
C: Curve<T>,
Create a new Curve
by composing this curve end-to-start with another, producing another curve
with outputs of the same type. The domain of the other curve is translated so that its start
coincides with where this curve ends.
§Errors
A ChainError
is returned if this curve’s domain doesn’t have a finite end or if
other
’s domain doesn’t have a finite start.
Sourcefn reverse(self) -> Result<ReverseCurve<T, Self>, ReverseError>
fn reverse(self) -> Result<ReverseCurve<T, Self>, ReverseError>
Create a new Curve
inverting this curve on the x-axis, producing another curve with
outputs of the same type, effectively playing backwards starting at self.domain().end()
and transitioning over to self.domain().start()
. The domain of the new curve is still the
same.
§Errors
A ReverseError
is returned if this curve’s domain isn’t bounded.
Sourcefn repeat(self, count: usize) -> Result<RepeatCurve<T, Self>, RepeatError>
fn repeat(self, count: usize) -> Result<RepeatCurve<T, Self>, RepeatError>
Create a new Curve
repeating this curve N
times, producing another curve with outputs
of the same type. The domain of the new curve will be bigger by a factor of n + 1
.
§Notes
- this doesn’t guarantee a smooth transition from one occurrence of the curve to its next
iteration. The curve will make a jump if
self.domain().start() != self.domain().end()
! - for
count == 0
the output of this adaptor is basically identical to the previous curve - the value at the transitioning points (
domain.end() * n
forn >= 1
) in the results is the value atdomain.end()
in the original curve
§Errors
A RepeatError
is returned if this curve’s domain isn’t bounded.
Sourcefn forever(self) -> Result<ForeverCurve<T, Self>, RepeatError>
fn forever(self) -> Result<ForeverCurve<T, Self>, RepeatError>
Create a new Curve
repeating this curve forever, producing another curve with
outputs of the same type. The domain of the new curve will be unbounded.
§Notes
- this doesn’t guarantee a smooth transition from one occurrence of the curve to its next
iteration. The curve will make a jump if
self.domain().start() != self.domain().end()
! - the value at the transitioning points (
domain.end() * n
forn >= 1
) in the results is the value atdomain.end()
in the original curve
§Errors
A RepeatError
is returned if this curve’s domain isn’t bounded.
Sourcefn ping_pong(self) -> Result<PingPongCurve<T, Self>, PingPongError>
fn ping_pong(self) -> Result<PingPongCurve<T, Self>, PingPongError>
Create a new Curve
chaining the original curve with its inverse, producing
another curve with outputs of the same type. The domain of the new curve will be twice as
long. The transition point is guaranteed to not make any jumps.
§Errors
A PingPongError
is returned if this curve’s domain isn’t right-finite.
Sourcefn chain_continue<C>(
self,
other: C,
) -> Result<ContinuationCurve<T, Self, C>, ChainError>where
T: VectorSpace,
C: Curve<T>,
fn chain_continue<C>(
self,
other: C,
) -> Result<ContinuationCurve<T, Self, C>, ChainError>where
T: VectorSpace,
C: Curve<T>,
Create a new Curve
by composing this curve end-to-start with another, producing another
curve with outputs of the same type. The domain of the other curve is translated so that
its start coincides with where this curve ends.
Additionally the transition of the samples is guaranteed to make no sudden jumps. This is useful if you really just know about the shapes of your curves and don’t want to deal with stitching them together properly when it would just introduce useless complexity. It is realized by translating the other curve so that its start sample point coincides with the current curves’ end sample point.
§Errors
A ChainError
is returned if this curve’s domain doesn’t have a finite end or if
other
’s domain doesn’t have a finite start.
Sourcefn samples(
&self,
samples: usize,
) -> Result<impl Iterator<Item = T>, ResamplingError>
fn samples( &self, samples: usize, ) -> Result<impl Iterator<Item = T>, ResamplingError>
Extract an iterator over evenly-spaced samples from this curve.
§Errors
If samples
is less than 2 or if this curve has unbounded domain, a ResamplingError
is returned.
Sourcefn by_ref(&self) -> &Self
fn by_ref(&self) -> &Self
Borrow this curve rather than taking ownership of it. This is essentially an alias for a
prefix &
; the point is that intermediate operations can be performed while retaining
access to the original curve.
§Example
let my_curve = FunctionCurve::new(Interval::UNIT, |t| t * t + 1.0);
// Borrow `my_curve` long enough to resample a mapped version. Note that `map` takes
// ownership of its input.
let samples = my_curve.by_ref().map(|x| x * 2.0).resample_auto(100).unwrap();
// Do something else with `my_curve` since we retained ownership:
let new_curve = my_curve.reparametrize_linear(interval(-1.0, 1.0).unwrap()).unwrap();
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.