static SkScalar refine_cubic_root(const SkFP coeff[4], SkScalar root) { // x1 = x0 - f(t) / f'(t) SkFP T = SkScalarToFloat(root); SkFP N, D; // f' = 3*coeff[0]*T^2 + 2*coeff[1]*T + coeff[2] D = SkFPMul(SkFPMul(coeff[0], SkFPMul(T,T)), 3); D = SkFPAdd(D, SkFPMulInt(SkFPMul(coeff[1], T), 2)); D = SkFPAdd(D, coeff[2]); if (D == 0) return root; // f = coeff[0]*T^3 + coeff[1]*T^2 + coeff[2]*T + coeff[3] N = SkFPMul(SkFPMul(SkFPMul(T, T), T), coeff[0]); N = SkFPAdd(N, SkFPMul(SkFPMul(T, T), coeff[1])); N = SkFPAdd(N, SkFPMul(T, coeff[2])); N = SkFPAdd(N, coeff[3]); if (N) { SkScalar delta = SkFPToScalar(SkFPDiv(N, D)); if (delta) root -= delta; } return root; }
/* Looking for F' dot F'' == 0 A = b - a B = c - 2b + a C = d - 3c + 3b - a F' = 3Ct^2 + 6Bt + 3A F'' = 6Ct + 6B F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB */ int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3]) { SkFP coeffX[4], coeffY[4]; int i; formulate_F1DotF2(&src[0].fX, coeffX); formulate_F1DotF2(&src[0].fY, coeffY); for (i = 0; i < 4; i++) coeffX[i] = SkFPAdd(coeffX[i],coeffY[i]); SkScalar t[3]; int count = solve_cubic_polynomial(coeffX, t); int maxCount = 0; // now remove extrema where the curvature is zero (mins) // !!!! need a test for this !!!! for (i = 0; i < count; i++) { // if (not_min_curvature()) if (t[i] > kMinTValueForChopping && t[i] < SK_Scalar1 - kMinTValueForChopping) tValues[maxCount++] = t[i]; } return maxCount; }
/* 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();)
/* Looking for F' dot F'' == 0 A = b - a B = c - 2b + a C = d - 3c + 3b - a F' = 3Ct^2 + 6Bt + 3A F'' = 6Ct + 6B F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB */ static void formulate_F1DotF2(const SkScalar src[], SkFP coeff[4]) { SkScalar a = src[2] - src[0]; SkScalar b = src[4] - 2 * src[2] + src[0]; SkScalar c = src[6] + 3 * (src[2] - src[4]) - src[0]; SkFP A = SkScalarToFP(a); SkFP B = SkScalarToFP(b); SkFP C = SkScalarToFP(c); coeff[0] = SkFPMul(C, C); coeff[1] = SkFPMulInt(SkFPMul(B, C), 3); coeff[2] = SkFPMulInt(SkFPMul(B, B), 2); coeff[2] = SkFPAdd(coeff[2], SkFPMul(C, A)); coeff[3] = SkFPMul(A, B); }
/* 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); }