Ejemplo n.º 1
0
/* Does the given edge contain the given point. The point must already
 * be known to be contained within the line determined by the edge,
 * (most likely the point results from an intersection of this edge
 * with another).
 *
 * If we had exact arithmetic, then this function would simply be a
 * matter of examining whether the y value of the point lies within
 * the range of y values of the edge. But since intersection points
 * are not exact due to being rounded to the nearest integer within
 * the available precision, we must also examine the x value of the
 * point.
 *
 * The definition of "contains" here is that the given intersection
 * point will be seen by the sweep line after the start event for the
 * given edge and before the stop event for the edge. See the comments
 * in the implementation for more details.
 */
static cairo_bool_t
_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t		*edge,
					 cairo_bo_intersect_point_t	*point)
{
    int cmp_top, cmp_bottom;

    /* XXX: When running the actual algorithm, we don't actually need to
     * compare against edge->top at all here, since any intersection above
     * top is eliminated early via a slope comparison. We're leaving these
     * here for now only for the sake of the quadratic-time intersection
     * finder which needs them.
     */

    cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y,
						       edge->edge.top);
    cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y,
							  edge->edge.bottom);

    if (cmp_top < 0 || cmp_bottom > 0)
    {
	return FALSE;
    }

    if (cmp_top > 0 && cmp_bottom < 0)
    {
	return TRUE;
    }

    /* At this stage, the point lies on the same y value as either
     * edge->top or edge->bottom, so we have to examine the x value in
     * order to properly determine containment. */

    /* If the y value of the point is the same as the y value of the
     * top of the edge, then the x value of the point must be greater
     * to be considered as inside the edge. Similarly, if the y value
     * of the point is the same as the y value of the bottom of the
     * edge, then the x value of the point must be less to be
     * considered as inside. */

    if (cmp_top == 0) {
	cairo_fixed_t top_x;

	top_x = _line_compute_intersection_x_for_y (&edge->edge.line,
						    edge->edge.top);
	return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0;
    } else { /* cmp_bottom == 0 */
	cairo_fixed_t bot_x;

	bot_x = _line_compute_intersection_x_for_y (&edge->edge.line,
						    edge->edge.bottom);
	return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0;
    }
}
Ejemplo n.º 2
0
static cairo_status_t
_cairo_bo_event_queue_insert_stop (cairo_bo_event_queue_t	*event_queue,
				   cairo_bo_edge_t		*edge)
{
    cairo_bo_point32_t point;

    point.y = edge->edge.bottom;
    point.x = _line_compute_intersection_x_for_y (&edge->edge.line,
						  point.y);
    return _cairo_bo_event_queue_insert (event_queue,
					 CAIRO_BO_EVENT_TYPE_STOP,
					 edge, NULL,
					 &point);
}
Ejemplo n.º 3
0
static cairo_status_t
event_queue_insert_stop (cairo_bo_event_queue_t	*event_queue,
			 cairo_bo_edge_t		*edge)
{
    cairo_bo_intersect_point_t point;

    point.y.ordinate = edge->edge.bottom;
    point.y.approx   = EXACT;
    point.x.ordinate = _line_compute_intersection_x_for_y (&edge->edge.line,
							   point.y.ordinate);
    point.x.approx   = EXACT;

    return _cairo_bo_event_queue_insert (event_queue,
					 CAIRO_BO_EVENT_TYPE_STOP,
					 edge, NULL,
					 &point);
}
Ejemplo n.º 4
0
void
_cairo_traps_extents (const cairo_traps_t *traps,
		      cairo_box_t *extents)
{
    int i;

    if (traps->num_traps == 0) {
	extents->p1.x = extents->p1.y = 0;
	extents->p2.x = extents->p2.y = 0;
	return;
    }

    extents->p1.x = extents->p1.y = INT32_MAX;
    extents->p2.x = extents->p2.y = INT32_MIN;

    for (i = 0; i < traps->num_traps; i++) {
	const cairo_trapezoid_t *trap =  &traps->traps[i];

	if (trap->top < extents->p1.y)
	    extents->p1.y = trap->top;
	if (trap->bottom > extents->p2.y)
	    extents->p2.y = trap->bottom;

	if (trap->left.p1.x < extents->p1.x) {
	    cairo_fixed_t x = trap->left.p1.x;
	    if (trap->top != trap->left.p1.y) {
		x = _line_compute_intersection_x_for_y (&trap->left,
							trap->top);
		if (x < extents->p1.x)
		    extents->p1.x = x;
	    } else
		extents->p1.x = x;
	}
	if (trap->left.p2.x < extents->p1.x) {
	    cairo_fixed_t x = trap->left.p2.x;
	    if (trap->bottom != trap->left.p2.y) {
		x = _line_compute_intersection_x_for_y (&trap->left,
							trap->bottom);
		if (x < extents->p1.x)
		    extents->p1.x = x;
	    } else
		extents->p1.x = x;
	}

	if (trap->right.p1.x > extents->p2.x) {
	    cairo_fixed_t x = trap->right.p1.x;
	    if (trap->top != trap->right.p1.y) {
		x = _line_compute_intersection_x_for_y (&trap->right,
							trap->top);
		if (x > extents->p2.x)
		    extents->p2.x = x;
	    } else
		extents->p2.x = x;
	}
	if (trap->right.p2.x > extents->p2.x) {
	    cairo_fixed_t x = trap->right.p2.x;
	    if (trap->bottom != trap->right.p2.y) {
		x = _line_compute_intersection_x_for_y (&trap->right,
							trap->bottom);
		if (x > extents->p2.x)
		    extents->p2.x = x;
	    } else
		extents->p2.x = x;
	}
    }
}
Ejemplo n.º 5
0
cairo_status_t
_cairo_polygon_intersect (cairo_polygon_t *a, int winding_a,
			  cairo_polygon_t *b, int winding_b)
{
    cairo_status_t status;
    cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
    cairo_bo_start_event_t *events;
    cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
    cairo_bo_event_t **event_ptrs;
    int num_events;
    int i, j;

    /* XXX lazy */
    if (winding_a != CAIRO_FILL_RULE_WINDING) {
	status = _cairo_polygon_reduce (a, winding_a);
	if (unlikely (status))
	    return status;
    }

    if (winding_b != CAIRO_FILL_RULE_WINDING) {
	status = _cairo_polygon_reduce (b, winding_b);
	if (unlikely (status))
	    return status;
    }

    if (unlikely (0 == a->num_edges))
	return CAIRO_STATUS_SUCCESS;

    if (unlikely (0 == b->num_edges)) {
	a->num_edges = 0;
	return CAIRO_STATUS_SUCCESS;
    }

    events = stack_events;
    event_ptrs = stack_event_ptrs;
    num_events = a->num_edges + b->num_edges;
    if (num_events > ARRAY_LENGTH (stack_events)) {
	events = _cairo_malloc_ab_plus_c (num_events,
					  sizeof (cairo_bo_start_event_t) +
					  sizeof (cairo_bo_event_t *),
					  sizeof (cairo_bo_event_t *));
	if (unlikely (events == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	event_ptrs = (cairo_bo_event_t **) (events + num_events);
    }

    j = 0;
    for (i = 0; i < a->num_edges; i++) {
	event_ptrs[j] = (cairo_bo_event_t *) &events[j];

	events[j].type = CAIRO_BO_EVENT_TYPE_START;
	events[j].point.y.ordinate = a->edges[i].top;
	events[j].point.y.approx = EXACT;
	events[j].point.x.ordinate =
	    _line_compute_intersection_x_for_y (&a->edges[i].line,
						events[j].point.y.ordinate);
	events[j].point.x.approx = EXACT;

	events[j].edge.a_or_b = 0;
	events[j].edge.edge = a->edges[i];
	events[j].edge.deferred.other = NULL;
	events[j].edge.prev = NULL;
	events[j].edge.next = NULL;
	j++;
    }

    for (i = 0; i < b->num_edges; i++) {
	event_ptrs[j] = (cairo_bo_event_t *) &events[j];

	events[j].type = CAIRO_BO_EVENT_TYPE_START;
	events[j].point.y.ordinate = b->edges[i].top;
	events[j].point.y.approx = EXACT;
	events[j].point.x.ordinate =
	    _line_compute_intersection_x_for_y (&b->edges[i].line,
						events[j].point.y.ordinate);
	events[j].point.x.approx = EXACT;

	events[j].edge.a_or_b = 1;
	events[j].edge.edge = b->edges[i];
	events[j].edge.deferred.other = NULL;
	events[j].edge.prev = NULL;
	events[j].edge.next = NULL;
	j++;
    }
    assert (j == num_events);

#if 0
    {
	FILE *file = fopen ("clip_a.txt", "w");
	_cairo_debug_print_polygon (file, a);
	fclose (file);
    }
    {
	FILE *file = fopen ("clip_b.txt", "w");
	_cairo_debug_print_polygon (file, b);
	fclose (file);
    }
#endif

    a->num_edges = 0;
    status = intersection_sweep (event_ptrs, num_events, a);
    if (events != stack_events)
	free (events);

#if 0
    {
	FILE *file = fopen ("clip_result.txt", "w");
	_cairo_debug_print_polygon (file, a);
	fclose (file);
    }
#endif

    return status;
}
Ejemplo n.º 6
0
cairo_status_t
_cairo_polygon_reduce (cairo_polygon_t *polygon,
		       cairo_fill_rule_t fill_rule)
{
    cairo_status_t status;
    cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
    cairo_bo_start_event_t *events;
    cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
    cairo_bo_event_t **event_ptrs;
    int num_limits;
    int num_events;
    int i;

    num_events = polygon->num_edges;
    if (unlikely (0 == num_events))
	return CAIRO_STATUS_SUCCESS;

    if (DEBUG_POLYGON) {
	FILE *file = fopen ("reduce_in.txt", "w");
	_cairo_debug_print_polygon (file, polygon);
	fclose (file);
    }

    events = stack_events;
    event_ptrs = stack_event_ptrs;
    if (num_events > ARRAY_LENGTH (stack_events)) {
	events = _cairo_malloc_ab_plus_c (num_events,
					  sizeof (cairo_bo_start_event_t) +
					  sizeof (cairo_bo_event_t *),
					  sizeof (cairo_bo_event_t *));
	if (unlikely (events == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	event_ptrs = (cairo_bo_event_t **) (events + num_events);
    }

    for (i = 0; i < num_events; i++) {
	event_ptrs[i] = (cairo_bo_event_t *) &events[i];

	events[i].type = CAIRO_BO_EVENT_TYPE_START;
	events[i].point.y = polygon->edges[i].top;
	events[i].point.x =
	    _line_compute_intersection_x_for_y (&polygon->edges[i].line,
						events[i].point.y);

	events[i].edge.edge = polygon->edges[i];
	events[i].edge.deferred.right = NULL;
	events[i].edge.prev = NULL;
	events[i].edge.next = NULL;
    }

    num_limits = polygon->num_limits; polygon->num_limits = 0;
    polygon->num_edges = 0;

    status = _cairo_bentley_ottmann_tessellate_bo_edges (event_ptrs,
							 num_events,
							 fill_rule,
							 polygon);
    polygon->num_limits = num_limits;

    if (events != stack_events)
	free (events);

    if (DEBUG_POLYGON) {
	FILE *file = fopen ("reduce_out.txt", "w");
	_cairo_debug_print_polygon (file, polygon);
	fclose (file);
    }

    return status;
}