blob: 386f09225a94752e8875291f56711d6d6e0aa4a3 [file] [log] [blame]
caryclark@google.com639df892012-01-10 21:46:10 +00001#include "DataTypes.h"
2#include "Extrema.h"
3
caryclark@google.comfa0588f2012-04-26 21:01:06 +00004static int validUnitDivide(double numer, double denom, double* ratio)
caryclark@google.com639df892012-01-10 21:46:10 +00005{
caryclark@google.comfa0588f2012-04-26 21:01:06 +00006 if (numer < 0) {
caryclark@google.com639df892012-01-10 21:46:10 +00007 numer = -numer;
8 denom = -denom;
9 }
caryclark@google.com639df892012-01-10 21:46:10 +000010 if (denom == 0 || numer == 0 || numer >= denom)
11 return 0;
caryclark@google.com639df892012-01-10 21:46:10 +000012 double r = numer / denom;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000013 if (r == 0) { // catch underflow if numer <<<< denom
caryclark@google.com639df892012-01-10 21:46:10 +000014 return 0;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000015 }
caryclark@google.com639df892012-01-10 21:46:10 +000016 *ratio = r;
17 return 1;
18}
19
20/** From Numerical Recipes in C.
21
22 Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C])
23 x1 = Q / A
24 x2 = C / Q
25*/
caryclark@google.comfa0588f2012-04-26 21:01:06 +000026static int findUnitQuadRoots(double A, double B, double C, double roots[2])
caryclark@google.com639df892012-01-10 21:46:10 +000027{
28 if (A == 0)
caryclark@google.comfa0588f2012-04-26 21:01:06 +000029 return validUnitDivide(-C, B, roots);
caryclark@google.com639df892012-01-10 21:46:10 +000030
31 double* r = roots;
32
33 double R = B*B - 4*A*C;
34 if (R < 0) { // complex roots
35 return 0;
36 }
37 R = sqrt(R);
38
39 double Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
caryclark@google.comfa0588f2012-04-26 21:01:06 +000040 r += validUnitDivide(Q, A, r);
41 r += validUnitDivide(C, Q, r);
caryclark@google.com639df892012-01-10 21:46:10 +000042 if (r - roots == 2 && approximately_equal(roots[0], roots[1])) { // nearly-equal?
43 r -= 1; // skip the double root
44 }
45 return (int)(r - roots);
46}
47
48/** Cubic'(t) = At^2 + Bt + C, where
49 A = 3(-a + 3(b - c) + d)
50 B = 6(a - 2b + c)
51 C = 3(b - a)
caryclark@google.comfa0588f2012-04-26 21:01:06 +000052 Solve for t, keeping only those that fit between 0 < t < 1
caryclark@google.com639df892012-01-10 21:46:10 +000053*/
caryclark@google.comfa0588f2012-04-26 21:01:06 +000054int findExtrema(double a, double b, double c, double d, double tValues[2])
caryclark@google.com639df892012-01-10 21:46:10 +000055{
56 // we divide A,B,C by 3 to simplify
57 double A = d - a + 3*(b - c);
58 double B = 2*(a - b - b + c);
59 double C = b - a;
60
caryclark@google.comfa0588f2012-04-26 21:01:06 +000061 return findUnitQuadRoots(A, B, C, tValues);
caryclark@google.com639df892012-01-10 21:46:10 +000062}
63
64/** Quad'(t) = At + B, where
65 A = 2(a - 2b + c)
66 B = 2(b - a)
67 Solve for t, only if it fits between 0 < t < 1
68*/
caryclark@google.comfa0588f2012-04-26 21:01:06 +000069int findExtrema(double a, double b, double c, double tValue[1])
caryclark@google.com639df892012-01-10 21:46:10 +000070{
71 /* At + B == 0
72 t = -B / A
73 */
caryclark@google.comfa0588f2012-04-26 21:01:06 +000074 return validUnitDivide(a - b, a - b - b + c, tValue);
caryclark@google.com639df892012-01-10 21:46:10 +000075}