curve: Add gsk_curve_offset
This method creates an offset curve from an existing curve by just moving the control points laterally. This will be used in stroking.
This commit is contained in:
173
gsk/gskcurve.c
173
gsk/gskcurve.c
@@ -74,6 +74,9 @@ struct _GskCurveClass
|
||||
GskBoundingBox *bounds);
|
||||
void (* get_tight_bounds) (const GskCurve *curve,
|
||||
GskBoundingBox *bounds);
|
||||
void (* offset) (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset_curve);
|
||||
};
|
||||
|
||||
/* {{{ Utilities */
|
||||
@@ -87,6 +90,26 @@ get_tangent (const graphene_point_t *p0,
|
||||
graphene_vec2_normalize (t, t);
|
||||
}
|
||||
|
||||
static void
|
||||
get_normal (const graphene_point_t *p0,
|
||||
const graphene_point_t *p1,
|
||||
graphene_vec2_t *n)
|
||||
{
|
||||
graphene_vec2_init (n, p0->y - p1->y, p1->x - p0->x);
|
||||
graphene_vec2_normalize (n, n);
|
||||
}
|
||||
|
||||
/* Compute q = p + d * n */
|
||||
static void
|
||||
scale_point (const graphene_point_t *p,
|
||||
const graphene_vec2_t *n,
|
||||
float d,
|
||||
graphene_point_t *q)
|
||||
{
|
||||
q->x = p->x + d * graphene_vec2_get_x (n);
|
||||
q->y = p->y + d * graphene_vec2_get_y (n);
|
||||
}
|
||||
|
||||
/* Replace a line by an equivalent quad,
|
||||
* and a quad by an equivalent cubic.
|
||||
*/
|
||||
@@ -129,6 +152,40 @@ gsk_curve_elevate (const GskCurve *curve,
|
||||
/* }}} */
|
||||
/* {{{ Line */
|
||||
|
||||
/* Set p to the intersection of the lines through a, b and c, d.
|
||||
* Return the number of intersections found (0 or 1)
|
||||
*/
|
||||
static int
|
||||
line_intersection (const graphene_point_t *a,
|
||||
const graphene_point_t *b,
|
||||
const graphene_point_t *c,
|
||||
const graphene_point_t *d,
|
||||
graphene_point_t *p)
|
||||
{
|
||||
float a1 = b->y - a->y;
|
||||
float b1 = a->x - b->x;
|
||||
float c1 = a1*a->x + b1*a->y;
|
||||
|
||||
float a2 = d->y - c->y;
|
||||
float b2 = c->x - d->x;
|
||||
float c2 = a2*c->x+ b2*c->y;
|
||||
|
||||
float det = a1*b2 - a2*b1;
|
||||
|
||||
if (fabs (det) < 0.001)
|
||||
{
|
||||
p->x = NAN;
|
||||
p->y = NAN;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->x = (b2*c1 - b1*c2) / det;
|
||||
p->y = (a1*c2 - a2*c1) / det;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_line_curve_init_from_points (GskLineCurve *self,
|
||||
GskPathOperation op,
|
||||
@@ -310,6 +367,23 @@ gsk_line_curve_get_bounds (const GskCurve *curve,
|
||||
gsk_bounding_box_init (bounds, &pts[0], &pts[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_line_curve_offset (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset_curve)
|
||||
{
|
||||
const GskLineCurve *self = &curve->line;
|
||||
const graphene_point_t *pts = self->points;
|
||||
graphene_vec2_t n;
|
||||
graphene_point_t p[4];
|
||||
|
||||
get_normal (&pts[0], &pts[1], &n);
|
||||
scale_point (&pts[0], &n, distance, &p[0]);
|
||||
scale_point (&pts[1], &n, distance, &p[1]);
|
||||
|
||||
gsk_curve_init (offset_curve, gsk_pathop_encode (GSK_PATH_LINE, p));
|
||||
}
|
||||
|
||||
static const GskCurveClass GSK_LINE_CURVE_CLASS = {
|
||||
gsk_line_curve_init,
|
||||
gsk_line_curve_init_foreach,
|
||||
@@ -329,6 +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_offset,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -677,6 +752,32 @@ gsk_quad_curve_get_tight_bounds (const GskCurve *curve,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_quad_curve_offset (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset)
|
||||
{
|
||||
const GskCubicCurve *self = &curve->cubic;
|
||||
const graphene_point_t *pts = self->points;
|
||||
graphene_vec2_t n;
|
||||
graphene_point_t p[4];
|
||||
graphene_point_t m1, m2;
|
||||
|
||||
/* Simply scale control points, a la Tiller and Hanson */
|
||||
get_normal (&pts[0], &pts[1], &n);
|
||||
scale_point (&pts[0], &n, distance, &p[0]);
|
||||
scale_point (&pts[1], &n, distance, &m1);
|
||||
|
||||
get_normal (&pts[1], &pts[2], &n);
|
||||
scale_point (&pts[1], &n, distance, &m2);
|
||||
scale_point (&pts[2], &n, distance, &p[2]);
|
||||
|
||||
if (!line_intersection (&p[0], &m1, &m2, &p[2], &p[1]))
|
||||
gsk_curve_get_point (curve, 0.5, &p[1]);
|
||||
|
||||
gsk_quad_curve_init_from_points (&offset->quad, p);
|
||||
}
|
||||
|
||||
static const GskCurveClass GSK_QUAD_CURVE_CLASS = {
|
||||
gsk_quad_curve_init,
|
||||
gsk_quad_curve_init_foreach,
|
||||
@@ -696,6 +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_offset,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -1159,6 +1261,39 @@ gsk_cubic_curve_get_tight_bounds (const GskCurve *curve,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cubic_curve_offset (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset)
|
||||
{
|
||||
const GskCubicCurve *self = &curve->cubic;
|
||||
const graphene_point_t *pts = self->points;
|
||||
graphene_vec2_t n;
|
||||
graphene_point_t p[4];
|
||||
graphene_point_t m1, m2, m3, m4;
|
||||
|
||||
/* Simply scale control points, a la Tiller and Hanson */
|
||||
get_normal (&pts[0], &pts[1], &n);
|
||||
scale_point (&pts[0], &n, distance, &p[0]);
|
||||
scale_point (&pts[1], &n, distance, &m1);
|
||||
|
||||
get_normal (&pts[1], &pts[2], &n);
|
||||
scale_point (&pts[1], &n, distance, &m2);
|
||||
scale_point (&pts[2], &n, distance, &m3);
|
||||
|
||||
get_normal (&pts[2], &pts[3], &n);
|
||||
scale_point (&pts[2], &n, distance, &m4);
|
||||
scale_point (&pts[3], &n, distance, &p[3]);
|
||||
|
||||
if (!line_intersection (&p[0], &m1, &m2, &m3, &p[1]))
|
||||
p[1] = m1;
|
||||
|
||||
if (!line_intersection (&m2, &m3, &m4, &p[3], &p[2]))
|
||||
p[2] = m4;
|
||||
|
||||
gsk_cubic_curve_init_from_points (&offset->cubic, p);
|
||||
}
|
||||
|
||||
static const GskCurveClass GSK_CUBIC_CURVE_CLASS = {
|
||||
gsk_cubic_curve_init,
|
||||
gsk_cubic_curve_init_foreach,
|
||||
@@ -1178,6 +1313,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_offset,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -1818,6 +1954,34 @@ gsk_conic_curve_get_tight_bounds (const GskCurve *curve,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_conic_curve_offset (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset)
|
||||
{
|
||||
const GskConicCurve *self = &curve->conic;
|
||||
const graphene_point_t *pts = self->points;
|
||||
graphene_vec2_t n;
|
||||
graphene_point_t p[4];
|
||||
graphene_point_t m1, m2;
|
||||
|
||||
/* Simply scale control points, a la Tiller and Hanson */
|
||||
get_normal (&pts[0], &pts[1], &n);
|
||||
scale_point (&pts[0], &n, distance, &p[0]);
|
||||
scale_point (&pts[1], &n, distance, &m1);
|
||||
|
||||
get_normal (&pts[1], &pts[3], &n);
|
||||
scale_point (&pts[1], &n, distance, &m2);
|
||||
scale_point (&pts[3], &n, distance, &p[3]);
|
||||
|
||||
if (!line_intersection (&p[0], &m1, &m2, &p[3], &p[1]))
|
||||
p[1] = m1;
|
||||
|
||||
p[2] = pts[2];
|
||||
|
||||
gsk_conic_curve_init_from_points (&offset->conic, p);
|
||||
}
|
||||
|
||||
static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
|
||||
gsk_conic_curve_init,
|
||||
gsk_conic_curve_init_foreach,
|
||||
@@ -1837,6 +2001,7 @@ static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
|
||||
gsk_conic_curve_decompose_curve,
|
||||
gsk_conic_curve_get_bounds,
|
||||
gsk_conic_curve_get_tight_bounds,
|
||||
gsk_conic_curve_offset,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -2029,6 +2194,14 @@ gsk_curve_get_tight_bounds (const GskCurve *curve,
|
||||
get_class (curve->op)->get_tight_bounds (curve, bounds);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_curve_offset (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset_curve)
|
||||
{
|
||||
get_class (curve->op)->offset (curve, distance, offset_curve);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* vim:set foldmethod=marker expandtab: */
|
||||
|
||||
@@ -163,6 +163,9 @@ void gsk_curve_get_bounds (const GskCurve
|
||||
GskBoundingBox *bounds);
|
||||
void gsk_curve_get_tight_bounds (const GskCurve *curve,
|
||||
GskBoundingBox *bounds);
|
||||
void gsk_curve_offset (const GskCurve *curve,
|
||||
float distance,
|
||||
GskCurve *offset_curve);
|
||||
|
||||
int gsk_curve_get_curvature_points (const GskCurve *curve,
|
||||
float t[3]);
|
||||
|
||||
Reference in New Issue
Block a user