SkScalar SkPoint::Normalize(SkPoint* pt) { float x = pt->fX; float y = pt->fY; float mag2; if (isLengthNearlyZero(x, y, &mag2)) { return 0; } float mag, scale; if (SkScalarIsFinite(mag2)) { mag = sk_float_sqrt(mag2); scale = 1 / mag; } else { // our mag2 step overflowed to infinity, so use doubles instead. // much slower, but needed when x or y are very large, other wise we // divide by inf. and return (0,0) vector. double xx = x; double yy = y; double magmag = sqrt(xx * xx + yy * yy); mag = (float)magmag; // we perform the divide with the double magmag, to stay exactly the // same as setLength. It would be faster to perform the divide with // mag, but it is possible that mag has overflowed to inf. but still // have a non-zero value for scale (thanks to denormalized numbers). scale = (float)(1 / magmag); } pt->set(x * scale, y * scale); return mag; }
/* * We have to worry about 2 tricky conditions: * 1. underflow of mag2 (compared against nearlyzero^2) * 2. overflow of mag2 (compared w/ isfinite) * * If we underflow, we return false. If we overflow, we compute again using * doubles, which is much slower (3x in a desktop test) but will not overflow. */ bool SkPoint::setLength(float x, float y, float length) { float mag2; if (isLengthNearlyZero(x, y, &mag2)) { return false; } float scale; if (SkScalarIsFinite(mag2)) { scale = length / sk_float_sqrt(mag2); } else { // our mag2 step overflowed to infinity, so use doubles instead. // much slower, but needed when x or y are very large, other wise we // divide by inf. and return (0,0) vector. double xx = x; double yy = y; #ifdef SK_DISCARD_DENORMALIZED_FOR_SPEED // The iOS ARM processor discards small denormalized numbers to go faster. // Casting this to a float would cause the scale to go to zero. Keeping it // as a double for the multiply keeps the scale non-zero. double dscale = length / sqrt(xx * xx + yy * yy); fX = x * dscale; fY = y * dscale; return true; #else scale = (float)(length / sqrt(xx * xx + yy * yy)); #endif } fX = x * scale; fY = y * scale; return true; }
bool SkPoint::setLength(float x, float y, float length) { float mag2; if (!isLengthNearlyZero(x, y, &mag2)) { float scale = length / sk_float_sqrt(mag2); fX = x * scale; fY = y * scale; return true; } return false; }
SkScalar SkPoint::Normalize(SkPoint* pt) { Sk64 mag2; if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) { SkScalar mag = mag2.getSqrt(); SkScalar scale = SkScalarInvert(mag); pt->fX = SkScalarMul(pt->fX, scale); pt->fY = SkScalarMul(pt->fY, scale); return mag; } return 0; }
SkScalar SkPoint::Normalize(SkPoint* pt) { float mag2; if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) { float mag = sk_float_sqrt(mag2); float scale = 1.0f / mag; pt->fX = pt->fX * scale; pt->fY = pt->fY * scale; return mag; } return 0; }
bool SkPoint::setLengthFast(float x, float y, float length) { float mag2; if (isLengthNearlyZero(x, y, &mag2)) { return false; } float scale; if (SkScalarIsFinite(mag2)) { scale = length * sk_float_rsqrt(mag2); // <--- this is the difference } else { // our mag2 step overflowed to infinity, so use doubles instead. // much slower, but needed when x or y are very large, other wise we // divide by inf. and return (0,0) vector. double xx = x; double yy = y; scale = (float)(length / sqrt(xx * xx + yy * yy)); } fX = x * scale; fY = y * scale; return true; }
bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) { Sk64 mag2_unused; return !isLengthNearlyZero(dx, dy, &mag2_unused); }