#if (CAIRO_FIXED_BITS != 32) # error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type. # error To remove this limitation, you will have to fix the tessellator. #endif
/* This is the "magic number" approach to converting a double into fixed * point as described here: * * http://www.stereopsis.com/sree/fpu2006.html (an overview) * http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail) * * The basic idea is to add a large enough number to the double that the * literal floating point is moved up to the extent that it forces the * double's value to be shifted down to the bottom of the mantissa (to make * room for the large number being added in). Since the mantissa is, at a * given moment in time, a fixed point integer itself, one can convert a * float to various fixed point representations by moving around the point * of a floating point number through arithmetic operations. This behavior * is reliable on most modern platforms as it is mandated by the IEEE-754 * standard for floating point arithmetic. * * For our purposes, a "magic number" must be carefully selected that is * both large enough to produce the desired point-shifting effect, and also * has no lower bits in its representation that would interfere with our * value at the bottom of the mantissa. The magic number is calculated as * follows: * * (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5 * * where in our case: * - MANTISSA_SIZE for 64-bit doubles is 52 * - FRACTIONAL_SIZE for 16.16 fixed point is 16 * * Although this approach provides a very large speedup of this function * on a wide-array of systems, it does come with two caveats: * * 1) It uses banker's rounding as opposed to arithmetic rounding. * 2) It doesn't function properly if the FPU is in single-precision * mode.
*/
/* The 16.16 number must always be available */ #define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0)
/* A bunch of explicit 16.16 operators; we need these * to interface with pixman and other backends that require * 16.16 fixed point types.
*/ staticinline cairo_fixed_16_16_t
_cairo_fixed_to_16_16 (cairo_fixed_t f)
{ #if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32) return f; #elif CAIRO_FIXED_FRAC_BITS > 16 /* We're just dropping the low bits, so we won't ever got over/underflow here */ return f >> (CAIRO_FIXED_FRAC_BITS - 16); #else
cairo_fixed_16_16_t x;
/* Handle overflow/underflow by clamping to the lowest/highest * value representable as 16.16
*/ if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) {
x = INT32_MIN;
} elseif ((f >> CAIRO_FIXED_FRAC_BITS) > INT16_MAX) {
x = INT32_MAX;
} else {
x = f << (16 - CAIRO_FIXED_FRAC_BITS);
}
staticinline cairo_fixed_t
_cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
{
cairo_int64_t temp = _cairo_int32x32_64_mul (a, b); return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
/* computes round (a * b / c) */ staticinline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c); return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo);
}
/* computes floor (a * b / c) */ staticinline cairo_fixed_t
_cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{ return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c);
}
/* compute y from x so that (x,y), p1, and p2 are collinear */ staticinline cairo_fixed_t
_cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1, const cairo_point_t *p2,
cairo_fixed_t x)
{
cairo_fixed_t y, dx;
if (x == p1->x) return p1->y; if (x == p2->x) return p2->y;
y = p1->y;
dx = p2->x - p1->x; if (dx != 0)
y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx);
return y;
}
/* compute x from y so that (x,y), p1, and p2 are collinear */ staticinline cairo_fixed_t
_cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1, const cairo_point_t *p2,
cairo_fixed_t y)
{
cairo_fixed_t x, dy;
if (y == p1->y) return p1->x; if (y == p2->y) return p2->x;
x = p1->x;
dy = p2->y - p1->y; if (dy != 0)
x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy);
return x;
}
/* Intersect two segments based on the algorithm described at * http://paulbourke.net/geometry/pointlineplane/. This implementation
* uses floating point math. */ staticinline cairo_bool_t
_slow_segment_intersection (const cairo_point_t *seg1_p1, const cairo_point_t *seg1_p2, const cairo_point_t *seg2_p1, const cairo_point_t *seg2_p2,
cairo_point_t *intersection)
{ double denominator, u_a, u_b; double seg1_dx, seg1_dy, seg2_dx, seg2_dy, seg_start_dx, seg_start_dy;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.