/* Solve coeff(t) == 0, returning the number of roots that lie withing 0 < t < 1. coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3] Eliminates repeated roots (so that all tValues are distinct, and are always in increasing order. */ static int solve_cubic_polynomial(const SkFP coeff[4], SkScalar tValues[3]) { #ifndef SK_SCALAR_IS_FLOAT return 0; // this is not yet implemented for software float #endif if (SkScalarNearlyZero(coeff[0])) // we're just a quadratic { return SkFindUnitQuadRoots(coeff[1], coeff[2], coeff[3], tValues); } SkFP a, b, c, Q, R; { SkASSERT(coeff[0] != 0); SkFP inva = SkFPInvert(coeff[0]); a = SkFPMul(coeff[1], inva); b = SkFPMul(coeff[2], inva); c = SkFPMul(coeff[3], inva); } Q = SkFPDivInt(SkFPSub(SkFPMul(a,a), SkFPMulInt(b, 3)), 9); // R = (2*a*a*a - 9*a*b + 27*c) / 54; R = SkFPMulInt(SkFPMul(SkFPMul(a, a), a), 2); R = SkFPSub(R, SkFPMulInt(SkFPMul(a, b), 9)); R = SkFPAdd(R, SkFPMulInt(c, 27)); R = SkFPDivInt(R, 54); SkFP Q3 = SkFPMul(SkFPMul(Q, Q), Q); SkFP R2MinusQ3 = SkFPSub(SkFPMul(R,R), Q3); SkFP adiv3 = SkFPDivInt(a, 3); SkScalar* roots = tValues; SkScalar r; if (SkFPLT(R2MinusQ3, 0)) // we have 3 real roots { #ifdef SK_SCALAR_IS_FLOAT float theta = sk_float_acos(R / sk_float_sqrt(Q3)); float neg2RootQ = -2 * sk_float_sqrt(Q); r = neg2RootQ * sk_float_cos(theta/3) - adiv3; if (is_unit_interval(r)) *roots++ = r; r = neg2RootQ * sk_float_cos((theta + 2*SK_ScalarPI)/3) - adiv3; if (is_unit_interval(r)) *roots++ = r; r = neg2RootQ * sk_float_cos((theta - 2*SK_ScalarPI)/3) - adiv3; if (is_unit_interval(r)) *roots++ = r; SkDEBUGCODE(test_collaps_duplicates();)
SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const { #ifdef SK_SCALAR_IS_FLOAT float mag = sk_float_sqrt(fX*fX + fY*fY + fZ*fZ); if (mag) { float scale = 1.0f / mag; unit->fX = fX * scale; unit->fY = fY * scale; unit->fZ = fZ * scale; } #else Sk64 tmp1, tmp2; tmp1.setMul(fX, fX); tmp2.setMul(fY, fY); tmp1.add(tmp2); tmp2.setMul(fZ, fZ); tmp1.add(tmp2); SkFixed mag = tmp1.getSqrt(); if (mag) { // what if mag < SK_Fixed1 ??? we will underflow the fixdiv SkFixed scale = SkFixedDiv(SK_Fract1, mag); unit->fX = SkFixedMul(fX, scale); unit->fY = SkFixedMul(fY, scale); unit->fZ = SkFixedMul(fZ, scale); } #endif return mag; }
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 mag = sk_float_sqrt(x * x + y * y); if (mag > SK_ScalarNearlyZero) { length /= mag; fX = x * length; fY = y * length; return true; } return false; }
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::Length(SkScalar dx, SkScalar dy) { float mag2 = dx * dx + dy * dy; if (SkScalarIsFinite(mag2)) { return sk_float_sqrt(mag2); } else { double xx = dx; double yy = dy; return (float)sqrt(xx * xx + yy * yy); } }
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; }
// Return the number of distinct real roots, and write them into roots[] in // ascending order static int find_quad_roots(float A, float B, float C, float roots[2], bool descendingOrder = false) { SkASSERT(roots); if (A == 0) { return valid_divide(-C, B, roots); } float R = B*B - 4*A*C; if (R < 0) { return 0; } R = sk_float_sqrt(R); #if 1 float Q = B; if (Q < 0) { Q -= R; } else { Q += R; } #else // on 10.6 this was much slower than the above branch :( float Q = B + copysignf(R, B); #endif Q *= -0.5f; if (0 == Q) { roots[0] = 0; return 1; } float r0 = Q / A; float r1 = C / Q; roots[0] = r0 < r1 ? r0 : r1; roots[1] = r0 > r1 ? r0 : r1; if (descendingOrder) { SkTSwap(roots[0], roots[1]); } return 2; }
/** From Numerical Recipes in C. Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C]) x1 = Q / A x2 = C / Q */ int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) { SkASSERT(roots); if (A == 0) return valid_unit_divide(-C, B, roots); SkScalar* r = roots; #ifdef SK_SCALAR_IS_FLOAT float R = B*B - 4*A*C; if (R < 0 || SkScalarIsNaN(R)) { // complex roots return 0; } R = sk_float_sqrt(R); #else Sk64 RR, tmp; RR.setMul(B,B); tmp.setMul(A,C); tmp.shiftLeft(2); RR.sub(tmp); if (RR.isNeg()) return 0; SkFixed R = RR.getSqrt(); #endif SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2; r += valid_unit_divide(Q, A, r); r += valid_unit_divide(C, Q, r); if (r - roots == 2) { if (roots[0] > roots[1]) SkTSwap<SkScalar>(roots[0], roots[1]); else if (roots[0] == roots[1]) // nearly-equal? r -= 1; // skip the double root } return (int)(r - roots); }
/* Solve coeff(t) == 0, returning the number of roots that lie withing 0 < t < 1. coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3] */ static int solve_cubic_polynomial(const SkFP coeff[4], SkScalar tValues[3]) { #ifndef SK_SCALAR_IS_FLOAT return 0; // this is not yet implemented for software float #endif if (SkScalarNearlyZero(coeff[0])) // we're just a quadratic { return SkFindUnitQuadRoots(coeff[1], coeff[2], coeff[3], tValues); } SkFP a, b, c, Q, R; { SkASSERT(coeff[0] != 0); SkFP inva = SkFPInvert(coeff[0]); a = SkFPMul(coeff[1], inva); b = SkFPMul(coeff[2], inva); c = SkFPMul(coeff[3], inva); } Q = SkFPDivInt(SkFPSub(SkFPMul(a,a), SkFPMulInt(b, 3)), 9); // R = (2*a*a*a - 9*a*b + 27*c) / 54; R = SkFPMulInt(SkFPMul(SkFPMul(a, a), a), 2); R = SkFPSub(R, SkFPMulInt(SkFPMul(a, b), 9)); R = SkFPAdd(R, SkFPMulInt(c, 27)); R = SkFPDivInt(R, 54); SkFP Q3 = SkFPMul(SkFPMul(Q, Q), Q); SkFP R2MinusQ3 = SkFPSub(SkFPMul(R,R), Q3); SkFP adiv3 = SkFPDivInt(a, 3); SkScalar* roots = tValues; SkScalar r; if (SkFPLT(R2MinusQ3, 0)) // we have 3 real roots { #ifdef SK_SCALAR_IS_FLOAT float theta = sk_float_acos(R / sk_float_sqrt(Q3)); float neg2RootQ = -2 * sk_float_sqrt(Q); r = neg2RootQ * sk_float_cos(theta/3) - adiv3; if (is_unit_interval(r)) *roots++ = r; r = neg2RootQ * sk_float_cos((theta + 2*SK_ScalarPI)/3) - adiv3; if (is_unit_interval(r)) *roots++ = r; r = neg2RootQ * sk_float_cos((theta - 2*SK_ScalarPI)/3) - adiv3; if (is_unit_interval(r)) *roots++ = r; // now sort the roots bubble_sort(tValues, (int)(roots - tValues)); #endif } else // we have 1 real root { SkFP A = SkFPAdd(SkFPAbs(R), SkFPSqrt(R2MinusQ3)); A = SkFPCubeRoot(A); if (SkFPGT(R, 0)) A = SkFPNeg(A); if (A != 0) A = SkFPAdd(A, SkFPDiv(Q, A)); r = SkFPToScalar(SkFPSub(A, adiv3)); if (is_unit_interval(r)) *roots++ = r; } return (int)(roots - tValues); }
SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { return sk_float_sqrt(dx * dx + dy * dy); }
SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { return sk_float_sqrt(getLengthSquared(dx, dy)); }