Change curve derivative api
We don't need to have the derivative as a curve, it is enough for us to compute values of the derivative at a given t, which we can also do for conics.
This commit is contained in:
143
gsk/gskcurve.c
143
gsk/gskcurve.c
@@ -77,8 +77,9 @@ struct _GskCurveClass
|
||||
GskBoundingBox *bounds);
|
||||
void (* get_tight_bounds) (const GskCurve *curve,
|
||||
GskBoundingBox *bounds);
|
||||
void (* get_derivative) (const GskCurve *curve,
|
||||
GskCurve *derivative);
|
||||
void (* get_derivative_at) (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *value);
|
||||
int (* get_crossing) (const GskCurve *curve,
|
||||
const graphene_point_t *point);
|
||||
};
|
||||
@@ -366,16 +367,14 @@ gsk_line_curve_get_bounds (const GskCurve *curve,
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_line_curve_get_derivative (const GskCurve *curve,
|
||||
GskCurve *deriv)
|
||||
gsk_line_curve_get_derivative_at (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *value)
|
||||
{
|
||||
const GskLineCurve *self = &curve->line;
|
||||
graphene_point_t p;
|
||||
|
||||
p.x = self->points[1].x - self->points[0].x;
|
||||
p.y = self->points[1].y - self->points[0].y;
|
||||
|
||||
gsk_line_curve_init_from_points (&deriv->line, GSK_PATH_LINE, &p, &p);
|
||||
value->x = self->points[1].x - self->points[0].x;
|
||||
value->y = self->points[1].y - self->points[0].y;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -404,7 +403,7 @@ static const GskCurveClass GSK_LINE_CURVE_CLASS = {
|
||||
gsk_line_curve_decompose_curve,
|
||||
gsk_line_curve_get_bounds,
|
||||
gsk_line_curve_get_bounds,
|
||||
gsk_line_curve_get_derivative,
|
||||
gsk_line_curve_get_derivative_at,
|
||||
gsk_line_curve_get_crossing,
|
||||
};
|
||||
|
||||
@@ -762,6 +761,16 @@ gsk_quad_curve_get_derivative (const GskCurve *curve,
|
||||
gsk_line_curve_init_from_points (&deriv->line, GSK_PATH_LINE, &p[0], &p[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_quad_curve_get_derivative_at (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *value)
|
||||
{
|
||||
GskCurve d;
|
||||
gsk_quad_curve_get_derivative (curve, &d);
|
||||
gsk_curve_get_point (&d, t, value);
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_quad_curve_get_crossing (const GskCurve *curve,
|
||||
const graphene_point_t *point)
|
||||
@@ -788,7 +797,7 @@ static const GskCurveClass GSK_QUAD_CURVE_CLASS = {
|
||||
gsk_quad_curve_decompose_curve,
|
||||
gsk_quad_curve_get_bounds,
|
||||
gsk_quad_curve_get_tight_bounds,
|
||||
gsk_quad_curve_get_derivative,
|
||||
gsk_quad_curve_get_derivative_at,
|
||||
gsk_quad_curve_get_crossing,
|
||||
};
|
||||
|
||||
@@ -975,8 +984,22 @@ pow3 (float w)
|
||||
return w * w * w;
|
||||
}
|
||||
|
||||
static void gsk_cubic_curve_get_derivative (const GskCurve *curve,
|
||||
GskCurve *deriv);
|
||||
static void
|
||||
gsk_cubic_curve_get_derivative (const GskCurve *curve,
|
||||
GskCurve *deriv)
|
||||
{
|
||||
const GskCubicCurve *self = &curve->cubic;
|
||||
graphene_point_t p[3];
|
||||
|
||||
p[0].x = 3.f * (self->points[1].x - self->points[0].x);
|
||||
p[0].y = 3.f * (self->points[1].y - self->points[0].y);
|
||||
p[1].x = 3.f * (self->points[2].x - self->points[1].x);
|
||||
p[1].y = 3.f * (self->points[2].y - self->points[1].y);
|
||||
p[2].x = 3.f * (self->points[3].x - self->points[2].x);
|
||||
p[2].y = 3.f * (self->points[3].y - self->points[2].y);
|
||||
|
||||
gsk_quad_curve_init_from_points (&deriv->quad, p);
|
||||
}
|
||||
|
||||
static float
|
||||
gsk_cubic_curve_get_curvature (const GskCurve *curve,
|
||||
@@ -1201,20 +1224,13 @@ gsk_cubic_curve_get_tight_bounds (const GskCurve *curve,
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cubic_curve_get_derivative (const GskCurve *curve,
|
||||
GskCurve *deriv)
|
||||
gsk_cubic_curve_get_derivative_at (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *value)
|
||||
{
|
||||
const GskCubicCurve *self = &curve->cubic;
|
||||
graphene_point_t p[3];
|
||||
|
||||
p[0].x = 3.f * (self->points[1].x - self->points[0].x);
|
||||
p[0].y = 3.f * (self->points[1].y - self->points[0].y);
|
||||
p[1].x = 3.f * (self->points[2].x - self->points[1].x);
|
||||
p[1].y = 3.f * (self->points[2].y - self->points[1].y);
|
||||
p[2].x = 3.f * (self->points[3].x - self->points[2].x);
|
||||
p[2].y = 3.f * (self->points[3].y - self->points[2].y);
|
||||
|
||||
gsk_quad_curve_init_from_points (&deriv->quad, p);
|
||||
GskCurve d;
|
||||
gsk_cubic_curve_get_derivative (curve, &d);
|
||||
gsk_curve_get_point (&d, t, value);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1243,7 +1259,7 @@ static const GskCurveClass GSK_CUBIC_CURVE_CLASS = {
|
||||
gsk_cubic_curve_decompose_curve,
|
||||
gsk_cubic_curve_get_bounds,
|
||||
gsk_cubic_curve_get_tight_bounds,
|
||||
gsk_cubic_curve_get_derivative,
|
||||
gsk_cubic_curve_get_derivative_at,
|
||||
gsk_cubic_curve_get_crossing,
|
||||
};
|
||||
|
||||
@@ -1407,35 +1423,53 @@ gsk_conic_curve_get_point (const GskCurve *curve,
|
||||
gsk_conic_curve_eval_point (self, t, pos);
|
||||
}
|
||||
|
||||
/* See M. Floater, Derivatives of rational Bezier curves */
|
||||
static void
|
||||
gsk_conic_curve_get_derivative_at (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *value)
|
||||
{
|
||||
const GskConicCurve *self = &curve->conic;
|
||||
float w = gsk_conic_curve_get_weight (self);
|
||||
const graphene_point_t *pts = self->points;
|
||||
graphene_point_t p[3], p1[2];
|
||||
float w1[2], w2;
|
||||
|
||||
/* The tangent will be 0 in these corner cases, just
|
||||
* treat it like a line here.
|
||||
*/
|
||||
if ((t <= 0.f && graphene_point_equal (&pts[0], &pts[1])) ||
|
||||
(t >= 1.f && graphene_point_equal (&pts[1], &pts[3])))
|
||||
{
|
||||
graphene_point_init (value, pts[3].x - pts[0].x, pts[3].y - pts[0].y);
|
||||
return;
|
||||
}
|
||||
|
||||
p[0] = pts[0];
|
||||
p[1] = pts[1];
|
||||
p[2] = pts[3];
|
||||
|
||||
w1[0] = (1 - t) + t*w;
|
||||
w1[1] = (1 - t)*w + t;
|
||||
|
||||
w2 = (1 - t) * w1[0] + t * w1[1];
|
||||
|
||||
p1[0].x = ((1 - t)*p[0].x + t*w*p[1].x)/w1[0];
|
||||
p1[0].y = ((1 - t)*p[0].y + t*w*p[1].y)/w1[0];
|
||||
p1[1].x = ((1 - t)*w*p[1].x + t*p[2].x)/w1[1];
|
||||
p1[1].y = ((1 - t)*w*p[1].y + t*p[2].y)/w1[1];
|
||||
|
||||
value->x = 2 * (w1[0] * w1[1])/(w2*w2) * (p1[1].x - p1[0].x);
|
||||
value->y = 2 * (w1[0] * w1[1])/(w2*w2) * (p1[1].y - p1[0].y);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_conic_curve_get_tangent (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_vec2_t *tangent)
|
||||
{
|
||||
const GskConicCurve *self = &curve->conic;
|
||||
graphene_point_t tmp;
|
||||
float w = gsk_conic_curve_get_weight (self);
|
||||
const graphene_point_t *pts = self->points;
|
||||
|
||||
/* The tangent will be 0 in these corner cases, just
|
||||
* treat it like a line here. */
|
||||
if ((t <= 0.f && graphene_point_equal (&pts[0], &pts[1])) ||
|
||||
(t >= 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_curve_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))
|
||||
},
|
||||
t,
|
||||
&tmp);
|
||||
gsk_conic_curve_get_derivative_at (curve, t, &tmp);
|
||||
graphene_vec2_init (tangent, tmp.x, tmp.y);
|
||||
graphene_vec2_normalize (tangent, tangent);
|
||||
}
|
||||
@@ -1911,7 +1945,7 @@ static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
|
||||
gsk_conic_curve_decompose_curve,
|
||||
gsk_conic_curve_get_bounds,
|
||||
gsk_conic_curve_get_tight_bounds,
|
||||
NULL, /* FIXME */
|
||||
gsk_conic_curve_get_derivative_at,
|
||||
gsk_conic_curve_get_crossing,
|
||||
};
|
||||
|
||||
@@ -2106,10 +2140,11 @@ gsk_curve_get_tight_bounds (const GskCurve *curve,
|
||||
}
|
||||
|
||||
void
|
||||
gsk_curve_get_derivative (const GskCurve *curve,
|
||||
GskCurve *deriv)
|
||||
gsk_curve_get_derivative_at (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *value)
|
||||
{
|
||||
get_class (curve->op)->get_derivative (curve, deriv);
|
||||
get_class (curve->op)->get_derivative_at (curve, t, value);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -164,8 +164,9 @@ void gsk_curve_get_bounds (const GskCurve
|
||||
void gsk_curve_get_tight_bounds (const GskCurve *curve,
|
||||
GskBoundingBox *bounds);
|
||||
|
||||
void gsk_curve_get_derivative (const GskCurve *curve,
|
||||
GskCurve *derivative);
|
||||
void gsk_curve_get_derivative_at (const GskCurve *curve,
|
||||
float t,
|
||||
graphene_point_t *value);
|
||||
int gsk_curve_get_crossing (const GskCurve *curve,
|
||||
const graphene_point_t *point);
|
||||
gboolean gsk_curve_get_closest_point (const GskCurve *curve,
|
||||
|
||||
@@ -342,26 +342,22 @@ test_curve_split (void)
|
||||
static void
|
||||
test_curve_derivative (void)
|
||||
{
|
||||
GskCurve c, d;
|
||||
GskCurve c;
|
||||
float t;
|
||||
graphene_vec2_t t1, t2;
|
||||
graphene_point_t p;
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
/* No derivatives for conics */
|
||||
init_random_curve_with_op (&c, GSK_PATH_LINE, GSK_PATH_CUBIC);
|
||||
|
||||
gsk_curve_get_derivative (&c, &d);
|
||||
init_random_curve (&c);
|
||||
|
||||
for (int j = 0; j < 100; j++)
|
||||
{
|
||||
t = g_test_rand_double_range (0, 1);
|
||||
gsk_curve_get_derivative_at (&c, t, &p);
|
||||
gsk_curve_get_tangent (&c, t, &t1);
|
||||
gsk_curve_get_point (&d, t, &p);
|
||||
graphene_vec2_init (&t2, p.x, p.y);
|
||||
graphene_vec2_normalize (&t2, &t2);
|
||||
|
||||
g_assert_true (graphene_vec2_near (&t1, &t2, 0.1));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user