caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame^] | 1 | #include "DataTypes.h" |
| 2 | #include "Extrema.h" |
| 3 | |
| 4 | static int valid_unit_divide(double numer, double denom, double* ratio) |
| 5 | { |
| 6 | if (numer < 0) |
| 7 | { |
| 8 | numer = -numer; |
| 9 | denom = -denom; |
| 10 | } |
| 11 | |
| 12 | if (denom == 0 || numer == 0 || numer >= denom) |
| 13 | return 0; |
| 14 | |
| 15 | double r = numer / denom; |
| 16 | if (r == 0) // catch underflow if numer <<<< denom |
| 17 | return 0; |
| 18 | *ratio = r; |
| 19 | return 1; |
| 20 | } |
| 21 | |
| 22 | /** From Numerical Recipes in C. |
| 23 | |
| 24 | Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C]) |
| 25 | x1 = Q / A |
| 26 | x2 = C / Q |
| 27 | */ |
| 28 | static int SkFindUnitQuadRoots(double A, double B, double C, double roots[2]) |
| 29 | { |
| 30 | if (A == 0) |
| 31 | return valid_unit_divide(-C, B, roots); |
| 32 | |
| 33 | double* r = roots; |
| 34 | |
| 35 | double R = B*B - 4*A*C; |
| 36 | if (R < 0) { // complex roots |
| 37 | return 0; |
| 38 | } |
| 39 | R = sqrt(R); |
| 40 | |
| 41 | double Q = (B < 0) ? -(B-R)/2 : -(B+R)/2; |
| 42 | r += valid_unit_divide(Q, A, r); |
| 43 | r += valid_unit_divide(C, Q, r); |
| 44 | if (r - roots == 2 && approximately_equal(roots[0], roots[1])) { // nearly-equal? |
| 45 | r -= 1; // skip the double root |
| 46 | } |
| 47 | return (int)(r - roots); |
| 48 | } |
| 49 | |
| 50 | /** Cubic'(t) = At^2 + Bt + C, where |
| 51 | A = 3(-a + 3(b - c) + d) |
| 52 | B = 6(a - 2b + c) |
| 53 | C = 3(b - a) |
| 54 | Solve for t, keeping only those that fit betwee 0 < t < 1 |
| 55 | */ |
| 56 | int SkFindCubicExtrema(double a, double b, double c, double d, double tValues[2]) |
| 57 | { |
| 58 | // we divide A,B,C by 3 to simplify |
| 59 | double A = d - a + 3*(b - c); |
| 60 | double B = 2*(a - b - b + c); |
| 61 | double C = b - a; |
| 62 | |
| 63 | return SkFindUnitQuadRoots(A, B, C, tValues); |
| 64 | } |
| 65 | |
| 66 | /** Quad'(t) = At + B, where |
| 67 | A = 2(a - 2b + c) |
| 68 | B = 2(b - a) |
| 69 | Solve for t, only if it fits between 0 < t < 1 |
| 70 | */ |
| 71 | int SkFindQuadExtrema(double a, double b, double c, double tValue[1]) |
| 72 | { |
| 73 | /* At + B == 0 |
| 74 | t = -B / A |
| 75 | */ |
| 76 | return valid_unit_divide(a - b, a - b - b + c, tValue); |
| 77 | } |