Exemplo n.º 1
0
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
 *
 * Note: See the comments for _cairo_pen_find_active_cw_vertex_index
 * for some details about the strictness of the inequalities here.
 */
void
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
					 cairo_slope_t *slope,
					 int *active)
{
    int i;
    cairo_slope_t slope_reverse;

    slope_reverse = *slope;
    slope_reverse.dx = -slope_reverse.dx;
    slope_reverse.dy = -slope_reverse.dy;

    for (i=pen->num_vertices-1; i >= 0; i--) {
	if ((_cairo_slope_compare (&pen->vertices[i].slope_ccw, &slope_reverse) >= 0) &&
	    (_cairo_slope_compare (&pen->vertices[i].slope_cw, &slope_reverse) < 0))
	    break;
    }

    /* If the desired slope cannot be found between any of the pen
     * vertices, then we must have a degenerate pen, (such as a pen
     * that's been transformed to a line). In that case, we consider
     * the last pen vertex as the appropriate counterclockwise vertex.
     */
    if (i < 0)
	i = pen->num_vertices - 1;

    *active = i;
}
Exemplo n.º 2
0
static int
_cairo_hull_vertex_compare (const void *av, const void *bv)
{
    cairo_hull_t *a = (cairo_hull_t *) av;
    cairo_hull_t *b = (cairo_hull_t *) bv;
    int ret;

    ret = _cairo_slope_compare (&a->slope, &b->slope);

    /* In the case of two vertices with identical slope from the
       extremal point discard the nearer point. */

    if (ret == 0) {
	cairo_fixed_48_16_t a_dist, b_dist;
	a_dist = ((cairo_fixed_48_16_t) a->slope.dx * a->slope.dx +
		  (cairo_fixed_48_16_t) a->slope.dy * a->slope.dy);
	b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx +
		  (cairo_fixed_48_16_t) b->slope.dy * b->slope.dy);
	/*
	 * Use the point's ids to ensure a total ordering.
	 * a well-defined ordering, and avoid setting discard on
	 * both points.
	 */
	if (a_dist < b_dist || (a_dist == b_dist && a->id < b->id)) {
	    a->discard = 1;
	    ret = -1;
	} else {
	    b->discard = 1;
	    ret = 1;
	}
    }

    return ret;
}
Exemplo n.º 3
0
static cairo_status_t
_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
{
    int i, j, k;
    cairo_slope_t slope_ij, slope_jk;

    i = 0;
    j = _cairo_hull_next_valid (hull, num_hull, i);
    k = _cairo_hull_next_valid (hull, num_hull, j);

    do {
	_cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
	_cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);

	/* Is the angle formed by ij and jk concave? */
	if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
	    if (i == k)
		return CAIRO_STATUS_SUCCESS;
	    hull[j].discard = 1;
	    j = i;
	    i = _cairo_hull_prev_valid (hull, num_hull, j);
	} else {
	    i = j;
	    j = k;
	    k = _cairo_hull_next_valid (hull, num_hull, j);
	}
    } while (j != 0);

    return CAIRO_STATUS_SUCCESS;
}
Exemplo n.º 4
0
static cairo_status_t
line_to (void *closure,
	 const cairo_point_t *point)
{
    struct stroker *stroker = closure;
    cairo_stroke_face_t start;
    cairo_point_t *p1 = &stroker->current_face.point;
    cairo_slope_t dev_slope;

    stroker->has_initial_sub_path = TRUE;

    if (p1->x == point->x && p1->y == point->y)
	return CAIRO_STATUS_SUCCESS;

#if DEBUG
    _cairo_contour_add_point (&stroker->path, point);
#endif

    _cairo_slope_init (&dev_slope, p1, point);
    compute_face (p1, &dev_slope, stroker, &start);

    if (stroker->has_current_face) {
	int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
					      &start.dev_vector);
	if (clockwise) {
	    clockwise = clockwise < 0;
	    /* Join with final face from previous segment */
	    if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
				    stroker->contour_tolerance) ||
		! within_tolerance (&stroker->current_face.cw, &start.cw,
				    stroker->contour_tolerance))
	    {
		outer_join (stroker, &stroker->current_face, &start, clockwise);
		inner_join (stroker, &stroker->current_face, &start, clockwise);
	    }
	}
    } else {
	if (! stroker->has_first_face) {
	    /* Save sub path's first face in case needed for closing join */
	    stroker->first_face = start;
	    stroker->has_first_face = TRUE;
	}
	stroker->has_current_face = TRUE;

	contour_add_point (stroker, &stroker->cw, &start.cw);
	contour_add_point (stroker, &stroker->ccw, &start.ccw);
    }

    stroker->current_face = start;
    stroker->current_face.point = *point;
    stroker->current_face.ccw.x += dev_slope.dx;
    stroker->current_face.ccw.y += dev_slope.dy;
    stroker->current_face.cw.x += dev_slope.dx;
    stroker->current_face.cw.y += dev_slope.dy;

    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);

    return CAIRO_STATUS_SUCCESS;
}
Exemplo n.º 5
0
static int
_cairo_hull_vertex_compare (const void *av, const void *bv)
{
    cairo_hull_t *a = (cairo_hull_t *) av;
    cairo_hull_t *b = (cairo_hull_t *) bv;
    int ret;

    ret = _cairo_slope_compare (&a->slope, &b->slope);

    /*
     * In the case of two vertices with identical slope from the
     * extremal point discard the nearer point.
     */
    if (ret == 0) {
	int cmp;

	cmp = _cairo_int64_cmp (_slope_length (&a->slope),
				_slope_length (&b->slope));

	/*
	 * Use the points' ids to ensure a well-defined ordering,
	 * and avoid setting discard on both points.
	 */
	if (cmp < 0 || (cmp == 0 && a->id < b->id)) {
	    a->discard = 1;
	    ret = -1;
	} else {
	    b->discard = 1;
	    ret = 1;
	}
    }

    return ret;
}
Exemplo n.º 6
0
static int
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
{
    cairo_slope_t in_slope, out_slope;

    _cairo_slope_init (&in_slope, &in->point, &in->cw);
    _cairo_slope_init (&out_slope, &out->point, &out->cw);

    return _cairo_slope_compare (&in_slope, &out_slope) < 0;
}
Exemplo n.º 7
0
void
_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
				    const cairo_slope_t *in,
				    const cairo_slope_t *out,
				    int *start, int *stop)
{

    int lo = 0, hi = pen->num_vertices;
    int i;

    i = (lo + hi) >> 1;
    do {
	if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
	    lo = i;
	else
	    hi = i;
	i = (lo + hi) >> 1;
    } while (hi - lo > 1);
    if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
	if (++i == pen->num_vertices)
	    i = 0;
    *start = i;

    if (_cairo_slope_compare (out, &pen->vertices[i].slope_ccw) >= 0) {
	lo = i;
	hi = i + pen->num_vertices;
	i = (lo + hi) >> 1;
	do {
	    int j = i;
	    if (j >= pen->num_vertices)
		j -= pen->num_vertices;
	    if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
		hi = i;
	    else
		lo = i;
	    i = (lo + hi) >> 1;
	} while (hi - lo > 1);
	if (i >= pen->num_vertices)
	    i -= pen->num_vertices;
    }
Exemplo n.º 8
0
/*
 * Find active pen vertex for clockwise edge of stroke at the given slope.
 *
 * The strictness of the inequalities here is delicate. The issue is
 * that the slope_ccw member of one pen vertex will be equivalent to
 * the slope_cw member of the next pen vertex in a counterclockwise
 * order. However, for this function, we care strongly about which
 * vertex is returned.
 *
 * [I think the "care strongly" above has to do with ensuring that the
 * pen's "extra points" from the spline's initial and final slopes are
 * properly found when beginning the spline stroking.]
 */
int
_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen,
					const cairo_slope_t *slope)
{
    int i;

    for (i=0; i < pen->num_vertices; i++) {
	if ((_cairo_slope_compare (slope, &pen->vertices[i].slope_ccw) < 0) &&
	    (_cairo_slope_compare (slope, &pen->vertices[i].slope_cw) >= 0))
	    break;
    }

    /* If the desired slope cannot be found between any of the pen
     * vertices, then we must have a degenerate pen, (such as a pen
     * that's been transformed to a line). In that case, we consider
     * the first pen vertex as the appropriate clockwise vertex.
     */
    if (i == pen->num_vertices)
	i = 0;

    return i;
}
Exemplo n.º 9
0
static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{
    cairo_slope_t slope_left, slope_pt, slope_right;

    if (t->top > pt->y)
	return FALSE;
    if (t->bottom < pt->y)
	return FALSE;

    _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
    _cairo_slope_init (&slope_pt, &t->left.p1, pt);

    if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
	return FALSE;

    _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
    _cairo_slope_init (&slope_pt, &t->right.p1, pt);

    if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
	return FALSE;

    return TRUE;
}
Exemplo n.º 10
0
static int
_cairo_hull_vertex_compare (const void *av, const void *bv)
{
    cairo_hull_t *a = (cairo_hull_t *) av;
    cairo_hull_t *b = (cairo_hull_t *) bv;
    int ret;

    /* Some libraries are reported to actually compare identical
     * pointers and require the result to be 0. This is the crazy world we
     * have to live in.
     */
    if (a == b)
	return 0;

    ret = _cairo_slope_compare (&a->slope, &b->slope);

    /*
     * In the case of two vertices with identical slope from the
     * extremal point discard the nearer point.
     */
    if (ret == 0) {
	int cmp;

	cmp = _cairo_int64_cmp (_slope_length (&a->slope),
				_slope_length (&b->slope));

	/*
	 * Use the points' ids to ensure a well-defined ordering,
	 * and avoid setting discard on both points.
	 */
	if (cmp < 0 || (cmp == 0 && a->id < b->id)) {
	    a->discard = 1;
	    ret = -1;
	} else {
	    b->discard = 1;
	    ret = 1;
	}
    }

    return ret;
}
Exemplo n.º 11
0
static int
join_is_clockwise (const cairo_stroke_face_t *in,
                   const cairo_stroke_face_t *out)
{
    return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
}
Exemplo n.º 12
0
/*
 * Construct a fan around the midpoint using the vertices from pen between
 * inpt and outpt.
 */
static void
add_fan (struct stroker *stroker,
         const cairo_slope_t *in_vector,
         const cairo_slope_t *out_vector,
         const cairo_point_t *midpt,
         const cairo_point_t *inpt,
         const cairo_point_t *outpt,
         cairo_bool_t clockwise)
{
    int start, stop, step, i, npoints;

    if (clockwise) {
        step  = 1;

        start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
                in_vector);
        if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
                                  in_vector) < 0)
            start = range_step (start, 1, stroker->pen.num_vertices);

        stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
                out_vector);
        if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
                                  out_vector) > 0)
        {
            stop = range_step (stop, -1, stroker->pen.num_vertices);
            if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
                                      in_vector) < 0)
                return;
        }

        npoints = stop - start;
    } else {
        step  = -1;

        start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
                in_vector);
        if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
                                  in_vector) < 0)
            start = range_step (start, -1, stroker->pen.num_vertices);

        stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
                out_vector);
        if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
                                  out_vector) > 0)
        {
            stop = range_step (stop, 1, stroker->pen.num_vertices);
            if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
                                      in_vector) < 0)
                return;
        }

        npoints = start - stop;
    }
    stop = range_step (stop, step, stroker->pen.num_vertices);
    if (npoints < 0)
        npoints += stroker->pen.num_vertices;
    if (npoints <= 1)
        return;

    for (i = start;
            i != stop;
            i = range_step (i, step, stroker->pen.num_vertices))
    {
        cairo_point_t p = *midpt;
        translate_point (&p, &stroker->pen.vertices[i].point);
        //contour_add_point (stroker, c, &p);
    }
}
Exemplo n.º 13
0
/*
 * Construct a fan around the midpoint using the vertices from pen between
 * inpt and outpt.
 */
static cairo_status_t
_tessellate_fan (cairo_stroker_t *stroker,
		 const cairo_slope_t *in_vector,
		 const cairo_slope_t *out_vector,
		 const cairo_point_t *midpt,
		 const cairo_point_t *inpt,
		 const cairo_point_t *outpt,
		 cairo_bool_t clockwise)
{
    cairo_point_t stack_points[64], *points = stack_points;
    int start, stop, step, i, npoints;
    cairo_status_t status;

    if (clockwise) {
	step  = -1;

	start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
							 in_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
				  in_vector) < 0)
	    start = _range_step (start, -1, stroker->pen.num_vertices);

	stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
							 out_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
				  out_vector) > 0)
	{
	    stop = _range_step (stop, 1, stroker->pen.num_vertices);
	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
				      in_vector) < 0)
	    {
		goto BEVEL;
	    }
	}

	npoints = start - stop;
    } else {
	step  = 1;

	start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
							in_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
				  in_vector) < 0)
	    start = _range_step (start, 1, stroker->pen.num_vertices);

	stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
							out_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
				  out_vector) > 0)
	{
	    stop = _range_step (stop, -1, stroker->pen.num_vertices);
	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
				      in_vector) < 0)
	    {
		goto BEVEL;
	    }
	}

	npoints = stop - start;
    }
    stop = _range_step (stop, step, stroker->pen.num_vertices);

    if (npoints < 0)
	npoints += stroker->pen.num_vertices;
    npoints += 3;

    if (npoints <= 1)
	goto BEVEL;

    if (npoints > ARRAY_LENGTH (stack_points)) {
	points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t));
	if (unlikely (points == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }


    /* Construct the fan. */
    npoints = 0;
    points[npoints++] = *inpt;
    for (i = start;
	 i != stop;
	i = _range_step (i, step, stroker->pen.num_vertices))
    {
	points[npoints] = *midpt;
	_translate_point (&points[npoints], &stroker->pen.vertices[i].point);
	npoints++;
    }
    points[npoints++] = *outpt;

    if (stroker->add_external_edge != NULL) {
	for (i = 0; i < npoints - 1; i++) {
	    if (clockwise) {
		status = stroker->add_external_edge (stroker->closure,
						     &points[i], &points[i+1]);
	    } else {
		status = stroker->add_external_edge (stroker->closure,
						     &points[i+1], &points[i]);
	    }
	    if (unlikely (status))
		break;
	}
    } else {
	status = stroker->add_triangle_fan (stroker->closure,
					    midpt, points, npoints);
    }

    if (points != stack_points)
	free (points);

    return status;

BEVEL:
    /* Ensure a leak free connection... */
    if (stroker->add_external_edge != NULL) {
	if (clockwise)
	    return stroker->add_external_edge (stroker->closure, inpt, outpt);
	else
	    return stroker->add_external_edge (stroker->closure, outpt, inpt);
    } else {
	stack_points[0] = *midpt;
	stack_points[1] = *inpt;
	stack_points[2] = *outpt;
	return stroker->add_triangle (stroker->closure, stack_points);
    }
}
Exemplo n.º 14
0
void
_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
				     const cairo_point_t q[4])
{
    int a, b, c, d;
    int i;
    cairo_slope_t ab, ad;
    cairo_bool_t b_left_of_d;
    cairo_line_t left;
    cairo_line_t right;

    /* Choose a as a point with minimal y */
    a = 0;
    for (i = 1; i < 4; i++)
	if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
	    a = i;

    /* b and d are adjacent to a, while c is opposite */
    b = (a + 1) % 4;
    c = (a + 2) % 4;
    d = (a + 3) % 4;

    /* Choose between b and d so that b.y is less than d.y */
    if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
	b = (a + 3) % 4;
	d = (a + 1) % 4;
    }

    /* Without freedom left to choose anything else, we have four
     * cases to tessellate.
     *
     * First, we have to determine the Y-axis sort of the four
     * vertices, (either abcd or abdc). After that we need to detemine
     * which edges will be "left" and which will be "right" in the
     * resulting trapezoids. This can be determined by computing a
     * slope comparison of ab and ad to determine if b is left of d or
     * not.
     *
     * Note that "left of" here is in the sense of which edges should
     * be the left vs. right edges of the trapezoid. In particular, b
     * left of d does *not* mean that b.x is less than d.x.
     *
     * This should hopefully be made clear in the lame ASCII art
     * below. Since the same slope comparison is used in all cases, we
     * compute it before testing for the Y-value sort. */

    /* Note: If a == b then the ab slope doesn't give us any
     * information. In that case, we can replace it with the ac (or
     * equivalenly the bc) slope which gives us exactly the same
     * information we need. At worst the names of the identifiers ab
     * and b_left_of_d are inaccurate in this case, (would be ac, and
     * c_left_of_d). */
    if (q[a].x == q[b].x && q[a].y == q[b].y)
	_cairo_slope_init (&ab, &q[a], &q[c]);
    else
	_cairo_slope_init (&ab, &q[a], &q[b]);

    _cairo_slope_init (&ad, &q[a], &q[d]);

    b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;

    if (q[c].y <= q[d].y) {
	if (b_left_of_d) {
	    /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
	     *
	     *                      top bot left right
	     *        _a  a  a
	     *      / /  /|  |\      a.y b.y  ab   ad
	     *     b /  b |  b \
	     *    / /   | |   \ \    b.y c.y  bc   ad
	     *   c /    c |    c \
	     *  | /      \|     \ \  c.y d.y  cd   ad
	     *  d         d       d
	     */
	    left.p1  = q[a]; left.p2  = q[b];
	    right.p1 = q[a]; right.p2 = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    left.p1  = q[b]; left.p2  = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
	    left.p1  = q[c]; left.p2  = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
	} else {
	    /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
	     *
	     *       a  a  a_
	     *      /|  |\  \ \     a.y b.y  ad  ab
	     *     / b  | b  \ b
	     *    / /   | |   \ \   b.y c.y  ad  bc
	     *   / c    | c    \ c
	     *  / /     |/      \ | c.y d.y  ad  cd
	     *  d       d         d
	     */
	    left.p1  = q[a]; left.p2  = q[d];
	    right.p1 = q[a]; right.p2 = q[b];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    right.p1 = q[b]; right.p2 = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
	    right.p1 = q[c]; right.p2 = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
	}
    } else {
	if (b_left_of_d) {
	    /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
	     *
	     *        a   a     a
	     *       //  / \    |\     a.y b.y  ab  ad
	     *     /b/  b   \   b \
	     *    / /    \   \   \ \   b.y d.y  bc  ad
	     *   /d/      \   d   \ d
	     *  //         \ /     \|  d.y c.y  bc  dc
	     *  c           c       c
	     */
	    left.p1  = q[a]; left.p2  = q[b];
	    right.p1 = q[a]; right.p2 = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    left.p1  = q[b]; left.p2  = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
	    right.p1 = q[d]; right.p2 = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
	} else {
	    /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
	     *
	     *      a     a   a
	     *     /|    / \  \\       a.y b.y  ad  ab
	     *    / b   /   b  \b\
	     *   / /   /   /    \ \    b.y d.y  ad  bc
	     *  d /   d   /	 \d\
	     *  |/     \ /         \\  d.y c.y  dc  bc
	     *  c       c	   c
	     */
	    left.p1  = q[a]; left.p2  = q[d];
	    right.p1 = q[a]; right.p2 = q[b];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    right.p1 = q[b]; right.p2 = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
	    left.p1  = q[d]; left.p2  = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
	}
    }
}
Exemplo n.º 15
0
static void
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
			       cairo_spline_t *spline,
			       cairo_direction_t dir,
			       cairo_polygon_t *polygon)
{
    int i;
    int start, stop, step;
    int active = 0;
    cairo_point_t hull_point;
    cairo_slope_t slope, initial_slope, final_slope;
    cairo_point_t *point = spline->points;
    int num_points = spline->num_points;

    if (dir == CAIRO_DIRECTION_FORWARD) {
	start = 0;
	stop = num_points;
	step = 1;
	initial_slope = spline->initial_slope;
	final_slope = spline->final_slope;
    } else {
	start = num_points - 1;
	stop = -1;
	step = -1;
	initial_slope = spline->final_slope;
	initial_slope.dx = -initial_slope.dx;
	initial_slope.dy = -initial_slope.dy;
	final_slope = spline->initial_slope;
	final_slope.dx = -final_slope.dx;
	final_slope.dy = -final_slope.dy;
    }

    _cairo_pen_find_active_cw_vertex_index (pen,
	                                    &initial_slope,
					    &active);

    i = start;
    while (i != stop) {
	hull_point.x = point[i].x + pen->vertices[active].point.x;
	hull_point.y = point[i].y + pen->vertices[active].point.y;

	_cairo_polygon_line_to (polygon, &hull_point);

	if (i + step == stop)
	    slope = final_slope;
	else
	    _cairo_slope_init (&slope, &point[i], &point[i+step]);

	/* The strict inequalities here ensure that if a spline slope
	 * compares identically with either of the slopes of the
	 * active vertex, then it remains the active vertex. This is
	 * very important since otherwise we can trigger an infinite
	 * loop in the case of a degenerate pen, (a line), where
	 * neither vertex considers itself active for the slope---one
	 * will consider it as equal and reject, and the other will
	 * consider it unequal and reject. This is due to the inherent
	 * ambiguity when comparing slopes that differ by exactly
	 * pi. */
	if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_ccw) > 0) {
	    if (++active == pen->num_vertices)
		active = 0;
	} else if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_cw) < 0) {
	    if (--active == -1)
		active = pen->num_vertices - 1;
	} else {
	    i += step;
	}
    }
}
Exemplo n.º 16
0
/* Is a clockwise of b?
 *
 * NOTE: The strict equality here is not significant in and of itself,
 * but there are functions up above that are sensitive to it,
 * (cf. _cairo_pen_find_active_cw_vertex_index).
 */
int
_cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b)
{
    return _cairo_slope_compare (a, b) < 0;
}