1 /*
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 */
7 #include "SkIntersections.h"
8 #include "SkLineParameters.h"
9 #include "SkPathOpsCubic.h"
10 #include "SkPathOpsCurve.h"
11 #include "SkPathOpsQuad.h"
12
13 // from blackpawn.com/texts/pointinpoly
pointInTriangle(const SkDPoint fPts[3],const SkDPoint & test)14 static bool pointInTriangle(const SkDPoint fPts[3], const SkDPoint& test) {
15 SkDVector v0 = fPts[2] - fPts[0];
16 SkDVector v1 = fPts[1] - fPts[0];
17 SkDVector v2 = test - fPts[0];
18 double dot00 = v0.dot(v0);
19 double dot01 = v0.dot(v1);
20 double dot02 = v0.dot(v2);
21 double dot11 = v1.dot(v1);
22 double dot12 = v1.dot(v2);
23 // Compute barycentric coordinates
24 double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
25 double u = (dot11 * dot02 - dot01 * dot12) * invDenom;
26 double v = (dot00 * dot12 - dot01 * dot02) * invDenom;
27 // Check if point is in triangle
28 return u >= 0 && v >= 0 && u + v < 1;
29 }
30
matchesEnd(const SkDPoint fPts[3],const SkDPoint & test)31 static bool matchesEnd(const SkDPoint fPts[3], const SkDPoint& test) {
32 return fPts[0] == test || fPts[2] == test;
33 }
34
35 /* started with at_most_end_pts_in_common from SkDQuadIntersection.cpp */
36 // Do a quick reject by rotating all points relative to a line formed by
37 // a pair of one quad's points. If the 2nd quad's points
38 // are on the line or on the opposite side from the 1st quad's 'odd man', the
39 // curves at most intersect at the endpoints.
40 /* if returning true, check contains true if quad's hull collapsed, making the cubic linear
41 if returning false, check contains true if the the quad pair have only the end point in common
42 */
hullIntersects(const SkDQuad & q2,bool * isLinear) const43 bool SkDQuad::hullIntersects(const SkDQuad& q2, bool* isLinear) const {
44 bool linear = true;
45 for (int oddMan = 0; oddMan < kPointCount; ++oddMan) {
46 const SkDPoint* endPt[2];
47 this->otherPts(oddMan, endPt);
48 double origX = endPt[0]->fX;
49 double origY = endPt[0]->fY;
50 double adj = endPt[1]->fX - origX;
51 double opp = endPt[1]->fY - origY;
52 double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX) * opp;
53 if (approximately_zero(sign)) {
54 continue;
55 }
56 linear = false;
57 bool foundOutlier = false;
58 for (int n = 0; n < kPointCount; ++n) {
59 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
60 if (test * sign > 0 && !precisely_zero(test)) {
61 foundOutlier = true;
62 break;
63 }
64 }
65 if (!foundOutlier) {
66 return false;
67 }
68 }
69 if (linear && !matchesEnd(fPts, q2.fPts[0]) && !matchesEnd(fPts, q2.fPts[2])) {
70 // if the end point of the opposite quad is inside the hull that is nearly a line,
71 // then representing the quad as a line may cause the intersection to be missed.
72 // Check to see if the endpoint is in the triangle.
73 if (pointInTriangle(fPts, q2.fPts[0]) || pointInTriangle(fPts, q2.fPts[2])) {
74 linear = false;
75 }
76 }
77 *isLinear = linear;
78 return true;
79 }
80
hullIntersects(const SkDConic & conic,bool * isLinear) const81 bool SkDQuad::hullIntersects(const SkDConic& conic, bool* isLinear) const {
82 return conic.hullIntersects(*this, isLinear);
83 }
84
hullIntersects(const SkDCubic & cubic,bool * isLinear) const85 bool SkDQuad::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
86 return cubic.hullIntersects(*this, isLinear);
87 }
88
89 /* bit twiddling for finding the off curve index (x&~m is the pair in [0,1,2] excluding oddMan)
90 oddMan opp x=oddMan^opp x=x-oddMan m=x>>2 x&~m
91 0 1 1 1 0 1
92 2 2 2 0 2
93 1 1 0 -1 -1 0
94 2 3 2 0 2
95 2 1 3 1 0 1
96 2 0 -2 -1 0
97 */
otherPts(int oddMan,const SkDPoint * endPt[2]) const98 void SkDQuad::otherPts(int oddMan, const SkDPoint* endPt[2]) const {
99 for (int opp = 1; opp < kPointCount; ++opp) {
100 int end = (oddMan ^ opp) - oddMan; // choose a value not equal to oddMan
101 end &= ~(end >> 2); // if the value went negative, set it to zero
102 endPt[opp - 1] = &fPts[end];
103 }
104 }
105
AddValidTs(double s[],int realRoots,double * t)106 int SkDQuad::AddValidTs(double s[], int realRoots, double* t) {
107 int foundRoots = 0;
108 for (int index = 0; index < realRoots; ++index) {
109 double tValue = s[index];
110 if (approximately_zero_or_more(tValue) && approximately_one_or_less(tValue)) {
111 if (approximately_less_than_zero(tValue)) {
112 tValue = 0;
113 } else if (approximately_greater_than_one(tValue)) {
114 tValue = 1;
115 }
116 for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
117 if (approximately_equal(t[idx2], tValue)) {
118 goto nextRoot;
119 }
120 }
121 t[foundRoots++] = tValue;
122 }
123 nextRoot:
124 {}
125 }
126 return foundRoots;
127 }
128
129 // note: caller expects multiple results to be sorted smaller first
130 // note: http://en.wikipedia.org/wiki/Loss_of_significance has an interesting
131 // analysis of the quadratic equation, suggesting why the following looks at
132 // the sign of B -- and further suggesting that the greatest loss of precision
133 // is in b squared less two a c
RootsValidT(double A,double B,double C,double t[2])134 int SkDQuad::RootsValidT(double A, double B, double C, double t[2]) {
135 double s[2];
136 int realRoots = RootsReal(A, B, C, s);
137 int foundRoots = AddValidTs(s, realRoots, t);
138 return foundRoots;
139 }
140
141 /*
142 Numeric Solutions (5.6) suggests to solve the quadratic by computing
143 Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C))
144 and using the roots
145 t1 = Q / A
146 t2 = C / Q
147 */
148 // this does not discard real roots <= 0 or >= 1
RootsReal(const double A,const double B,const double C,double s[2])149 int SkDQuad::RootsReal(const double A, const double B, const double C, double s[2]) {
150 const double p = B / (2 * A);
151 const double q = C / A;
152 if (!A || (approximately_zero(A) && (approximately_zero_inverse(p)
153 || approximately_zero_inverse(q)))) {
154 if (approximately_zero(B)) {
155 s[0] = 0;
156 return C == 0;
157 }
158 s[0] = -C / B;
159 return 1;
160 }
161 /* normal form: x^2 + px + q = 0 */
162 const double p2 = p * p;
163 if (!AlmostDequalUlps(p2, q) && p2 < q) {
164 return 0;
165 }
166 double sqrt_D = 0;
167 if (p2 > q) {
168 sqrt_D = sqrt(p2 - q);
169 }
170 s[0] = sqrt_D - p;
171 s[1] = -sqrt_D - p;
172 return 1 + !AlmostDequalUlps(s[0], s[1]);
173 }
174
isLinear(int startIndex,int endIndex) const175 bool SkDQuad::isLinear(int startIndex, int endIndex) const {
176 SkLineParameters lineParameters;
177 lineParameters.quadEndPoints(*this, startIndex, endIndex);
178 // FIXME: maybe it's possible to avoid this and compare non-normalized
179 lineParameters.normalize();
180 double distance = lineParameters.controlPtDistance(*this);
181 double tiniest = SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY),
182 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY);
183 double largest = SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY),
184 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY);
185 largest = SkTMax(largest, -tiniest);
186 return approximately_zero_when_compared_to(distance, largest);
187 }
188
dxdyAtT(double t) const189 SkDVector SkDQuad::dxdyAtT(double t) const {
190 double a = t - 1;
191 double b = 1 - 2 * t;
192 double c = t;
193 SkDVector result = { a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX,
194 a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY };
195 if (result.fX == 0 && result.fY == 0) {
196 if (zero_or_one(t)) {
197 result = fPts[2] - fPts[0];
198 } else {
199 // incomplete
200 SkDebugf("!q");
201 }
202 }
203 return result;
204 }
205
206 // OPTIMIZE: assert if caller passes in t == 0 / t == 1 ?
ptAtT(double t) const207 SkDPoint SkDQuad::ptAtT(double t) const {
208 if (0 == t) {
209 return fPts[0];
210 }
211 if (1 == t) {
212 return fPts[2];
213 }
214 double one_t = 1 - t;
215 double a = one_t * one_t;
216 double b = 2 * one_t * t;
217 double c = t * t;
218 SkDPoint result = { a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX,
219 a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY };
220 return result;
221 }
222
interp_quad_coords(const double * src,double t)223 static double interp_quad_coords(const double* src, double t) {
224 if (0 == t) {
225 return src[0];
226 }
227 if (1 == t) {
228 return src[4];
229 }
230 double ab = SkDInterp(src[0], src[2], t);
231 double bc = SkDInterp(src[2], src[4], t);
232 double abc = SkDInterp(ab, bc, t);
233 return abc;
234 }
235
monotonicInX() const236 bool SkDQuad::monotonicInX() const {
237 return between(fPts[0].fX, fPts[1].fX, fPts[2].fX);
238 }
239
monotonicInY() const240 bool SkDQuad::monotonicInY() const {
241 return between(fPts[0].fY, fPts[1].fY, fPts[2].fY);
242 }
243
244 /*
245 Given a quadratic q, t1, and t2, find a small quadratic segment.
246
247 The new quadratic is defined by A, B, and C, where
248 A = c[0]*(1 - t1)*(1 - t1) + 2*c[1]*t1*(1 - t1) + c[2]*t1*t1
249 C = c[3]*(1 - t1)*(1 - t1) + 2*c[2]*t1*(1 - t1) + c[1]*t1*t1
250
251 To find B, compute the point halfway between t1 and t2:
252
253 q(at (t1 + t2)/2) == D
254
255 Next, compute where D must be if we know the value of B:
256
257 _12 = A/2 + B/2
258 12_ = B/2 + C/2
259 123 = A/4 + B/2 + C/4
260 = D
261
262 Group the known values on one side:
263
264 B = D*2 - A/2 - C/2
265 */
266
267 // OPTIMIZE? : special case t1 = 1 && t2 = 0
subDivide(double t1,double t2) const268 SkDQuad SkDQuad::subDivide(double t1, double t2) const {
269 if (0 == t1 && 1 == t2) {
270 return *this;
271 }
272 SkDQuad dst;
273 double ax = dst[0].fX = interp_quad_coords(&fPts[0].fX, t1);
274 double ay = dst[0].fY = interp_quad_coords(&fPts[0].fY, t1);
275 double dx = interp_quad_coords(&fPts[0].fX, (t1 + t2) / 2);
276 double dy = interp_quad_coords(&fPts[0].fY, (t1 + t2) / 2);
277 double cx = dst[2].fX = interp_quad_coords(&fPts[0].fX, t2);
278 double cy = dst[2].fY = interp_quad_coords(&fPts[0].fY, t2);
279 /* bx = */ dst[1].fX = 2 * dx - (ax + cx) / 2;
280 /* by = */ dst[1].fY = 2 * dy - (ay + cy) / 2;
281 return dst;
282 }
283
align(int endIndex,SkDPoint * dstPt) const284 void SkDQuad::align(int endIndex, SkDPoint* dstPt) const {
285 if (fPts[endIndex].fX == fPts[1].fX) {
286 dstPt->fX = fPts[endIndex].fX;
287 }
288 if (fPts[endIndex].fY == fPts[1].fY) {
289 dstPt->fY = fPts[endIndex].fY;
290 }
291 }
292
subDivide(const SkDPoint & a,const SkDPoint & c,double t1,double t2) const293 SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2) const {
294 SkASSERT(t1 != t2);
295 SkDPoint b;
296 SkDQuad sub = subDivide(t1, t2);
297 SkDLine b0 = {{a, sub[1] + (a - sub[0])}};
298 SkDLine b1 = {{c, sub[1] + (c - sub[2])}};
299 SkIntersections i;
300 i.intersectRay(b0, b1);
301 if (i.used() == 1 && i[0][0] >= 0 && i[1][0] >= 0) {
302 b = i.pt(0);
303 } else {
304 SkASSERT(i.used() <= 2);
305 return SkDPoint::Mid(b0[1], b1[1]);
306 }
307 if (t1 == 0 || t2 == 0) {
308 align(0, &b);
309 }
310 if (t1 == 1 || t2 == 1) {
311 align(2, &b);
312 }
313 if (AlmostBequalUlps(b.fX, a.fX)) {
314 b.fX = a.fX;
315 } else if (AlmostBequalUlps(b.fX, c.fX)) {
316 b.fX = c.fX;
317 }
318 if (AlmostBequalUlps(b.fY, a.fY)) {
319 b.fY = a.fY;
320 } else if (AlmostBequalUlps(b.fY, c.fY)) {
321 b.fY = c.fY;
322 }
323 return b;
324 }
325
326 /* classic one t subdivision */
interp_quad_coords(const double * src,double * dst,double t)327 static void interp_quad_coords(const double* src, double* dst, double t) {
328 double ab = SkDInterp(src[0], src[2], t);
329 double bc = SkDInterp(src[2], src[4], t);
330 dst[0] = src[0];
331 dst[2] = ab;
332 dst[4] = SkDInterp(ab, bc, t);
333 dst[6] = bc;
334 dst[8] = src[4];
335 }
336
chopAt(double t) const337 SkDQuadPair SkDQuad::chopAt(double t) const
338 {
339 SkDQuadPair dst;
340 interp_quad_coords(&fPts[0].fX, &dst.pts[0].fX, t);
341 interp_quad_coords(&fPts[0].fY, &dst.pts[0].fY, t);
342 return dst;
343 }
344
valid_unit_divide(double numer,double denom,double * ratio)345 static int valid_unit_divide(double numer, double denom, double* ratio)
346 {
347 if (numer < 0) {
348 numer = -numer;
349 denom = -denom;
350 }
351 if (denom == 0 || numer == 0 || numer >= denom) {
352 return 0;
353 }
354 double r = numer / denom;
355 if (r == 0) { // catch underflow if numer <<<< denom
356 return 0;
357 }
358 *ratio = r;
359 return 1;
360 }
361
362 /** Quad'(t) = At + B, where
363 A = 2(a - 2b + c)
364 B = 2(b - a)
365 Solve for t, only if it fits between 0 < t < 1
366 */
FindExtrema(const double src[],double tValue[1])367 int SkDQuad::FindExtrema(const double src[], double tValue[1]) {
368 /* At + B == 0
369 t = -B / A
370 */
371 double a = src[0];
372 double b = src[2];
373 double c = src[4];
374 return valid_unit_divide(a - b, a - b - b + c, tValue);
375 }
376
377 /* Parameterization form, given A*t*t + 2*B*t*(1-t) + C*(1-t)*(1-t)
378 *
379 * a = A - 2*B + C
380 * b = 2*B - 2*C
381 * c = C
382 */
SetABC(const double * quad,double * a,double * b,double * c)383 void SkDQuad::SetABC(const double* quad, double* a, double* b, double* c) {
384 *a = quad[0]; // a = A
385 *b = 2 * quad[2]; // b = 2*B
386 *c = quad[4]; // c = C
387 *b -= *c; // b = 2*B - C
388 *a -= *b; // a = A - 2*B + C
389 *b -= *c; // b = 2*B - 2*C
390 }
391