blob: a84009da875b51c7b838aadcc252701d71ef1aa4 [file] [log] [blame]
caryclark@google.com9e49fb62012-08-27 14:11:33 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.combeda3892013-02-07 13:13:41 +00007#include "CubicUtilities.h"
caryclark@google.com27accef2012-01-25 18:57:23 +00008#include "QuadraticUtilities.h"
caryclark@google.combeda3892013-02-07 13:13:41 +00009#include "TriangleUtilities.h"
10
11// from http://blog.gludion.com/2009/08/distance-to-quadratic-bezier-curve.html
12double nearestT(const Quadratic& quad, const _Point& pt) {
13 _Point pos = quad[0] - pt;
14 // search points P of bezier curve with PM.(dP / dt) = 0
15 // a calculus leads to a 3d degree equation :
16 _Point A = quad[1] - quad[0];
17 _Point B = quad[2] - quad[1];
18 B -= A;
19 double a = B.dot(B);
20 double b = 3 * A.dot(B);
21 double c = 2 * A.dot(A) + pos.dot(B);
22 double d = pos.dot(A);
23 double ts[3];
24 int roots = cubicRootsValidT(a, b, c, d, ts);
25 double d0 = pt.distanceSquared(quad[0]);
26 double d2 = pt.distanceSquared(quad[2]);
27 double distMin = SkTMin(d0, d2);
28 int bestIndex = -1;
29 for (int index = 0; index < roots; ++index) {
30 _Point onQuad;
31 xy_at_t(quad, ts[index], onQuad.x, onQuad.y);
32 double dist = pt.distanceSquared(onQuad);
33 if (distMin > dist) {
34 distMin = dist;
35 bestIndex = index;
36 }
37 }
38 if (bestIndex >= 0) {
39 return ts[bestIndex];
40 }
41 return d0 < d2 ? 0 : 1;
42}
43
44bool point_in_hull(const Quadratic& quad, const _Point& pt) {
45 return pointInTriangle((const Triangle&) quad, pt);
46}
caryclark@google.com27accef2012-01-25 18:57:23 +000047
caryclark@google.com03f97062012-08-21 13:13:52 +000048/*
caryclark@google.com03f97062012-08-21 13:13:52 +000049Numeric Solutions (5.6) suggests to solve the quadratic by computing
caryclark@google.com03f97062012-08-21 13:13:52 +000050 Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C))
caryclark@google.com03f97062012-08-21 13:13:52 +000051and using the roots
caryclark@google.com03f97062012-08-21 13:13:52 +000052 t1 = Q / A
53 t2 = C / Q
caryclark@google.com03f97062012-08-21 13:13:52 +000054*/
caryclark@google.com9f602912013-01-24 21:47:16 +000055int add_valid_ts(double s[], int realRoots, double* t) {
56 int foundRoots = 0;
57 for (int index = 0; index < realRoots; ++index) {
58 double tValue = s[index];
59 if (approximately_zero_or_more(tValue) && approximately_one_or_less(tValue)) {
60 if (approximately_less_than_zero(tValue)) {
61 tValue = 0;
62 } else if (approximately_greater_than_one(tValue)) {
63 tValue = 1;
64 }
65 for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
66 if (approximately_equal(t[idx2], tValue)) {
67 goto nextRoot;
68 }
69 }
70 t[foundRoots++] = tValue;
71 }
72nextRoot:
73 ;
74 }
75 return foundRoots;
76}
77
caryclark@google.coma7e483d2012-08-28 20:44:43 +000078// note: caller expects multiple results to be sorted smaller first
79// note: http://en.wikipedia.org/wiki/Loss_of_significance has an interesting
80// analysis of the quadratic equation, suggesting why the following looks at
81// the sign of B -- and further suggesting that the greatest loss of precision
82// is in b squared less two a c
caryclark@google.com9f602912013-01-24 21:47:16 +000083int quadraticRootsValidT(double A, double B, double C, double t[2]) {
84#if 0
caryclark@google.com27accef2012-01-25 18:57:23 +000085 B *= 2;
86 double square = B * B - 4 * A * C;
caryclark@google.com235f56a2012-09-14 14:19:30 +000087 if (approximately_negative(square)) {
88 if (!approximately_positive(square)) {
89 return 0;
90 }
91 square = 0;
caryclark@google.com27accef2012-01-25 18:57:23 +000092 }
93 double squareRt = sqrt(square);
94 double Q = (B + (B < 0 ? -squareRt : squareRt)) / -2;
95 int foundRoots = 0;
caryclark@google.com03f97062012-08-21 13:13:52 +000096 double ratio = Q / A;
caryclark@google.coma7e483d2012-08-28 20:44:43 +000097 if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
98 if (approximately_less_than_zero(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +000099 ratio = 0;
caryclark@google.coma7e483d2012-08-28 20:44:43 +0000100 } else if (approximately_greater_than_one(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +0000101 ratio = 1;
caryclark@google.com78e17132012-04-17 11:40:34 +0000102 }
caryclark@google.coma7e483d2012-08-28 20:44:43 +0000103 t[0] = ratio;
104 ++foundRoots;
caryclark@google.com27accef2012-01-25 18:57:23 +0000105 }
caryclark@google.com03f97062012-08-21 13:13:52 +0000106 ratio = C / Q;
caryclark@google.coma7e483d2012-08-28 20:44:43 +0000107 if (approximately_zero_or_more(ratio) && approximately_one_or_less(ratio)) {
108 if (approximately_less_than_zero(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +0000109 ratio = 0;
caryclark@google.coma7e483d2012-08-28 20:44:43 +0000110 } else if (approximately_greater_than_one(ratio)) {
caryclark@google.com03f97062012-08-21 13:13:52 +0000111 ratio = 1;
caryclark@google.com78e17132012-04-17 11:40:34 +0000112 }
caryclark@google.coma7e483d2012-08-28 20:44:43 +0000113 if (foundRoots == 0 || !approximately_negative(ratio - t[0])) {
caryclark@google.comc899ad92012-08-23 15:24:42 +0000114 t[foundRoots++] = ratio;
caryclark@google.coma7e483d2012-08-28 20:44:43 +0000115 } else if (!approximately_negative(t[0] - ratio)) {
116 t[foundRoots++] = t[0];
117 t[0] = ratio;
caryclark@google.comc899ad92012-08-23 15:24:42 +0000118 }
caryclark@google.com27accef2012-01-25 18:57:23 +0000119 }
caryclark@google.com9f602912013-01-24 21:47:16 +0000120#else
121 double s[2];
122 int realRoots = quadraticRootsReal(A, B, C, s);
123 int foundRoots = add_valid_ts(s, realRoots, t);
124#endif
caryclark@google.com27accef2012-01-25 18:57:23 +0000125 return foundRoots;
126}
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000127
caryclark@google.com9f602912013-01-24 21:47:16 +0000128// unlike quadratic roots, this does not discard real roots <= 0 or >= 1
129int quadraticRootsReal(const double A, const double B, const double C, double s[2]) {
caryclark@google.com85ec74c2013-01-28 19:25:51 +0000130 const double p = B / (2 * A);
131 const double q = C / A;
132 if (approximately_zero(A) && (approximately_zero_inverse(p) || approximately_zero_inverse(q))) {
caryclark@google.com9f602912013-01-24 21:47:16 +0000133 if (approximately_zero(B)) {
134 s[0] = 0;
135 return C == 0;
136 }
137 s[0] = -C / B;
138 return 1;
139 }
140 /* normal form: x^2 + px + q = 0 */
caryclark@google.com9f602912013-01-24 21:47:16 +0000141 const double p2 = p * p;
142#if 0
143 double D = AlmostEqualUlps(p2, q) ? 0 : p2 - q;
144 if (D <= 0) {
145 if (D < 0) {
146 return 0;
147 }
148 s[0] = -p;
149 SkDebugf("[%d] %1.9g\n", 1, s[0]);
150 return 1;
151 }
152 double sqrt_D = sqrt(D);
153 s[0] = sqrt_D - p;
154 s[1] = -sqrt_D - p;
155 SkDebugf("[%d] %1.9g %1.9g\n", 2, s[0], s[1]);
156 return 2;
157#else
158 if (!AlmostEqualUlps(p2, q) && p2 < q) {
159 return 0;
160 }
161 double sqrt_D = 0;
162 if (p2 > q) {
163 sqrt_D = sqrt(p2 - q);
164 }
165 s[0] = sqrt_D - p;
166 s[1] = -sqrt_D - p;
167#if 0
168 if (AlmostEqualUlps(s[0], s[1])) {
169 SkDebugf("[%d] %1.9g\n", 1, s[0]);
170 } else {
171 SkDebugf("[%d] %1.9g %1.9g\n", 2, s[0], s[1]);
172 }
173#endif
174 return 1 + !AlmostEqualUlps(s[0], s[1]);
175#endif
176}
177
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000178static double derivativeAtT(const double* quad, double t) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000179 double a = t - 1;
180 double b = 1 - 2 * t;
181 double c = t;
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000182 return a * quad[0] + b * quad[2] + c * quad[4];
183}
184
185double dx_at_t(const Quadratic& quad, double t) {
186 return derivativeAtT(&quad[0].x, t);
187}
188
189double dy_at_t(const Quadratic& quad, double t) {
190 return derivativeAtT(&quad[0].y, t);
191}
192
193void dxdy_at_t(const Quadratic& quad, double t, _Point& dxy) {
194 double a = t - 1;
195 double b = 1 - 2 * t;
196 double c = t;
197 dxy.x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
198 dxy.y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000199}
200
201void xy_at_t(const Quadratic& quad, double t, double& x, double& y) {
202 double one_t = 1 - t;
203 double a = one_t * one_t;
204 double b = 2 * one_t * t;
205 double c = t * t;
206 if (&x) {
207 x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
208 }
209 if (&y) {
210 y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
211 }
212}