spline: Use Skia's tolerance checks

This avoids measuring being too far off (it's still off, but it's less
than a percent now.
This commit is contained in:
Benjamin Otte
2020-11-25 02:18:34 +01:00
parent d84132824f
commit 51a1adf312
2 changed files with 25 additions and 5 deletions

View File

@@ -25,8 +25,8 @@
G_BEGIN_DECLS G_BEGIN_DECLS
/* Same as Cairo, so looks like a good value. ¯\_(ツ)_/¯ */ /* Same as Skia, so looks like a good value. ¯\_(ツ)_/¯ */
#define GSK_PATH_TOLERANCE_DEFAULT (0.1) #define GSK_PATH_TOLERANCE_DEFAULT (0.5)
gsize gsk_path_get_n_contours (GskPath *path); gsize gsk_path_get_n_contours (GskPath *path);
gboolean gsk_path_foreach_with_tolerance (GskPath *self, gboolean gsk_path_foreach_with_tolerance (GskPath *self,

View File

@@ -29,7 +29,7 @@ typedef struct
{ {
graphene_point_t last_point; graphene_point_t last_point;
float last_progress; float last_progress;
float tolerance_squared; float tolerance;
GskSplineAddPointFunc func; GskSplineAddPointFunc func;
gpointer user_data; gpointer user_data;
} GskCubicDecomposition; } GskCubicDecomposition;
@@ -103,6 +103,7 @@ gsk_spline_split_cubic (const graphene_point_t pts[4],
memcpy (result2, (graphene_point_t[4]) { final, bccd, cd, pts[3] }, sizeof (graphene_point_t[4])); memcpy (result2, (graphene_point_t[4]) { final, bccd, cd, pts[3] }, sizeof (graphene_point_t[4]));
} }
#if 0
/* Return an upper bound on the error (squared) that could result from /* Return an upper bound on the error (squared) that could result from
* approximating a spline as a line segment connecting the two endpoints. */ * approximating a spline as a line segment connecting the two endpoints. */
static float static float
@@ -180,6 +181,25 @@ gsk_spline_error_squared (const graphene_point_t pts[4])
else else
return cerr; return cerr;
} }
#endif
/* taken from Skia, including the very descriptive name */
static gboolean
gsk_spline_cubic_too_curvy (const graphene_point_t pts[4],
float tolerance)
{
graphene_point_t p;
graphene_point_interpolate (&pts[0], &pts[3], 1.0f / 3, &p);
if (ABS (p.x - pts[1].x) + ABS (p.y - pts[1].y) > tolerance)
return TRUE;
graphene_point_interpolate (&pts[0], &pts[3], 2.0f / 3, &p);
if (ABS (p.x - pts[2].x) + ABS (p.y - pts[2].y) > tolerance)
return TRUE;
return FALSE;
}
static void static void
gsk_spline_decompose_into (GskCubicDecomposition *decomp, gsk_spline_decompose_into (GskCubicDecomposition *decomp,
@@ -188,7 +208,7 @@ gsk_spline_decompose_into (GskCubicDecomposition *decomp,
{ {
graphene_point_t left[4], right[4]; graphene_point_t left[4], right[4];
if (gsk_spline_error_squared (pts) < decomp->tolerance_squared) if (!gsk_spline_cubic_too_curvy (pts, decomp->tolerance) || progress < 1 / 1024.f)
{ {
gsk_spline_decompose_add_point (decomp, &pts[3], progress); gsk_spline_decompose_add_point (decomp, &pts[3], progress);
return; return;
@@ -206,7 +226,7 @@ gsk_spline_decompose_cubic (const graphene_point_t pts[4],
GskSplineAddPointFunc add_point_func, GskSplineAddPointFunc add_point_func,
gpointer user_data) gpointer user_data)
{ {
GskCubicDecomposition decomp = { pts[0], 0.0f, tolerance * tolerance, add_point_func, user_data }; GskCubicDecomposition decomp = { pts[0], 0.0f, tolerance, add_point_func, user_data };
gsk_spline_decompose_into (&decomp, pts, 1.0f); gsk_spline_decompose_into (&decomp, pts, 1.0f);