| 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 |