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 |