static int _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) { cairo_fixed_16_16_t dx1, dx2, dy1, dy2; cairo_fixed_32_32_t den_det; cairo_fixed_32_32_t l1_det, l2_det; cairo_fixed_64_64_t num_det; cairo_fixed_32_32_t intersect_32_32; cairo_fixed_48_16_t intersect_48_16; cairo_fixed_16_16_t intersect_16_16; cairo_quorem128_t qr; dx1 = l1->p1.x - l1->p2.x; dy1 = l1->p1.y - l1->p2.y; dx2 = l2->p1.x - l2->p2.x; dy2 = l2->p1.y - l2->p2.y; den_det = _det16_32 (dx1, dy1, dx2, dy2); if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0))) return 0; l1_det = _det16_32 (l1->p1.x, l1->p1.y, l1->p2.x, l1->p2.y); l2_det = _det16_32 (l2->p1.x, l2->p1.y, l2->p2.x, l2->p2.y); num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1), l2_det, _fixed_16_16_to_fixed_32_32 (dy2)); /* * Ok, this one is a bit tricky in fixed point, the denominator * needs to be left with 32-bits of fraction so that the * result of the divide ends up with 32-bits of fraction (64 - 32 = 32) */ qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det)); intersect_32_32 = _cairo_int128_to_int64 (qr.quo); /* * Find the ceiling of the quotient -- divrem returns * the quotient truncated towards zero, so if the * quotient should be positive (num_den and den_det have same sign) * bump the quotient up by one. */ if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) && (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) == _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0)))) { intersect_32_32 = _cairo_int64_add (intersect_32_32, _cairo_int32_to_int64 (1)); } /* * Now convert from 32.32 to 48.16 and take the ceiling; * this requires adding in 15 1 bits and shifting the result */ intersect_32_32 = _cairo_int64_add (intersect_32_32, _cairo_int32_to_int64 ((1 << 16) - 1)); intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16); /* * And drop the top bits */ intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16); *y_intersection = intersect_16_16; return 1; }
/* Compute the intersection of two lines as defined by two edges. The * result is provided as a coordinate pair of 128-bit integers. * * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel. */ static cairo_bool_t intersect_lines (cairo_bo_edge_t *a, cairo_bo_edge_t *b, cairo_bo_intersect_point_t *intersection) { cairo_int64_t a_det, b_det; /* XXX: We're assuming here that dx and dy will still fit in 32 * bits. That's not true in general as there could be overflow. We * should prevent that before the tessellation algorithm begins. * What we're doing to mitigate this is to perform clamping in * cairo_bo_tessellate_polygon(). */ int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x; int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y; int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x; int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y; cairo_int64_t den_det; cairo_int64_t R; cairo_quorem64_t qr; den_det = det32_64 (dx1, dy1, dx2, dy2); /* Q: Can we determine that the lines do not intersect (within range) * much more cheaply than computing the intersection point i.e. by * avoiding the division? * * X = ax + t * adx = bx + s * bdx; * Y = ay + t * ady = by + s * bdy; * ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx) * => t * L = R * * Therefore we can reject any intersection (under the criteria for * valid intersection events) if: * L^R < 0 => t < 0, or * L<R => t > 1 * * (where top/bottom must at least extend to the line endpoints). * * A similar substitution can be performed for s, yielding: * s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by) */ R = det32_64 (dx2, dy2, b->edge.line.p1.x - a->edge.line.p1.x, b->edge.line.p1.y - a->edge.line.p1.y); if (_cairo_int64_negative (den_det)) { if (_cairo_int64_ge (den_det, R)) return FALSE; } else { if (_cairo_int64_le (den_det, R)) return FALSE; } R = det32_64 (dy1, dx1, a->edge.line.p1.y - b->edge.line.p1.y, a->edge.line.p1.x - b->edge.line.p1.x); if (_cairo_int64_negative (den_det)) { if (_cairo_int64_ge (den_det, R)) return FALSE; } else { if (_cairo_int64_le (den_det, R)) return FALSE; } /* We now know that the two lines should intersect within range. */ a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y, a->edge.line.p2.x, a->edge.line.p2.y); b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y, b->edge.line.p2.x, b->edge.line.p2.y); /* x = det (a_det, dx1, b_det, dx2) / den_det */ qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1, b_det, dx2), den_det); if (_cairo_int64_eq (qr.rem, den_det)) return FALSE; #if 0 intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; #else intersection->x.exactness = EXACT; if (! _cairo_int64_is_zero (qr.rem)) { if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) qr.rem = _cairo_int64_negate (qr.rem); qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); if (_cairo_int64_ge (qr.rem, den_det)) { qr.quo = _cairo_int64_add (qr.quo, _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); } else intersection->x.exactness = INEXACT; } #endif intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo); /* y = det (a_det, dy1, b_det, dy2) / den_det */ qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1, b_det, dy2), den_det); if (_cairo_int64_eq (qr.rem, den_det)) return FALSE; #if 0 intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; #else intersection->y.exactness = EXACT; if (! _cairo_int64_is_zero (qr.rem)) { if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) qr.rem = _cairo_int64_negate (qr.rem); qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); if (_cairo_int64_ge (qr.rem, den_det)) { qr.quo = _cairo_int64_add (qr.quo, _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); } else intersection->y.exactness = INEXACT; } #endif intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo); return TRUE; }