コード例 #1
0
static cairo_status_t
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
			       cairo_spline_t *spline,
			       cairo_direction_t dir,
			       cairo_polygon_t *polygon)
{
    int i;
    cairo_status_t status;
    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;
	status = _cairo_polygon_line_to (polygon, &hull_point);
	if (status)
	    return status;

	if (i + step == stop)
	    slope = final_slope;
	else
	    _cairo_slope_init (&slope, &point[i], &point[i+step]);
	if (_cairo_slope_counter_clockwise (&slope, &pen->vertices[active].slope_ccw)) {
	    if (++active == pen->num_vertices)
		active = 0;
	} else if (_cairo_slope_clockwise (&slope, &pen->vertices[active].slope_cw)) {
	    if (--active == -1)
		active = pen->num_vertices - 1;
	} else {
	    i += step;
	}
    }

    return CAIRO_STATUS_SUCCESS;
}
コード例 #2
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);
    }
}
コード例 #3
0
ファイル: cairo-path-stroke.c プロジェクト: alexgcastro/cairo
/*
 * 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);
    }
}
コード例 #4
0
ファイル: cairo-path-stroke.c プロジェクト: AliYousuf/cairo
static cairo_status_t
_cairo_stroker_add_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
{
    cairo_status_t	    status;

    if (stroker->style->line_cap == CAIRO_LINE_CAP_BUTT)
	return CAIRO_STATUS_SUCCESS;

    switch (stroker->style->line_cap) {
    case CAIRO_LINE_CAP_ROUND: {
	int i;
	int start, stop;
	cairo_slope_t slope;
	cairo_point_t tri[3];
	cairo_pen_t *pen = &stroker->pen;

	slope = f->dev_vector;
	start = _cairo_pen_find_active_cw_vertex_index (pen, &slope);
	slope.dx = -slope.dx;
	slope.dy = -slope.dy;
	stop = _cairo_pen_find_active_cw_vertex_index (pen, &slope);

	tri[0] = f->point;
	tri[1] = f->cw;
	for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
	    tri[2] = f->point;
	    _translate_point (&tri[2], &pen->vertices[i].point);
	    status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
	    if (unlikely (status))
		return status;
	    tri[1] = tri[2];
	}
	tri[2] = f->ccw;

	return _cairo_traps_tessellate_triangle (stroker->traps, tri);
    }
    case CAIRO_LINE_CAP_SQUARE: {
	double dx, dy;
	cairo_slope_t	fvector;
	cairo_point_t	occw, ocw;
	cairo_polygon_t	polygon;

	dx = f->usr_vector.x;
	dy = f->usr_vector.y;
	dx *= stroker->style->line_width / 2.0;
	dy *= stroker->style->line_width / 2.0;
	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
	fvector.dx = _cairo_fixed_from_double (dx);
	fvector.dy = _cairo_fixed_from_double (dy);
	occw.x = f->ccw.x + fvector.dx;
	occw.y = f->ccw.y + fvector.dy;
	ocw.x = f->cw.x + fvector.dx;
	ocw.y = f->cw.y + fvector.dy;

	_cairo_polygon_init (&polygon);
	_cairo_polygon_move_to (&polygon, &f->cw);
	_cairo_polygon_line_to (&polygon, &ocw);
	_cairo_polygon_line_to (&polygon, &occw);
	_cairo_polygon_line_to (&polygon, &f->ccw);
	_cairo_polygon_close (&polygon);
	status = _cairo_polygon_status (&polygon);

	if (status == CAIRO_STATUS_SUCCESS) {
	    status = _cairo_bentley_ottmann_tessellate_polygon (stroker->traps,
								&polygon,
								CAIRO_FILL_RULE_WINDING);
	}

	_cairo_polygon_fini (&polygon);

	return status;
    }
    case CAIRO_LINE_CAP_BUTT:
    default:
	return CAIRO_STATUS_SUCCESS;
    }
}
コード例 #5
0
ファイル: cairo-path-stroke.c プロジェクト: AliYousuf/cairo
static cairo_status_t
_cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out)
{
    int			clockwise = _cairo_stroker_face_clockwise (out, in);
    cairo_point_t	*inpt, *outpt;
    cairo_status_t status;

    if (in->cw.x == out->cw.x
	&& in->cw.y == out->cw.y
	&& in->ccw.x == out->ccw.x
	&& in->ccw.y == out->ccw.y)
    {
	return CAIRO_STATUS_SUCCESS;
    }

    if (clockwise) {
	inpt = &in->ccw;
	outpt = &out->ccw;
    } else {
	inpt = &in->cw;
	outpt = &out->cw;
    }

    switch (stroker->style->line_join) {
    case CAIRO_LINE_JOIN_ROUND: {
	int i;
	int start, step, stop;
	cairo_point_t tri[3];
	cairo_pen_t *pen = &stroker->pen;

	tri[0] = in->point;
	if (clockwise) {
	    start =
		_cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector);
	    stop =
		_cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector);
	    step = -1;
	} else {
	    start =
		_cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector);
	    stop =
		_cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector);
	    step = +1;
	}

	i = start;
	tri[1] = *inpt;
	while (i != stop) {
	    tri[2] = in->point;
	    _translate_point (&tri[2], &pen->vertices[i].point);
	    status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
	    if (unlikely (status))
		return status;
	    tri[1] = tri[2];
	    i += step;
	    if (i < 0)
		i = pen->num_vertices - 1;
	    if (i >= pen->num_vertices)
		i = 0;
	}

	tri[2] = *outpt;

	return _cairo_traps_tessellate_triangle (stroker->traps, tri);
    }
    case CAIRO_LINE_JOIN_MITER:
    default: {
	/* dot product of incoming slope vector with outgoing slope vector */
	double	in_dot_out = ((-in->usr_vector.x * out->usr_vector.x)+
			      (-in->usr_vector.y * out->usr_vector.y));
	double	ml = stroker->style->miter_limit;

	/* Check the miter limit -- lines meeting at an acute angle
	 * can generate long miters, the limit converts them to bevel
	 *
	 * Consider the miter join formed when two line segments
	 * meet at an angle psi:
	 *
	 *	   /.\
	 *	  /. .\
	 *	 /./ \.\
	 *	/./psi\.\
	 *
	 * We can zoom in on the right half of that to see:
	 *
	 *	    |\
	 *	    | \ psi/2
	 *	    |  \
	 *	    |   \
	 *	    |    \
	 *	    |     \
	 *	  miter    \
	 *	 length     \
	 *	    |        \
	 *	    |        .\
	 *	    |    .     \
	 *	    |.   line   \
	 *	     \    width  \
	 *	      \           \
	 *
	 *
	 * The right triangle in that figure, (the line-width side is
	 * shown faintly with three '.' characters), gives us the
	 * following expression relating miter length, angle and line
	 * width:
	 *
	 *	1 /sin (psi/2) = miter_length / line_width
	 *
	 * The right-hand side of this relationship is the same ratio
	 * in which the miter limit (ml) is expressed. We want to know
	 * when the miter length is within the miter limit. That is
	 * when the following condition holds:
	 *
	 *	1/sin(psi/2) <= ml
	 *	1 <= ml sin(psi/2)
	 *	1 <= ml² sin²(psi/2)
	 *	2 <= ml² 2 sin²(psi/2)
	 *				2·sin²(psi/2) = 1-cos(psi)
	 *	2 <= ml² (1-cos(psi))
	 *
	 *				in · out = |in| |out| cos (psi)
	 *
	 * in and out are both unit vectors, so:
	 *
	 *				in · out = cos (psi)
	 *
	 *	2 <= ml² (1 - in · out)
	 *
	 */
	if (2 <= ml * ml * (1 - in_dot_out))
	{
	    double		x1, y1, x2, y2;
	    double		mx, my;
	    double		dx1, dx2, dy1, dy2;
	    cairo_point_t	outer;
	    cairo_point_t	quad[4];
	    double		ix, iy;
	    double		fdx1, fdy1, fdx2, fdy2;
	    double		mdx, mdy;

	    /*
	     * we've got the points already transformed to device
	     * space, but need to do some computation with them and
	     * also need to transform the slope from user space to
	     * device space
	     */
	    /* outer point of incoming line face */
	    x1 = _cairo_fixed_to_double (inpt->x);
	    y1 = _cairo_fixed_to_double (inpt->y);
	    dx1 = in->usr_vector.x;
	    dy1 = in->usr_vector.y;
	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);

	    /* outer point of outgoing line face */
	    x2 = _cairo_fixed_to_double (outpt->x);
	    y2 = _cairo_fixed_to_double (outpt->y);
	    dx2 = out->usr_vector.x;
	    dy2 = out->usr_vector.y;
	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);

	    /*
	     * Compute the location of the outer corner of the miter.
	     * That's pretty easy -- just the intersection of the two
	     * outer edges.  We've got slopes and points on each
	     * of those edges.  Compute my directly, then compute
	     * mx by using the edge with the larger dy; that avoids
	     * dividing by values close to zero.
	     */
	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
		  (dx1 * dy2 - dx2 * dy1));
	    if (fabs (dy1) >= fabs (dy2))
		mx = (my - y1) * dx1 / dy1 + x1;
	    else
		mx = (my - y2) * dx2 / dy2 + x2;

	    /*
	     * When the two outer edges are nearly parallel, slight
	     * perturbations in the position of the outer points of the lines
	     * caused by representing them in fixed point form can cause the
	     * intersection point of the miter to move a large amount. If
	     * that moves the miter intersection from between the two faces,
	     * then draw a bevel instead.
	     */

	    ix = _cairo_fixed_to_double (in->point.x);
	    iy = _cairo_fixed_to_double (in->point.y);

	    /* slope of one face */
	    fdx1 = x1 - ix; fdy1 = y1 - iy;

	    /* slope of the other face */
	    fdx2 = x2 - ix; fdy2 = y2 - iy;

	    /* slope from the intersection to the miter point */
	    mdx = mx - ix; mdy = my - iy;

	    /*
	     * Make sure the miter point line lies between the two
	     * faces by comparing the slopes
	     */
	    if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
		_cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
	    {
		/*
		 * Draw the quadrilateral
		 */
		outer.x = _cairo_fixed_from_double (mx);
		outer.y = _cairo_fixed_from_double (my);

		quad[0] = in->point;
		quad[1] = *inpt;
		quad[2] = outer;
		quad[3] = *outpt;

		return _cairo_traps_tessellate_convex_quad (stroker->traps, quad);
	    }
	}
	/* fall through ... */
    }
    case CAIRO_LINE_JOIN_BEVEL: {
	cairo_point_t tri[3];
	tri[0] = in->point;
	tri[1] = *inpt;
	tri[2] = *outpt;

	return _cairo_traps_tessellate_triangle (stroker->traps, tri);
    }
    }
}
コード例 #6
0
ファイル: cairo-pen.c プロジェクト: 3oyka/cairo2
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;
	}
    }
}