diff options
Diffstat (limited to 'gsk/gskspline.c')
-rw-r--r-- | gsk/gskspline.c | 378 |
1 files changed, 0 insertions, 378 deletions
diff --git a/gsk/gskspline.c b/gsk/gskspline.c index 711226229c..5590c7f7e0 100644 --- a/gsk/gskspline.c +++ b/gsk/gskspline.c @@ -25,384 +25,6 @@ #include <math.h> -#define MIN_PROGRESS (1/1024.f) - -typedef struct -{ - graphene_point_t last_point; - float last_progress; - GskSplineAddPointFunc func; - gpointer user_data; -} GskSplineDecompose; - -static void -gsk_spline_decompose_add_point (GskSplineDecompose *decomp, - const graphene_point_t *pt, - float progress) -{ - if (graphene_point_equal (&decomp->last_point, pt)) - return; - - decomp->func (&decomp->last_point, pt, decomp->last_progress, decomp->last_progress + progress, decomp->user_data); - decomp->last_point = *pt; - decomp->last_progress += progress; -} - -static void -gsk_spline_decompose_finish (GskSplineDecompose *decomp, - const graphene_point_t *end_point) -{ - g_assert (graphene_point_equal (&decomp->last_point, end_point)); - g_assert (decomp->last_progress == 1.0f || decomp->last_progress == 0.0f); -} - -typedef struct -{ - GskSplineDecompose decomp; - float tolerance; -} GskCubicDecomposition; - -static void -gsk_spline_cubic_get_coefficients (graphene_point_t coeffs[4], - const graphene_point_t pts[4]) -{ - coeffs[0] = GRAPHENE_POINT_INIT (pts[3].x - 3.0f * pts[2].x + 3.0f * pts[1].x - pts[0].x, - pts[3].y - 3.0f * pts[2].y + 3.0f * pts[1].y - pts[0].y); - coeffs[1] = GRAPHENE_POINT_INIT (3.0f * pts[2].x - 6.0f * pts[1].x + 3.0f * pts[0].x, - 3.0f * pts[2].y - 6.0f * pts[1].y + 3.0f * pts[0].y); - coeffs[2] = GRAPHENE_POINT_INIT (3.0f * pts[1].x - 3.0f * pts[0].x, - 3.0f * pts[1].y - 3.0f * pts[0].y); - coeffs[3] = pts[0]; -} - -void -gsk_spline_get_point_cubic (const graphene_point_t pts[4], - float progress, - graphene_point_t *pos, - graphene_vec2_t *tangent) -{ - graphene_point_t c[4]; - - gsk_spline_cubic_get_coefficients (c, pts); - - if (pos) - *pos = GRAPHENE_POINT_INIT (((c[0].x * progress + c[1].x) * progress +c[2].x) * progress + c[3].x, - ((c[0].y * progress + c[1].y) * progress +c[2].y) * progress + c[3].y); - if (tangent) - { - graphene_vec2_init (tangent, - (3.0f * c[0].x * progress + 2.0f * c[1].x) * progress + c[2].x, - (3.0f * c[0].y * progress + 2.0f * c[1].y) * progress + c[2].y); - graphene_vec2_normalize (tangent, tangent); - } -} - -void -gsk_spline_split_cubic (const graphene_point_t pts[4], - graphene_point_t result1[4], - graphene_point_t result2[4], - float progress) -{ - graphene_point_t ab, bc, cd; - graphene_point_t abbc, bccd; - graphene_point_t final; - - graphene_point_interpolate (&pts[0], &pts[1], progress, &ab); - graphene_point_interpolate (&pts[1], &pts[2], progress, &bc); - graphene_point_interpolate (&pts[2], &pts[3], progress, &cd); - graphene_point_interpolate (&ab, &bc, progress, &abbc); - graphene_point_interpolate (&bc, &cd, progress, &bccd); - graphene_point_interpolate (&abbc, &bccd, progress, &final); - - memcpy (result1, (graphene_point_t[4]) { pts[0], ab, abbc, final }, 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 - * approximating a spline as a line segment connecting the two endpoints. */ -static float -gsk_spline_error_squared (const graphene_point_t pts[4]) -{ - float bdx, bdy, berr; - float cdx, cdy, cerr; - - /* We are going to compute the distance (squared) between each of the the b - * and c control points and the segment a-b. The maximum of these two - * distances will be our approximation error. */ - - bdx = pts[1].x - pts[0].x; - bdy = pts[1].y - pts[0].y; - - cdx = pts[2].x - pts[0].x; - cdy = pts[2].y - pts[0].y; - - if (!graphene_point_equal (&pts[0], &pts[3])) - { - float dx, dy, u, v; - - /* Intersection point (px): - * px = p1 + u(p2 - p1) - * (p - px) ∙ (p2 - p1) = 0 - * Thus: - * u = ((p - p1) ∙ (p2 - p1)) / ∥p2 - p1∥²; - */ - - dx = pts[3].x - pts[0].x; - dy = pts[3].y - pts[0].y; - v = dx * dx + dy * dy; - - u = bdx * dx + bdy * dy; - if (u <= 0) - { - /* bdx -= 0; - * bdy -= 0; - */ - } - else if (u >= v) - { - bdx -= dx; - bdy -= dy; - } - else - { - bdx -= u/v * dx; - bdy -= u/v * dy; - } - - u = cdx * dx + cdy * dy; - if (u <= 0) - { - /* cdx -= 0; - * cdy -= 0; - */ - } - else if (u >= v) - { - cdx -= dx; - cdy -= dy; - } - else - { - cdx -= u/v * dx; - cdy -= u/v * dy; - } - } - - berr = bdx * bdx + bdy * bdy; - cerr = cdx * cdx + cdy * cdy; - if (berr > cerr) - return berr; - else - 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 -gsk_spline_cubic_decompose (GskCubicDecomposition *d, - const graphene_point_t pts[4], - float progress) -{ - graphene_point_t left[4], right[4]; - - if (!gsk_spline_cubic_too_curvy (pts, d->tolerance) || progress < MIN_PROGRESS) - { - gsk_spline_decompose_add_point (&d->decomp, &pts[3], progress); - return; - } - - gsk_spline_split_cubic (pts, left, right, 0.5); - - gsk_spline_cubic_decompose (d, left, progress / 2); - gsk_spline_cubic_decompose (d, right, progress / 2); -} - -void -gsk_spline_decompose_cubic (const graphene_point_t pts[4], - float tolerance, - GskSplineAddPointFunc add_point_func, - gpointer user_data) -{ - GskCubicDecomposition decomp = { { pts[0], 0.0f, add_point_func, user_data }, tolerance }; - - gsk_spline_cubic_decompose (&decomp, pts, 1.0f); - - gsk_spline_decompose_finish (&decomp.decomp, &pts[3]); -} - -/* CONIC */ - -typedef struct { - graphene_point_t num[3]; - graphene_point_t denom[3]; -} ConicCoefficients; - -typedef struct -{ - GskSplineDecompose decomp; - float tolerance; - ConicCoefficients c; -} GskConicDecomposition; - - -static void -gsk_spline_conic_get_coefficents (ConicCoefficients *c, - const graphene_point_t pts[4]) -{ - float w = pts[2].x; - graphene_point_t pw = GRAPHENE_POINT_INIT (w * pts[1].x, w * pts[1].y); - - c->num[2] = pts[0]; - c->num[1] = GRAPHENE_POINT_INIT (2 * (pw.x - pts[0].x), - 2 * (pw.y - pts[0].y)); - c->num[0] = GRAPHENE_POINT_INIT (pts[3].x - 2 * pw.x + pts[0].x, - pts[3].y - 2 * pw.y + pts[0].y); - - c->denom[2] = GRAPHENE_POINT_INIT (1, 1); - c->denom[1] = GRAPHENE_POINT_INIT (2 * (w - 1), 2 * (w - 1)); - c->denom[0] = GRAPHENE_POINT_INIT (-c->denom[1].x, -c->denom[1].y); -} - -static inline void -gsk_spline_eval_quad (const graphene_point_t quad[3], - float progress, - graphene_point_t *result) -{ - *result = GRAPHENE_POINT_INIT ((quad[0].x * progress + quad[1].x) * progress + quad[2].x, - (quad[0].y * progress + quad[1].y) * progress + quad[2].y); -} - -static inline void -gsk_spline_eval_conic (const ConicCoefficients *c, - float progress, - graphene_point_t *result) -{ - graphene_point_t num, denom; - - gsk_spline_eval_quad (c->num, progress, &num); - gsk_spline_eval_quad (c->denom, progress, &denom); - *result = GRAPHENE_POINT_INIT (num.x / denom.x, num.y / denom.y); -} - -void -gsk_spline_get_point_conic (const graphene_point_t pts[4], - float progress, - graphene_point_t *pos, - graphene_vec2_t *tangent) -{ - ConicCoefficients c; - - gsk_spline_conic_get_coefficents (&c, pts); - - if (pos) - gsk_spline_eval_conic (&c, progress, pos); - - if (tangent) - { - graphene_point_t tmp; - float w = pts[2].x; - - /* The tangent will be 0 in these corner cases, just - * treat it like a line here. */ - if ((progress <= 0.f && graphene_point_equal (&pts[0], &pts[1])) || - (progress >= 1.f && graphene_point_equal (&pts[1], &pts[3]))) - { - graphene_vec2_init (tangent, pts[3].x - pts[0].x, pts[3].y - pts[0].y); - return; - } - - gsk_spline_eval_quad ((graphene_point_t[3]) { - GRAPHENE_POINT_INIT ((w - 1) * (pts[3].x - pts[0].x), - (w - 1) * (pts[3].y - pts[0].y)), - GRAPHENE_POINT_INIT (pts[3].x - pts[0].x - 2 * w * (pts[1].x - pts[0].x), - pts[3].y - pts[0].y - 2 * w * (pts[1].y - pts[0].y)), - GRAPHENE_POINT_INIT (w * (pts[1].x - pts[0].x), - w * (pts[1].y - pts[0].y)) - }, - progress, - &tmp); - graphene_vec2_init (tangent, tmp.x, tmp.y); - graphene_vec2_normalize (tangent, tangent); - } -} - -void -gsk_spline_split_conic (const graphene_point_t pts[4], - graphene_point_t result1[4], - graphene_point_t result2[4], - float progress) -{ - g_warning ("FIXME: Stop treating conics as lines"); -} - -/* taken from Skia, including the very descriptive name */ -static gboolean -gsk_spline_conic_too_curvy (const graphene_point_t *start, - const graphene_point_t *mid, - const graphene_point_t *end, - float tolerance) -{ - return fabs ((start->x + end->x) * 0.5 - mid->x) > tolerance - || fabs ((start->y + end->y) * 0.5 - mid->y) > tolerance; -} - -static void -gsk_spline_decompose_conic_subdivide (GskConicDecomposition *d, - const graphene_point_t *start, - float start_progress, - const graphene_point_t *end, - float end_progress) -{ - graphene_point_t mid; - float mid_progress; - - mid_progress = (start_progress + end_progress) / 2; - gsk_spline_eval_conic (&d->c, mid_progress, &mid); - - if (end_progress - start_progress < MIN_PROGRESS || - !gsk_spline_conic_too_curvy (start, &mid, end, d->tolerance)) - { - gsk_spline_decompose_add_point (&d->decomp, end, end_progress - start_progress); - return; - } - - gsk_spline_decompose_conic_subdivide (d, start, start_progress, &mid, mid_progress); - gsk_spline_decompose_conic_subdivide (d, &mid, mid_progress, end, end_progress); -} - -void -gsk_spline_decompose_conic (const graphene_point_t pts[4], - float tolerance, - GskSplineAddPointFunc add_point_func, - gpointer user_data) -{ - GskConicDecomposition d = { { pts[0], 0.0f, add_point_func, user_data }, tolerance, }; - - gsk_spline_conic_get_coefficents (&d.c, pts); - - gsk_spline_decompose_conic_subdivide (&d, &pts[0], 0.0f, &pts[3], 1.0f); - - gsk_spline_decompose_finish (&d.decomp, &pts[3]); -} - /* Spline deviation from the circle in radius would be given by: error = sqrt (x**2 + y**2) - 1 |