// from SkGeometry.cpp (and Numeric Solutions, 5.6) int cubicRootsValidT(double A, double B, double C, double D, double t[3]) { #if 0 if (approximately_zero(A)) { // we're just a quadratic return quadraticRootsValidT(B, C, D, t); } double a, b, c; { double invA = 1 / A; a = B * invA; b = C * invA; c = D * invA; } double a2 = a * a; double Q = (a2 - b * 3) / 9; double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54; double Q3 = Q * Q * Q; double R2MinusQ3 = R * R - Q3; double adiv3 = a / 3; double* roots = t; double r; if (R2MinusQ3 < 0) // we have 3 real roots { double theta = acos(R / sqrt(Q3)); double neg2RootQ = -2 * sqrt(Q); r = neg2RootQ * cos(theta / 3) - adiv3; if (is_unit_interval(r)) *roots++ = r; r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3; if (is_unit_interval(r)) *roots++ = r; r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3; if (is_unit_interval(r)) *roots++ = r; } else // we have 1 real root { double A = fabs(R) + sqrt(R2MinusQ3); A = cube_root(A); if (R > 0) { A = -A; } if (A != 0) { A += Q / A; } r = A - adiv3; if (is_unit_interval(r)) *roots++ = r; } return (int)(roots - t); #else double s[3]; int realRoots = cubicRootsReal(A, B, C, D, s); int foundRoots = add_valid_ts(s, realRoots, t); return foundRoots; #endif }
/* 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();)
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[], const SkScalar tValues[], int roots) { #ifdef SK_DEBUG { for (int i = 0; i < roots - 1; i++) { SkASSERT(is_unit_interval(tValues[i])); SkASSERT(is_unit_interval(tValues[i+1])); SkASSERT(tValues[i] < tValues[i+1]); } } #endif if (dst) { if (roots == 0) // nothing to chop memcpy(dst, src, 4*sizeof(SkPoint)); else { SkScalar t = tValues[0]; SkPoint tmp[4]; for (int i = 0; i < roots; i++) { SkChopCubicAt(src, dst, t); if (i == roots - 1) break; dst += 3; // have src point to the remaining cubic (after the chop) memcpy(tmp, dst, 4 * sizeof(SkPoint)); src = tmp; // watch out in case the renormalized t isn't in range if (!valid_unit_divide(tValues[i+1] - tValues[i], SK_Scalar1 - tValues[i], &t)) { // if we can't, just create a degenerate cubic dst[4] = dst[5] = dst[6] = src[3]; break; } } } } }
/* 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_poly(const SkScalar coeff[4], SkScalar tValues[3]) { if (SkScalarNearlyZero(coeff[0])) { // we're just a quadratic return SkFindUnitQuadRoots(coeff[1], coeff[2], coeff[3], tValues); } SkScalar a, b, c, Q, R; { SkASSERT(coeff[0] != 0); SkScalar inva = SkScalarInvert(coeff[0]); a = coeff[1] * inva; b = coeff[2] * inva; c = coeff[3] * inva; } Q = (a*a - b*3) / 9; R = (2*a*a*a - 9*a*b + 27*c) / 54; SkScalar Q3 = Q * Q * Q; SkScalar R2MinusQ3 = R * R - Q3; SkScalar adiv3 = a / 3; SkScalar* roots = tValues; SkScalar r; if (R2MinusQ3 < 0) { // we have 3 real roots SkScalar theta = SkScalarACos(R / SkScalarSqrt(Q3)); SkScalar neg2RootQ = -2 * SkScalarSqrt(Q); r = neg2RootQ * SkScalarCos(theta/3) - adiv3; if (is_unit_interval(r)) { *roots++ = r; } r = neg2RootQ * SkScalarCos((theta + 2*SK_ScalarPI)/3) - adiv3; if (is_unit_interval(r)) { *roots++ = r; } r = neg2RootQ * SkScalarCos((theta - 2*SK_ScalarPI)/3) - adiv3; if (is_unit_interval(r)) { *roots++ = r; } SkDEBUGCODE(test_collaps_duplicates();)
/* 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); }