/* 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; } }
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); }
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); }
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; } } }
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; }
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; }