OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #include "SkIntersections.h" | 7 #include "SkIntersections.h" |
8 #include "SkLineParameters.h" | 8 #include "SkLineParameters.h" |
9 #include "SkPathOpsCubic.h" | 9 #include "SkPathOpsCubic.h" |
10 #include "SkPathOpsQuad.h" | 10 #include "SkPathOpsQuad.h" |
11 #include "SkPathOpsTriangle.h" | 11 |
| 12 /* started with at_most_end_pts_in_common from SkDQuadIntersection.cpp */ |
| 13 // Do a quick reject by rotating all points relative to a line formed by |
| 14 // a pair of one quad's points. If the 2nd quad's points |
| 15 // are on the line or on the opposite side from the 1st quad's 'odd man', the |
| 16 // curves at most intersect at the endpoints. |
| 17 /* if returning true, check contains true if quad's hull collapsed, making the c
ubic linear |
| 18 if returning false, check contains true if the the quad pair have only the en
d point in common |
| 19 */ |
| 20 bool SkDQuad::hullIntersects(const SkDQuad& q2, bool* isLinear) const { |
| 21 bool linear = true; |
| 22 for (int oddMan = 0; oddMan < kPointCount; ++oddMan) { |
| 23 const SkDPoint* endPt[2]; |
| 24 this->otherPts(oddMan, endPt); |
| 25 double origX = endPt[0]->fX; |
| 26 double origY = endPt[0]->fY; |
| 27 double adj = endPt[1]->fX - origX; |
| 28 double opp = endPt[1]->fY - origY; |
| 29 double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX
) * opp; |
| 30 if (approximately_zero(sign)) { |
| 31 continue; |
| 32 } |
| 33 linear = false; |
| 34 bool foundOutlier = false; |
| 35 for (int n = 0; n < kPointCount; ++n) { |
| 36 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; |
| 37 if (test * sign > 0 && !precisely_zero(test)) { |
| 38 foundOutlier = true; |
| 39 break; |
| 40 } |
| 41 } |
| 42 if (!foundOutlier) { |
| 43 return false; |
| 44 } |
| 45 } |
| 46 *isLinear = linear; |
| 47 return true; |
| 48 } |
| 49 |
| 50 /* bit twiddling for finding the off curve index (x&~m is the pair in [0,1,2] ex
cluding oddMan) |
| 51 oddMan opp x=oddMan^opp x=x-oddMan m=x>>2 x&~m |
| 52 0 1 1 1 0 1 |
| 53 2 2 2 0 2 |
| 54 1 1 0 -1 -1 0 |
| 55 2 3 2 0 2 |
| 56 2 1 3 1 0 1 |
| 57 2 0 -2 -1 0 |
| 58 */ |
| 59 void SkDQuad::otherPts(int oddMan, const SkDPoint* endPt[2]) const { |
| 60 for (int opp = 1; opp < kPointCount; ++opp) { |
| 61 int end = (oddMan ^ opp) - oddMan; // choose a value not equal to oddMa
n |
| 62 end &= ~(end >> 2); // if the value went negative, set it to zero |
| 63 endPt[opp - 1] = &fPts[end]; |
| 64 } |
| 65 } |
12 | 66 |
13 // from http://blog.gludion.com/2009/08/distance-to-quadratic-bezier-curve.html | 67 // from http://blog.gludion.com/2009/08/distance-to-quadratic-bezier-curve.html |
14 // (currently only used by testing) | 68 // (currently only used by testing) |
15 double SkDQuad::nearestT(const SkDPoint& pt) const { | 69 double SkDQuad::nearestT(const SkDPoint& pt) const { |
16 SkDVector pos = fPts[0] - pt; | 70 SkDVector pos = fPts[0] - pt; |
17 // search points P of bezier curve with PM.(dP / dt) = 0 | 71 // search points P of bezier curve with PM.(dP / dt) = 0 |
18 // a calculus leads to a 3d degree equation : | 72 // a calculus leads to a 3d degree equation : |
19 SkDVector A = fPts[1] - fPts[0]; | 73 SkDVector A = fPts[1] - fPts[0]; |
20 SkDVector B = fPts[2] - fPts[1]; | 74 SkDVector B = fPts[2] - fPts[1]; |
21 B -= A; | 75 B -= A; |
(...skipping 14 matching lines...) Expand all Loading... |
36 distMin = dist; | 90 distMin = dist; |
37 bestIndex = index; | 91 bestIndex = index; |
38 } | 92 } |
39 } | 93 } |
40 if (bestIndex >= 0) { | 94 if (bestIndex >= 0) { |
41 return ts[bestIndex]; | 95 return ts[bestIndex]; |
42 } | 96 } |
43 return d0 < d2 ? 0 : 1; | 97 return d0 < d2 ? 0 : 1; |
44 } | 98 } |
45 | 99 |
46 bool SkDQuad::pointInHull(const SkDPoint& pt) const { | |
47 return ((const SkDTriangle&) fPts).contains(pt); | |
48 } | |
49 | |
50 SkDPoint SkDQuad::top(double startT, double endT) const { | 100 SkDPoint SkDQuad::top(double startT, double endT) const { |
51 SkDQuad sub = subDivide(startT, endT); | 101 SkDQuad sub = subDivide(startT, endT); |
52 SkDPoint topPt = sub[0]; | 102 SkDPoint topPt = sub[0]; |
53 if (topPt.fY > sub[2].fY || (topPt.fY == sub[2].fY && topPt.fX > sub[2].fX))
{ | 103 if (topPt.fY > sub[2].fY || (topPt.fY == sub[2].fY && topPt.fX > sub[2].fX))
{ |
54 topPt = sub[2]; | 104 topPt = sub[2]; |
55 } | 105 } |
56 if (!between(sub[0].fY, sub[1].fY, sub[2].fY)) { | 106 if (!between(sub[0].fY, sub[1].fY, sub[2].fY)) { |
57 double extremeT; | 107 double extremeT; |
58 if (FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, &extremeT)) { | 108 if (FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, &extremeT)) { |
59 extremeT = startT + (endT - startT) * extremeT; | 109 extremeT = startT + (endT - startT) * extremeT; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 s[1] = -sqrt_D - p; | 183 s[1] = -sqrt_D - p; |
134 return 1 + !AlmostDequalUlps(s[0], s[1]); | 184 return 1 + !AlmostDequalUlps(s[0], s[1]); |
135 } | 185 } |
136 | 186 |
137 bool SkDQuad::isLinear(int startIndex, int endIndex) const { | 187 bool SkDQuad::isLinear(int startIndex, int endIndex) const { |
138 SkLineParameters lineParameters; | 188 SkLineParameters lineParameters; |
139 lineParameters.quadEndPoints(*this, startIndex, endIndex); | 189 lineParameters.quadEndPoints(*this, startIndex, endIndex); |
140 // FIXME: maybe it's possible to avoid this and compare non-normalized | 190 // FIXME: maybe it's possible to avoid this and compare non-normalized |
141 lineParameters.normalize(); | 191 lineParameters.normalize(); |
142 double distance = lineParameters.controlPtDistance(*this); | 192 double distance = lineParameters.controlPtDistance(*this); |
143 return approximately_zero(distance); | 193 double tiniest = SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY), |
| 194 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY); |
| 195 double largest = SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY), |
| 196 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY); |
| 197 largest = SkTMax(largest, -tiniest); |
| 198 return approximately_zero_when_compared_to(distance, largest); |
144 } | 199 } |
145 | 200 |
146 SkDCubic SkDQuad::toCubic() const { | 201 SkDCubic SkDQuad::toCubic() const { |
147 SkDCubic cubic; | 202 SkDCubic cubic; |
148 cubic[0] = fPts[0]; | 203 cubic[0] = fPts[0]; |
149 cubic[2] = fPts[1]; | 204 cubic[2] = fPts[1]; |
150 cubic[3] = fPts[2]; | 205 cubic[3] = fPts[2]; |
151 cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3; | 206 cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3; |
152 cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3; | 207 cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3; |
153 cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3; | 208 cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 dstPt->fX = fPts[endIndex].fX; | 288 dstPt->fX = fPts[endIndex].fX; |
234 } | 289 } |
235 if (fPts[endIndex].fY == fPts[1].fY) { | 290 if (fPts[endIndex].fY == fPts[1].fY) { |
236 dstPt->fY = fPts[endIndex].fY; | 291 dstPt->fY = fPts[endIndex].fY; |
237 } | 292 } |
238 } | 293 } |
239 | 294 |
240 SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, dou
ble t2) const { | 295 SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, dou
ble t2) const { |
241 SkASSERT(t1 != t2); | 296 SkASSERT(t1 != t2); |
242 SkDPoint b; | 297 SkDPoint b; |
243 #if 0 | |
244 // this approach assumes that the control point computed directly is accurat
e enough | |
245 double dx = interp_quad_coords(&fPts[0].fX, (t1 + t2) / 2); | |
246 double dy = interp_quad_coords(&fPts[0].fY, (t1 + t2) / 2); | |
247 b.fX = 2 * dx - (a.fX + c.fX) / 2; | |
248 b.fY = 2 * dy - (a.fY + c.fY) / 2; | |
249 #else | |
250 SkDQuad sub = subDivide(t1, t2); | 298 SkDQuad sub = subDivide(t1, t2); |
251 SkDLine b0 = {{a, sub[1] + (a - sub[0])}}; | 299 SkDLine b0 = {{a, sub[1] + (a - sub[0])}}; |
252 SkDLine b1 = {{c, sub[1] + (c - sub[2])}}; | 300 SkDLine b1 = {{c, sub[1] + (c - sub[2])}}; |
253 SkIntersections i; | 301 SkIntersections i; |
254 i.intersectRay(b0, b1); | 302 i.intersectRay(b0, b1); |
255 if (i.used() == 1 && i[0][0] >= 0 && i[1][0] >= 0) { | 303 if (i.used() == 1 && i[0][0] >= 0 && i[1][0] >= 0) { |
256 b = i.pt(0); | 304 b = i.pt(0); |
257 } else { | 305 } else { |
258 SkASSERT(i.used() <= 2); | 306 SkASSERT(i.used() <= 2); |
259 b = SkDPoint::Mid(b0[1], b1[1]); | 307 b = SkDPoint::Mid(b0[1], b1[1]); |
260 } | 308 } |
261 #endif | |
262 if (t1 == 0 || t2 == 0) { | 309 if (t1 == 0 || t2 == 0) { |
263 align(0, &b); | 310 align(0, &b); |
264 } | 311 } |
265 if (t1 == 1 || t2 == 1) { | 312 if (t1 == 1 || t2 == 1) { |
266 align(2, &b); | 313 align(2, &b); |
267 } | 314 } |
268 if (AlmostBequalUlps(b.fX, a.fX)) { | 315 if (AlmostBequalUlps(b.fX, a.fX)) { |
269 b.fX = a.fX; | 316 b.fX = a.fX; |
270 } else if (AlmostBequalUlps(b.fX, c.fX)) { | 317 } else if (AlmostBequalUlps(b.fX, c.fX)) { |
271 b.fX = c.fX; | 318 b.fX = c.fX; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 * c = C | 380 * c = C |
334 */ | 381 */ |
335 void SkDQuad::SetABC(const double* quad, double* a, double* b, double* c) { | 382 void SkDQuad::SetABC(const double* quad, double* a, double* b, double* c) { |
336 *a = quad[0]; // a = A | 383 *a = quad[0]; // a = A |
337 *b = 2 * quad[2]; // b = 2*B | 384 *b = 2 * quad[2]; // b = 2*B |
338 *c = quad[4]; // c = C | 385 *c = quad[4]; // c = C |
339 *b -= *c; // b = 2*B - C | 386 *b -= *c; // b = 2*B - C |
340 *a -= *b; // a = A - 2*B + C | 387 *a -= *b; // a = A - 2*B + C |
341 *b -= *c; // b = 2*B - 2*C | 388 *b -= *c; // b = 2*B - 2*C |
342 } | 389 } |
OLD | NEW |