Skip to content

Curve extrapolation for curves which can be extrapolated #20028

@laundmo

Description

@laundmo

What problem does this solve or what need does it fill?

Currently, there are few ways to make a Curve trait implementor continue beyond its domain. This is especially apparent for SampleCurve/UnevenSampleCurve. For example, when using a simple lerp(a, b, t) to interpolate, theres no reason i couldn't extrapolate by providing a t > 1.0 or t < 0.0, and this can be very useful in some cases.

For example, this curve would translate something along a V shape:

UnevenSampleCurve::new(
  vec![
    (0.0, Vec2::new(1.0, 0.0)),
    (0.5, Vec2::new(0.0, 1.0)),
    (1.0, Vec2::new(1.0, 2.0))
  ],
  |a, b, t| a.lerp(*b, t)
)

Its perfectly valid to extrapolate this in both directions infiniteley (making a larger/infinite V shape, in this case) but i can't find a builtin way to encode this in the Curve itself. The domain is 0.0..=1.0 and i can't find a way to change that which leads to the behaviour i'm looking for.

What solution would you like?

I would like some way which allows me to get a infinite domain curve for all curves where extrapolation can make sense. Lerp is the most obvious extrapolate-able example, but bezier curves, for example, are also fine to extrapolate.

I think ideally this should be a wrapper struct, like the various ones returned by ChainExt methods. This would allow passing it to external code which calls .sample(t) more easily.

What alternative(s) have you considered?

  • Curve::sample_unchecked explicitly documents i can't use it for this (quote: "extrapolation beyond a curves domain should not be relied upon"). If that documentation is changed, external code may need to be updated to use sample_unchecked to allow for infinite domain curves. Also, would make it harder to prevent extrapolation for curves which can't/shouldn't be extrapolated.

Additional context

A related feature to consider along with this is some way to cutoff and chain curves with infinite domains. Similar to CurveExt::chain, i would propose CurveExt::chain_atwith an extratargument which defines the cutoff point. This could be implemented by having a wrapper struct, similar to the one i've proposed above, which overrides their domain to end at a specific value (which would make the implementation ofchain_atsomething like this:RightCutoff::new(my_curve, t).chain(LeftCutoff(t, my_other_curve))`).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-MathFundamental domain-agnostic mathematical operationsC-FeatureA new feature, making something new possible

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions