/* Warning: This function reorders the elements of the array provided. */ cairo_status_t _cairo_traps_tessellate_rectangle (cairo_traps_t *traps, cairo_point_t q[4]) { cairo_status_t status; qsort (q, 4, sizeof (cairo_point_t), _compare_point_fixed_by_y); if (q[1].x > q[2].x) { status = _cairo_traps_add_trap_from_points (traps, q[0].y, q[1].y, q[0], q[2], q[0], q[1]); if (status) return status; status = _cairo_traps_add_trap_from_points (traps, q[1].y, q[2].y, q[0], q[2], q[1], q[3]); if (status) return status; status = _cairo_traps_add_trap_from_points (traps, q[2].y, q[3].y, q[2], q[3], q[1], q[3]); if (status) return status; } else { status = _cairo_traps_add_trap_from_points (traps, q[0].y, q[1].y, q[0], q[1], q[0], q[2]); if (status) return status; status = _cairo_traps_add_trap_from_points (traps, q[1].y, q[2].y, q[1], q[3], q[0], q[2]); if (status) return status; status = _cairo_traps_add_trap_from_points (traps, q[2].y, q[3].y, q[1], q[3], q[2], q[3]); if (status) return status; } return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4]) { int a, b, c, d; int i; cairo_slope_t ab, ad; cairo_bool_t b_left_of_d; /* 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 */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, q[a], q[b], q[a], q[d]); _cairo_traps_add_trap_from_points (traps, q[b].y, q[c].y, q[b], q[c], q[a], q[d]); _cairo_traps_add_trap_from_points (traps, q[c].y, q[d].y, q[c], q[d], q[a], q[d]); } 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 */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, q[a], q[d], q[a], q[b]); _cairo_traps_add_trap_from_points (traps, q[b].y, q[c].y, q[a], q[d], q[b], q[c]); _cairo_traps_add_trap_from_points (traps, q[c].y, q[d].y, q[a], q[d], q[c], q[d]); } } 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 */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, q[a], q[b], q[a], q[d]); _cairo_traps_add_trap_from_points (traps, q[b].y, q[d].y, q[b], q[c], q[a], q[d]); _cairo_traps_add_trap_from_points (traps, q[d].y, q[c].y, q[b], q[c], q[d], q[c]); } 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 */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, q[a], q[d], q[a], q[b]); _cairo_traps_add_trap_from_points (traps, q[b].y, q[d].y, q[a], q[d], q[b], q[c]); _cairo_traps_add_trap_from_points (traps, q[d].y, q[c].y, q[d], q[c], q[b], q[c]); } } return traps->status; }
cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]) { cairo_status_t status; cairo_line_t line; cairo_fixed_16_16_t intersect; cairo_point_t tsort[3]; memcpy (tsort, t, 3 * sizeof (cairo_point_t)); qsort (tsort, 3, sizeof (cairo_point_t), _compare_point_fixed_by_y); /* horizontal top edge requires special handling */ if (tsort[0].y == tsort[1].y) { if (tsort[0].x < tsort[1].x) status = _cairo_traps_add_trap_from_points (traps, tsort[1].y, tsort[2].y, tsort[0], tsort[2], tsort[1], tsort[2]); else status = _cairo_traps_add_trap_from_points (traps, tsort[1].y, tsort[2].y, tsort[1], tsort[2], tsort[0], tsort[2]); return status; } line.p1 = tsort[0]; line.p2 = tsort[1]; intersect = _compute_x (&line, tsort[2].y); if (intersect < tsort[2].x) { status = _cairo_traps_add_trap_from_points (traps, tsort[0].y, tsort[1].y, tsort[0], tsort[1], tsort[0], tsort[2]); if (status) return status; status = _cairo_traps_add_trap_from_points (traps, tsort[1].y, tsort[2].y, tsort[1], tsort[2], tsort[0], tsort[2]); if (status) return status; } else { status = _cairo_traps_add_trap_from_points (traps, tsort[0].y, tsort[1].y, tsort[0], tsort[2], tsort[0], tsort[1]); if (status) return status; status = _cairo_traps_add_trap_from_points (traps, tsort[1].y, tsort[2].y, tsort[0], tsort[2], tsort[1], tsort[2]); if (status) return status; } return CAIRO_STATUS_SUCCESS; }