bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Cyclic splines

Open mweatherley opened this issue 7 months ago • 0 comments

Objective

Fill a gap in the functionality of our curve constructions by allowing users to easily build cyclic curves from control data.

Solution

Here I opted for something lightweight and discoverable. There is a new CyclicCubicGenerator trait with a method to_curve_cyclic which uses splines' control data to create curves that are cyclic. For now, its signature is exactly like that of CubicGeneratorto_curve_cyclic just yields a CubicCurve:

/// Implement this on cubic splines that can generate a cyclic cubic curve from their spline parameters.
///
/// This makes sense only when the control data can be interpreted cyclically.
pub trait CyclicCubicGenerator<P: VectorSpace> {
    /// Build a cyclic [`CubicCurve`] by computing the interpolation coefficients for each curve segment.
    fn to_curve_cyclic(&self) -> CubicCurve<P>;
}

This trait has been implemented for CubicHermite, CubicCardinalSpline, CubicBSpline, and LinearSpline:

Screenshot 2024-07-01 at 8 58 27 PM Screenshot 2024-07-01 at 9 00 14 PM Screenshot 2024-07-01 at 8 59 36 PM Screenshot 2024-07-01 at 8 59 01 PM

(Each type pictured respectively with the control points rendered as green spheres; tangents not pictured in the case of the Hermite spline.)

These curves are all parametrized so that the output of to_curve and the output of to_curve_cyclic are similar. For instance, in CubicCardinalSpline, the first output segment is a curve segment joining the first and second control points in each, although it is constructed differently. In the other cases, the segments from to_curve are a subset of those in to_curve_cyclic, with the new segments appearing at the end.

Testing

I rendered cyclic splines from control data and made sure they looked reasonable. Existing tests are intact for splines where previous code was modified. (Note that the coefficient computation for cyclic spline segments is almost verbatim identical to that of their non-cyclic counterparts.)

The Bezier benchmarks also look fine.


Changelog

  • Added CyclicCubicGenerator trait to bevy_math::cubic_splines for creating cyclic curves from control data.
  • Implemented CyclicCubicGenerator for CubicHermite, CubicCardinalSpline, CubicBSpline, and LinearSpline.
  • bevy_math now depends on itertools.

Discussion

Design decisions

The biggest thing here is just the approach taken in the first place: namely, the cyclic constructions use new methods on the same old structs. This choice was made to reduce friction and increase discoverability but also because creating new ones just seemed unnecessary: the underlying data would have been the same, so creating something like "CyclicCubicBSpline" whose internally-held control data is regarded as cyclic in nature doesn't really accomplish much — the end result for the user is basically the same either way.

Similarly, I don't presently see a pressing need for to_curve_cyclic to output something other than a CubicCurve, although changing this in the future may be useful. See below.

A notable omission here is that CyclicCubicGenerator is not implemented for CubicBezier. This is not a gap waiting to be filled — CubicBezier just doesn't have enough data to join its start with its end without just making up the requisite control points wholesale. In all the cases where CyclicCubicGenerator has been implemented here, the fashion in which the ends are connected is quite natural and follows the semantics of the associated spline construction.

Future direction

There are two main things here:

  1. We should investigate whether we should do something similar for NURBS. I just don't know that much about NURBS at the moment, so I regarded this as out of scope for the PR.
  2. We may eventually want to change the output type of CyclicCubicGenerator::to_curve_cyclic to a type which reifies the cyclic nature of the curve output. This wasn't done in this PR because I'm unsure how much value a type-level guarantee of cyclicity actually has, but if some useful features make sense only in the case of cyclic curves, this might be worth pursuing.

mweatherley avatar Jul 02 '24 10:07 mweatherley