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

Better cubic to quadratic #235

Open
rsheeter opened this issue Mar 2, 2023 · 3 comments
Open

Better cubic to quadratic #235

rsheeter opened this issue Mar 2, 2023 · 3 comments
Labels
needs discussion This change requires some more discussion before we decide we definitely want it performance This issue suggests an improvement to either the time performance or accuracy of an algorithm

Comments

@rsheeter
Copy link
Collaborator

rsheeter commented Mar 2, 2023

https://docs.rs/kurbo/latest/kurbo/fn.cubics_to_quadratic_splines.html, added in #193 as a port of https://github.com/fonttools/fonttools/tree/main/Lib/fontTools/cu2qu, allows us to convert a set of cubics to an interpolation compatible quadratic b-spline. This is invaluable in font compilation of variable fonts that use cubic sources as the https://learn.microsoft.com/en-us/typography/opentype/spec/glyf table currently only supports quadratics.

Per discussion with @raphlinus, we could improve on the current algorithm:

  • Conversion from curve → quad b-spline is similar flattening
    • So, the density of points you need to retain is proportional to cube root of curvature
  • An optimal cu2qu would be looking at the cube root of curvature along the curve and evenly sampling, and that will determine how to split things up.
  • This would take two steps
    1. How many quads do we need? - based on cube root of curvature as above
    2. Fit N quads to the cubic, much as cu2qu does already

The improved version would be expected to outdo cu2qu for S curves and cases where there's an extremely highly curved region, e.g. the notch under a ball at the end of a font shape.

A better cu2qu would be of immediate value to https://github.com/googlefonts/fontmake-rs.

@behdad
Copy link

behdad commented Mar 2, 2023

The reason cu2qu works the way it is, is that it wouldn't need to encode any of the interior on-curve points.

So to beat it with non-uniform t values, you need to be able to use ~half the quads, which I have a hard time imagining you can do. You will only start seeing benefits if for a curve that cu2qu uses 5 quad segments, you can use 2 segments...

@derekdreery derekdreery added needs discussion This change requires some more discussion before we decide we definitely want it performance This issue suggests an improvement to either the time performance or accuracy of an algorithm labels Mar 18, 2023
@ctrlcctrlv
Copy link

Why not cucoqu?

@ctrlcctrlv
Copy link

I based cucoqu heavily on Skia's converter, so it is your optimal solution.

https://github.com/MFEK/cucoqu.rlib/blob/main/src/cu2qu/mod.rs

impl CurvesToQuadratic for Vec<Cubic> {
    fn curves_to_quadratic(&self, max_errors: Vec<f32>) -> Result<Vec<QuadSpline>, ApproxNotFoundError> {
        debug_assert_eq!(self.len(), max_errors.len());
        let l = self.len();
        let mut splines = vec![None; l];
        let mut last_i = 0;
        let mut i = 0;
        let mut n = 1;
        loop {
            let test_spline = self[i].approx_spline(n, max_errors[i]);
            if let Err(_) = test_spline {
                if n == MAX_N {
                    break;
                };
                n += 1;
                last_i = i;
                continue;
            }
            splines[i] = match test_spline {
                Ok(a) => Some(a),
                Err(e) => return Err(e),
            };
            i = (i + 1) % l;
            if i == last_i {
                //done
                return Ok(splines.into_iter().map(|maybe| maybe.expect("Should not get a None")).collect());
            }
        }
        Err(ApproxNotFoundError)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs discussion This change requires some more discussion before we decide we definitely want it performance This issue suggests an improvement to either the time performance or accuracy of an algorithm
Projects
None yet
Development

No branches or pull requests

4 participants