flo_curves icon indicating copy to clipboard operation
flo_curves copied to clipboard

A version of fit_curve_cubic that is gaurunteed to return only one curve.

Open MatthewBlanchard opened this issue 3 years ago • 1 comments
trafficstars


pub fn fit_curve_cubic<Curve: BezierCurveFactory+BezierCurve>(points: &[Curve::Point], start_tangent: &Curve::Point, end_tangent: &Curve::Point, iterations: u32) -> Vec<Curve> {
    if points.len() <= 2 {
        // 2 points is a line (less than 2 points is an error here)
        fit_line(&points[0], &points[1])
    } else {
        // Perform an initial estimate of the 't' values corresponding to the chords of the curve
        let mut chords                  = chords_for_points(points);

        // Use the least-squares method to fit against the initial set of chords
        let mut curve                   = generate_bezier(points, &chords, start_tangent, end_tangent);

        // Reparameterise the chords (which will probably be quite a bad estimate initially)
        chords                          = reparameterize(points, &chords, &curve);
        curve                           = generate_bezier(points, &chords, start_tangent, end_tangent);

        // Estimate the error after the reparameterization
        let (mut error, mut split_pos)  = max_error_for_curve(points, &chords, &curve);

        // Try iterating to improve the fit if we're not too far out
        for _iteration in 1..iterations {
            // Recompute the chords and the curve
            chords = reparameterize(points, &chords, &curve);
            curve  = generate_bezier(points, &chords, start_tangent, end_tangent);
        }
    }
}

Would something like this work? The code above is completely untested napkin code. Right now I'm using fit_cubic_curve and just raising the max_error until it returns only one curve, but I'd rather be able to give it a static number of iterations and do less spinning.

I'm willing to work on this myself if you give me the greenlight.

MatthewBlanchard avatar Sep 26 '22 18:09 MatthewBlanchard

I'm happy for you to work on this.

Yes, this would work: this section of the original does exactly what you want here. I think this would need to be a separate function, and it could potentially be re-used by the existing function if it didn't try to short-circuit the iterations when the error gets low enough (thinking about it, I'm not sure if short-circuiting actually saves any time given the need to calculate the error every iteration).

You might want to experiment to see if the iteration parameter is actually useful - the algorithm should minimize the error in the curve pretty quickly, so if the default value of 4 might be all that's required. It's quite hard to explain to a caller what values are a good choice for this parameter.

Logicalshift avatar Oct 04 '22 08:10 Logicalshift