blob: 3fab29ec80916e5c3b4aca5c912edea8693f8cc8 [file] [log] [blame]
caryclark@google.comc6825902012-02-03 22:07:47 +00001#include "CubicUtilities.h"
2#include "DataTypes.h"
3#include "QuadraticUtilities.h"
4
5void coefficients(const double* cubic, double& A, double& B, double& C, double& D) {
6 A = cubic[6]; // d
7 B = cubic[4] * 3; // 3*c
8 C = cubic[2] * 3; // 3*b
9 D = cubic[0]; // a
10 A -= D - C + B; // A = -a + 3*b - 3*c + d
11 B += 3 * D - 2 * C; // B = 3*a - 6*b + 3*c
12 C -= 3 * D; // C = -3*a + 3*b
13}
14
15// cubic roots
16
17const double PI = 4 * atan(1);
18
19static bool is_unit_interval(double x) {
20 return x > 0 && x < 1;
21}
22
23// from SkGeometry.cpp (and Numeric Solutions, 5.6)
24int cubicRoots(double A, double B, double C, double D, double t[3]) {
25 if (approximately_zero(A)) { // we're just a quadratic
26 return quadraticRoots(B, C, D, t);
27 }
28 double a, b, c;
29 {
30 double invA = 1 / A;
31 a = B * invA;
32 b = C * invA;
33 c = D * invA;
34 }
35 double a2 = a * a;
36 double Q = (a2 - b * 3) / 9;
37 double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
38 double Q3 = Q * Q * Q;
39 double R2MinusQ3 = R * R - Q3;
40 double adiv3 = a / 3;
41 double* roots = t;
42 double r;
43
44 if (R2MinusQ3 < 0) // we have 3 real roots
45 {
46 double theta = acos(R / sqrt(Q3));
47 double neg2RootQ = -2 * sqrt(Q);
48
49 r = neg2RootQ * cos(theta / 3) - adiv3;
50 if (is_unit_interval(r))
51 *roots++ = r;
52
53 r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
54 if (is_unit_interval(r))
55 *roots++ = r;
56
57 r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
58 if (is_unit_interval(r))
59 *roots++ = r;
60 }
61 else // we have 1 real root
62 {
63 double A = fabs(R) + sqrt(R2MinusQ3);
64 A = cube_root(A);
65 if (R > 0) {
66 A = -A;
67 }
68 if (A != 0) {
69 A += Q / A;
70 }
71 r = A - adiv3;
72 if (is_unit_interval(r))
73 *roots++ = r;
74 }
75 return (int)(roots - t);
76}