| 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 "SkPathOpsLine.h" | 8 #include "SkPathOpsLine.h" |
| 9 #include "SkPathOpsQuad.h" | 9 #include "SkPathOpsQuad.h" |
| 10 | 10 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 | 88 |
| 89 class LineQuadraticIntersections { | 89 class LineQuadraticIntersections { |
| 90 public: | 90 public: |
| 91 enum PinTPoint { | 91 enum PinTPoint { |
| 92 kPointUninitialized, | 92 kPointUninitialized, |
| 93 kPointInitialized | 93 kPointInitialized |
| 94 }; | 94 }; |
| 95 | 95 |
| 96 LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersectio
ns* i) | 96 LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersectio
ns* i) |
| 97 : fQuad(q) | 97 : fQuad(q) |
| 98 , fLine(l) | 98 , fLine(&l) |
| 99 , fIntersections(i) | 99 , fIntersections(i) |
| 100 , fAllowNear(true) { | 100 , fAllowNear(true) { |
| 101 i->setMax(3); // allow short partial coincidence plus discrete intersec
tion | 101 i->setMax(3); // allow short partial coincidence plus discrete intersec
tion |
| 102 } | 102 } |
| 103 | 103 |
| 104 LineQuadraticIntersections(const SkDQuad& q) |
| 105 : fQuad(q) |
| 106 SkDEBUGPARAMS(fLine(NULL)) |
| 107 SkDEBUGPARAMS(fIntersections(NULL)) |
| 108 SkDEBUGPARAMS(fAllowNear(false)) { |
| 109 } |
| 110 |
| 104 void allowNear(bool allow) { | 111 void allowNear(bool allow) { |
| 105 fAllowNear = allow; | 112 fAllowNear = allow; |
| 106 } | 113 } |
| 107 | 114 |
| 108 void checkCoincident() { | 115 void checkCoincident() { |
| 109 int last = fIntersections->used() - 1; | 116 int last = fIntersections->used() - 1; |
| 110 for (int index = 0; index < last; ) { | 117 for (int index = 0; index < last; ) { |
| 111 double quadMidT = ((*fIntersections)[0][index] + (*fIntersections)[0
][index + 1]) / 2; | 118 double quadMidT = ((*fIntersections)[0][index] + (*fIntersections)[0
][index + 1]) / 2; |
| 112 SkDPoint quadMidPt = fQuad.ptAtT(quadMidT); | 119 SkDPoint quadMidPt = fQuad.ptAtT(quadMidT); |
| 113 double t = fLine.nearPoint(quadMidPt, NULL); | 120 double t = fLine->nearPoint(quadMidPt, NULL); |
| 114 if (t < 0) { | 121 if (t < 0) { |
| 115 ++index; | 122 ++index; |
| 116 continue; | 123 continue; |
| 117 } | 124 } |
| 118 if (fIntersections->isCoincident(index)) { | 125 if (fIntersections->isCoincident(index)) { |
| 119 fIntersections->removeOne(index); | 126 fIntersections->removeOne(index); |
| 120 --last; | 127 --last; |
| 121 } else if (fIntersections->isCoincident(index + 1)) { | 128 } else if (fIntersections->isCoincident(index + 1)) { |
| 122 fIntersections->removeOne(index + 1); | 129 fIntersections->removeOne(index + 1); |
| 123 --last; | 130 --last; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 137 note that cos(a) = A(djacent) / Hypoteneuse | 144 note that cos(a) = A(djacent) / Hypoteneuse |
| 138 sin(a) = O(pposite) / Hypoteneuse | 145 sin(a) = O(pposite) / Hypoteneuse |
| 139 since we are computing Ts, we can ignore hypoteneuse, the scale factor: | 146 since we are computing Ts, we can ignore hypoteneuse, the scale factor: |
| 140 | A -O | | 147 | A -O | |
| 141 | O A | | 148 | O A | |
| 142 A = line[1].fX - line[0].fX (adjacent side of the right triangle) | 149 A = line[1].fX - line[0].fX (adjacent side of the right triangle) |
| 143 O = line[1].fY - line[0].fY (opposite side of the right triangle) | 150 O = line[1].fY - line[0].fY (opposite side of the right triangle) |
| 144 for each of the three points (e.g. n = 0 to 2) | 151 for each of the three points (e.g. n = 0 to 2) |
| 145 quad[n].fY' = (quad[n].fY - line[0].fY) * A - (quad[n].fX - line[0].fX)
* O | 152 quad[n].fY' = (quad[n].fY - line[0].fY) * A - (quad[n].fX - line[0].fX)
* O |
| 146 */ | 153 */ |
| 147 double adj = fLine[1].fX - fLine[0].fX; | 154 double adj = (*fLine)[1].fX - (*fLine)[0].fX; |
| 148 double opp = fLine[1].fY - fLine[0].fY; | 155 double opp = (*fLine)[1].fY - (*fLine)[0].fY; |
| 149 double r[3]; | 156 double r[3]; |
| 150 for (int n = 0; n < 3; ++n) { | 157 for (int n = 0; n < 3; ++n) { |
| 151 r[n] = (fQuad[n].fY - fLine[0].fY) * adj - (fQuad[n].fX - fLine[0].f
X) * opp; | 158 r[n] = (fQuad[n].fY - (*fLine)[0].fY) * adj - (fQuad[n].fX - (*fLine
)[0].fX) * opp; |
| 152 } | 159 } |
| 153 double A = r[2]; | 160 double A = r[2]; |
| 154 double B = r[1]; | 161 double B = r[1]; |
| 155 double C = r[0]; | 162 double C = r[0]; |
| 156 A += C - 2 * B; // A = a - 2*b + c | 163 A += C - 2 * B; // A = a - 2*b + c |
| 157 B -= C; // B = -(b - c) | 164 B -= C; // B = -(b - c) |
| 158 return SkDQuad::RootsValidT(A, 2 * B, C, roots); | 165 return SkDQuad::RootsValidT(A, 2 * B, C, roots); |
| 159 } | 166 } |
| 160 | 167 |
| 161 int intersect() { | 168 int intersect() { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 fIntersections->flip(); | 269 fIntersections->flip(); |
| 263 } | 270 } |
| 264 checkCoincident(); | 271 checkCoincident(); |
| 265 return fIntersections->used(); | 272 return fIntersections->used(); |
| 266 } | 273 } |
| 267 | 274 |
| 268 protected: | 275 protected: |
| 269 // add endpoints first to get zero and one t values exactly | 276 // add endpoints first to get zero and one t values exactly |
| 270 void addExactEndPoints() { | 277 void addExactEndPoints() { |
| 271 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 278 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 272 double lineT = fLine.exactPoint(fQuad[qIndex]); | 279 double lineT = fLine->exactPoint(fQuad[qIndex]); |
| 273 if (lineT < 0) { | 280 if (lineT < 0) { |
| 274 continue; | 281 continue; |
| 275 } | 282 } |
| 276 double quadT = (double) (qIndex >> 1); | 283 double quadT = (double) (qIndex >> 1); |
| 277 fIntersections->insert(quadT, lineT, fQuad[qIndex]); | 284 fIntersections->insert(quadT, lineT, fQuad[qIndex]); |
| 278 } | 285 } |
| 279 } | 286 } |
| 280 | 287 |
| 281 void addNearEndPoints() { | 288 void addNearEndPoints() { |
| 282 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 289 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 283 double quadT = (double) (qIndex >> 1); | 290 double quadT = (double) (qIndex >> 1); |
| 284 if (fIntersections->hasT(quadT)) { | 291 if (fIntersections->hasT(quadT)) { |
| 285 continue; | 292 continue; |
| 286 } | 293 } |
| 287 double lineT = fLine.nearPoint(fQuad[qIndex], NULL); | 294 double lineT = fLine->nearPoint(fQuad[qIndex], NULL); |
| 288 if (lineT < 0) { | 295 if (lineT < 0) { |
| 289 continue; | 296 continue; |
| 290 } | 297 } |
| 291 fIntersections->insert(quadT, lineT, fQuad[qIndex]); | 298 fIntersections->insert(quadT, lineT, fQuad[qIndex]); |
| 292 } | 299 } |
| 293 // FIXME: see if line end is nearly on quad | 300 // FIXME: see if line end is nearly on quad |
| 294 } | 301 } |
| 295 | 302 |
| 296 void addExactHorizontalEndPoints(double left, double right, double y) { | 303 void addExactHorizontalEndPoints(double left, double right, double y) { |
| 297 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 304 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 if (lineT < 0) { | 347 if (lineT < 0) { |
| 341 continue; | 348 continue; |
| 342 } | 349 } |
| 343 fIntersections->insert(quadT, lineT, fQuad[qIndex]); | 350 fIntersections->insert(quadT, lineT, fQuad[qIndex]); |
| 344 } | 351 } |
| 345 // FIXME: see if line end is nearly on quad | 352 // FIXME: see if line end is nearly on quad |
| 346 } | 353 } |
| 347 | 354 |
| 348 double findLineT(double t) { | 355 double findLineT(double t) { |
| 349 SkDPoint xy = fQuad.ptAtT(t); | 356 SkDPoint xy = fQuad.ptAtT(t); |
| 350 double dx = fLine[1].fX - fLine[0].fX; | 357 double dx = (*fLine)[1].fX - (*fLine)[0].fX; |
| 351 double dy = fLine[1].fY - fLine[0].fY; | 358 double dy = (*fLine)[1].fY - (*fLine)[0].fY; |
| 352 if (fabs(dx) > fabs(dy)) { | 359 if (fabs(dx) > fabs(dy)) { |
| 353 return (xy.fX - fLine[0].fX) / dx; | 360 return (xy.fX - (*fLine)[0].fX) / dx; |
| 354 } | 361 } |
| 355 return (xy.fY - fLine[0].fY) / dy; | 362 return (xy.fY - (*fLine)[0].fY) / dy; |
| 356 } | 363 } |
| 357 | 364 |
| 358 bool pinTs(double* quadT, double* lineT, SkDPoint* pt, PinTPoint ptSet) { | 365 bool pinTs(double* quadT, double* lineT, SkDPoint* pt, PinTPoint ptSet) { |
| 359 if (!approximately_one_or_less_double(*lineT)) { | 366 if (!approximately_one_or_less_double(*lineT)) { |
| 360 return false; | 367 return false; |
| 361 } | 368 } |
| 362 if (!approximately_zero_or_more_double(*lineT)) { | 369 if (!approximately_zero_or_more_double(*lineT)) { |
| 363 return false; | 370 return false; |
| 364 } | 371 } |
| 365 double qT = *quadT = SkPinT(*quadT); | 372 double qT = *quadT = SkPinT(*quadT); |
| 366 double lT = *lineT = SkPinT(*lineT); | 373 double lT = *lineT = SkPinT(*lineT); |
| 367 if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT
!= 1)) { | 374 if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT
!= 1)) { |
| 368 *pt = fLine.ptAtT(lT); | 375 *pt = (*fLine).ptAtT(lT); |
| 369 } else if (ptSet == kPointUninitialized) { | 376 } else if (ptSet == kPointUninitialized) { |
| 370 *pt = fQuad.ptAtT(qT); | 377 *pt = fQuad.ptAtT(qT); |
| 371 } | 378 } |
| 372 SkPoint gridPt = pt->asSkPoint(); | 379 SkPoint gridPt = pt->asSkPoint(); |
| 373 if (SkDPoint::ApproximatelyEqual(gridPt, fLine[0].asSkPoint())) { | 380 if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[0].asSkPoint())) { |
| 374 *pt = fLine[0]; | 381 *pt = (*fLine)[0]; |
| 375 *lineT = 0; | 382 *lineT = 0; |
| 376 } else if (SkDPoint::ApproximatelyEqual(gridPt, fLine[1].asSkPoint())) { | 383 } else if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[1].asSkPoint())
) { |
| 377 *pt = fLine[1]; | 384 *pt = (*fLine)[1]; |
| 378 *lineT = 1; | 385 *lineT = 1; |
| 379 } | 386 } |
| 380 if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[
1][0], *lineT)) { | 387 if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[
1][0], *lineT)) { |
| 381 return false; | 388 return false; |
| 382 } | 389 } |
| 383 if (gridPt == fQuad[0].asSkPoint()) { | 390 if (gridPt == fQuad[0].asSkPoint()) { |
| 384 *pt = fQuad[0]; | 391 *pt = fQuad[0]; |
| 385 *quadT = 0; | 392 *quadT = 0; |
| 386 } else if (gridPt == fQuad[2].asSkPoint()) { | 393 } else if (gridPt == fQuad[2].asSkPoint()) { |
| 387 *pt = fQuad[2]; | 394 *pt = fQuad[2]; |
| 388 *quadT = 1; | 395 *quadT = 1; |
| 389 } | 396 } |
| 390 return true; | 397 return true; |
| 391 } | 398 } |
| 392 | 399 |
| 393 private: | 400 private: |
| 394 const SkDQuad& fQuad; | 401 const SkDQuad& fQuad; |
| 395 const SkDLine& fLine; | 402 const SkDLine* fLine; |
| 396 SkIntersections* fIntersections; | 403 SkIntersections* fIntersections; |
| 397 bool fAllowNear; | 404 bool fAllowNear; |
| 398 }; | 405 }; |
| 399 | 406 |
| 400 int SkIntersections::horizontal(const SkDQuad& quad, double left, double right,
double y, | 407 int SkIntersections::horizontal(const SkDQuad& quad, double left, double right,
double y, |
| 401 bool flipped) { | 408 bool flipped) { |
| 402 SkDLine line = {{{ left, y }, { right, y }}}; | 409 SkDLine line = {{{ left, y }, { right, y }}}; |
| 403 LineQuadraticIntersections q(quad, line, this); | 410 LineQuadraticIntersections q(quad, line, this); |
| 404 return q.horizontalIntersect(y, left, right, flipped); | 411 return q.horizontalIntersect(y, left, right, flipped); |
| 405 } | 412 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 418 } | 425 } |
| 419 | 426 |
| 420 int SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) { | 427 int SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) { |
| 421 LineQuadraticIntersections q(quad, line, this); | 428 LineQuadraticIntersections q(quad, line, this); |
| 422 fUsed = q.intersectRay(fT[0]); | 429 fUsed = q.intersectRay(fT[0]); |
| 423 for (int index = 0; index < fUsed; ++index) { | 430 for (int index = 0; index < fUsed; ++index) { |
| 424 fPt[index] = quad.ptAtT(fT[0][index]); | 431 fPt[index] = quad.ptAtT(fT[0][index]); |
| 425 } | 432 } |
| 426 return fUsed; | 433 return fUsed; |
| 427 } | 434 } |
| 435 |
| 436 int SkIntersections::HorizontalIntercept(const SkDQuad& quad, SkScalar y, double
* roots) { |
| 437 LineQuadraticIntersections q(quad); |
| 438 return q.horizontalIntersect(y, roots); |
| 439 } |
| 440 |
| 441 int SkIntersections::VerticalIntercept(const SkDQuad& quad, SkScalar x, double*
roots) { |
| 442 LineQuadraticIntersections q(quad); |
| 443 return q.verticalIntersect(x, roots); |
| 444 } |
| OLD | NEW |