blob: 0b850607d49353976736f527c10a10fb2dfe8017 [file] [log] [blame]
caryclark@google.com639df892012-01-10 21:46:10 +00001#include "DataTypes.h"
2#include "Extrema.h"
3
4static 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*/
28static 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*/
56int 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*/
71int 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}