Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
MatthewBlanchard opened this issue Sep 26, 2022 · 1 comment

Comments

@MatthewBlanchard
Copy link

MatthewBlanchard commented Sep 26, 2022

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.

@Logicalshift
Copy link
Owner

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants