OLD | NEW |
1 // Another approach is to start with the implicit form of one curve and solve | 1 // Another approach is to start with the implicit form of one curve and solve |
2 // (seek implicit coefficients in QuadraticParameter.cpp | 2 // (seek implicit coefficients in QuadraticParameter.cpp |
3 // by substituting in the parametric form of the other. | 3 // by substituting in the parametric form of the other. |
4 // The downside of this approach is that early rejects are difficult to come by. | 4 // The downside of this approach is that early rejects are difficult to come by. |
5 // http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormu
la.html#step | 5 // http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormu
la.html#step |
6 | 6 |
7 | 7 |
8 #include "SkDQuadImplicit.h" | 8 #include "SkDQuadImplicit.h" |
9 #include "SkIntersections.h" | 9 #include "SkIntersections.h" |
10 #include "SkPathOpsLine.h" | 10 #include "SkPathOpsLine.h" |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 if (roots == 0) { | 132 if (roots == 0) { |
133 if (subDivide) { | 133 if (subDivide) { |
134 *subDivide = true; | 134 *subDivide = true; |
135 } | 135 } |
136 return true; | 136 return true; |
137 } | 137 } |
138 if (roots == 2) { | 138 if (roots == 2) { |
139 return false; | 139 return false; |
140 } | 140 } |
141 SkDPoint pt2 = q1.ptAtT(rootTs[0][0]); | 141 SkDPoint pt2 = q1.ptAtT(rootTs[0][0]); |
142 if (!pt2.approximatelyEqualHalf(mid)) { | 142 if (!pt2.approximatelyEqual(mid)) { |
143 return false; | 143 return false; |
144 } | 144 } |
145 i->insertSwap(rootTs[0][0], tMid, pt2); | 145 i->insertSwap(rootTs[0][0], tMid, pt2); |
146 return true; | 146 return true; |
147 } | 147 } |
148 | 148 |
149 static bool is_linear_inner(const SkDQuad& q1, double t1s, double t1e, const SkD
Quad& q2, | 149 static bool is_linear_inner(const SkDQuad& q1, double t1s, double t1e, const SkD
Quad& q2, |
150 double t2s, double t2e, SkIntersections* i, bool* su
bDivide) { | 150 double t2s, double t2e, SkIntersections* i, bool* su
bDivide) { |
151 SkDQuad hull = q1.subDivide(t1s, t1e); | 151 SkDQuad hull = q1.subDivide(t1s, t1e); |
152 SkDLine line = {{hull[2], hull[0]}}; | 152 SkDLine line = {{hull[2], hull[0]}}; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 static bool is_linear(const SkDQuad& q1, const SkDQuad& q2, SkIntersections* i)
{ | 242 static bool is_linear(const SkDQuad& q1, const SkDQuad& q2, SkIntersections* i)
{ |
243 double measure = flat_measure(q1); | 243 double measure = flat_measure(q1); |
244 // OPTIMIZE: (get rid of sqrt) use approximately_zero | 244 // OPTIMIZE: (get rid of sqrt) use approximately_zero |
245 if (!approximately_zero_sqrt(measure)) { | 245 if (!approximately_zero_sqrt(measure)) { |
246 return false; | 246 return false; |
247 } | 247 } |
248 return is_linear_inner(q1, 0, 1, q2, 0, 1, i, NULL); | 248 return is_linear_inner(q1, 0, 1, q2, 0, 1, i, NULL); |
249 } | 249 } |
250 | 250 |
251 // FIXME: if flat measure is sufficiently large, then probably the quartic solut
ion failed | 251 // FIXME: if flat measure is sufficiently large, then probably the quartic solut
ion failed |
252 static void relaxed_is_linear(const SkDQuad& q1, const SkDQuad& q2, SkIntersecti
ons* i) { | 252 // avoid imprecision incurred with chopAt |
253 double m1 = flat_measure(q1); | 253 static void relaxed_is_linear(const SkDQuad* q1, double s1, double e1, const SkD
Quad* q2, |
254 double m2 = flat_measure(q2); | 254 double s2, double e2, SkIntersections* i) { |
255 #if DEBUG_FLAT_QUADS | 255 double m1 = flat_measure(*q1); |
256 double min = SkTMin(m1, m2); | 256 double m2 = flat_measure(*q2); |
257 if (min > 5) { | 257 i->reset(); |
258 SkDebugf("%s maybe not flat enough.. %1.9g\n", __FUNCTION__, min); | 258 const SkDQuad* rounder, *flatter; |
| 259 double sf, midf, ef, sr, er; |
| 260 if (m2 < m1) { |
| 261 rounder = q1; |
| 262 sr = s1; |
| 263 er = e1; |
| 264 flatter = q2; |
| 265 sf = s2; |
| 266 midf = (s2 + e2) / 2; |
| 267 ef = e2; |
| 268 } else { |
| 269 rounder = q2; |
| 270 sr = s2; |
| 271 er = e2; |
| 272 flatter = q1; |
| 273 sf = s1; |
| 274 midf = (s1 + e1) / 2; |
| 275 ef = e1; |
259 } | 276 } |
260 #endif | |
261 i->reset(); | |
262 const SkDQuad& rounder = m2 < m1 ? q1 : q2; | |
263 const SkDQuad& flatter = m2 < m1 ? q2 : q1; | |
264 bool subDivide = false; | 277 bool subDivide = false; |
265 is_linear_inner(flatter, 0, 1, rounder, 0, 1, i, &subDivide); | 278 is_linear_inner(*flatter, sf, ef, *rounder, sr, er, i, &subDivide); |
266 if (subDivide) { | 279 if (subDivide) { |
267 SkDQuadPair pair = flatter.chopAt(0.5); | 280 relaxed_is_linear(flatter, sf, midf, rounder, sr, er, i); |
268 SkIntersections firstI, secondI; | 281 relaxed_is_linear(flatter, midf, ef, rounder, sr, er, i); |
269 relaxed_is_linear(pair.first(), rounder, &firstI); | |
270 for (int index = 0; index < firstI.used(); ++index) { | |
271 i->insert(firstI[0][index] * 0.5, firstI[1][index], firstI.pt(index)
); | |
272 } | |
273 relaxed_is_linear(pair.second(), rounder, &secondI); | |
274 for (int index = 0; index < secondI.used(); ++index) { | |
275 i->insert(0.5 + secondI[0][index] * 0.5, secondI[1][index], secondI.
pt(index)); | |
276 } | |
277 } | 282 } |
278 if (m2 < m1) { | 283 if (m2 < m1) { |
279 i->swapPts(); | 284 i->swapPts(); |
280 } | 285 } |
281 } | 286 } |
282 | 287 |
283 // each time through the loop, this computes values it had from the last loop | 288 // each time through the loop, this computes values it had from the last loop |
284 // if i == j == 1, the center values are still good | 289 // if i == j == 1, the center values are still good |
285 // otherwise, for i != 1 or j != 1, four of the values are still good | 290 // otherwise, for i != 1 or j != 1, four of the values are still good |
286 // and if i == 1 ^ j == 1, an additional value is good | 291 // and if i == 1 ^ j == 1, an additional value is good |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 } | 376 } |
372 SkDLine tmpLine; | 377 SkDLine tmpLine; |
373 int testTIndex = testT << 1; | 378 int testTIndex = testT << 1; |
374 tmpLine[0] = tmpLine[1] = q2[testTIndex]; | 379 tmpLine[0] = tmpLine[1] = q2[testTIndex]; |
375 tmpLine[1].fX += q2[1].fY - q2[testTIndex].fY; | 380 tmpLine[1].fX += q2[1].fY - q2[testTIndex].fY; |
376 tmpLine[1].fY -= q2[1].fX - q2[testTIndex].fX; | 381 tmpLine[1].fY -= q2[1].fX - q2[testTIndex].fX; |
377 SkIntersections impTs; | 382 SkIntersections impTs; |
378 impTs.intersectRay(q1, tmpLine); | 383 impTs.intersectRay(q1, tmpLine); |
379 for (int index = 0; index < impTs.used(); ++index) { | 384 for (int index = 0; index < impTs.used(); ++index) { |
380 SkDPoint realPt = impTs.pt(index); | 385 SkDPoint realPt = impTs.pt(index); |
381 if (!tmpLine[0].approximatelyEqualHalf(realPt)) { | 386 if (!tmpLine[0].approximatelyEqual(realPt)) { |
382 continue; | 387 continue; |
383 } | 388 } |
384 if (swap) { | 389 if (swap) { |
385 i->insert(testT, impTs[0][index], tmpLine[0]); | 390 i->insert(testT, impTs[0][index], tmpLine[0]); |
386 } else { | 391 } else { |
387 i->insert(impTs[0][index], testT, tmpLine[0]); | 392 i->insert(impTs[0][index], testT, tmpLine[0]); |
388 } | 393 } |
389 } | 394 } |
390 } | 395 } |
391 | 396 |
392 int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) { | 397 int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) { |
| 398 fMax = 4; |
393 // if the quads share an end point, check to see if they overlap | 399 // if the quads share an end point, check to see if they overlap |
394 for (int i1 = 0; i1 < 3; i1 += 2) { | 400 for (int i1 = 0; i1 < 3; i1 += 2) { |
395 for (int i2 = 0; i2 < 3; i2 += 2) { | 401 for (int i2 = 0; i2 < 3; i2 += 2) { |
396 if (q1[i1] == q2[i2]) { | 402 if (q1[i1] == q2[i2]) { |
397 insert(i1 >> 1, i2 >> 1, q1[i1]); | 403 insert(i1 >> 1, i2 >> 1, q1[i1]); |
398 } | 404 } |
399 } | 405 } |
400 } | 406 } |
401 if (fAllowNear || true) { // FIXME ? cubic/cubic intersection fails withou
t (cubicOp67u) | 407 if (fAllowNear || true) { // FIXME ? cubic/cubic intersection fails withou
t (cubicOp67u) |
402 for (int i1 = 0; i1 < 3; i1 += 2) { | 408 for (int i1 = 0; i1 < 3; i1 += 2) { |
403 for (int i2 = 0; i2 < 3; i2 += 2) { | 409 for (int i2 = 0; i2 < 3; i2 += 2) { |
404 if (q1[i1] != q2[i2] && q1[i1].approximatelyEqualHalf(q2[i2])) { | 410 if (q1[i1] != q2[i2] && q1[i1].approximatelyEqual(q2[i2])) { |
405 insertNear(i1 >> 1, i2 >> 1, q1[i1]); | 411 insertNear(i1 >> 1, i2 >> 1, q1[i1]); |
406 } | 412 } |
407 } | 413 } |
408 } | 414 } |
409 } | 415 } |
410 SkASSERT(fUsed < 3); | 416 SkASSERT(fUsed < 3); |
411 if (only_end_pts_in_common(q1, q2)) { | 417 if (only_end_pts_in_common(q1, q2)) { |
412 return fUsed; | 418 return fUsed; |
413 } | 419 } |
414 if (only_end_pts_in_common(q2, q1)) { | 420 if (only_end_pts_in_common(q2, q1)) { |
415 return fUsed; | 421 return fUsed; |
416 } | 422 } |
417 // see if either quad is really a line | 423 // see if either quad is really a line |
418 // FIXME: figure out why reduce step didn't find this earlier | 424 // FIXME: figure out why reduce step didn't find this earlier |
419 if (is_linear(q1, q2, this)) { | 425 if (is_linear(q1, q2, this)) { |
420 return fUsed; | 426 return fUsed; |
421 } | 427 } |
422 SkIntersections swapped; | 428 SkIntersections swapped; |
| 429 swapped.setMax(fMax); |
423 if (is_linear(q2, q1, &swapped)) { | 430 if (is_linear(q2, q1, &swapped)) { |
424 swapped.swapPts(); | 431 swapped.swapPts(); |
425 set(swapped); | 432 set(swapped); |
426 return fUsed; | 433 return fUsed; |
427 } | 434 } |
428 SkIntersections copyI(*this); | 435 SkIntersections copyI(*this); |
429 lookNearEnd(q1, q2, 0, *this, false, ©I); | 436 lookNearEnd(q1, q2, 0, *this, false, ©I); |
430 lookNearEnd(q1, q2, 1, *this, false, ©I); | 437 lookNearEnd(q1, q2, 1, *this, false, ©I); |
431 lookNearEnd(q2, q1, 0, *this, true, ©I); | 438 lookNearEnd(q2, q1, 0, *this, true, ©I); |
432 lookNearEnd(q2, q1, 1, *this, true, ©I); | 439 lookNearEnd(q2, q1, 1, *this, true, ©I); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 double roots2[4]; | 484 double roots2[4]; |
478 int rootCount2 = findRoots(i1, q2, roots2, useCubic, flip2, 0); | 485 int rootCount2 = findRoots(i1, q2, roots2, useCubic, flip2, 0); |
479 double roots2Copy[4]; | 486 double roots2Copy[4]; |
480 int r2Count = addValidRoots(roots2, rootCount2, roots2Copy); | 487 int r2Count = addValidRoots(roots2, rootCount2, roots2Copy); |
481 SkDPoint pts2[4]; | 488 SkDPoint pts2[4]; |
482 for (index = 0; index < r2Count; ++index) { | 489 for (index = 0; index < r2Count; ++index) { |
483 pts2[index] = q2.ptAtT(roots2Copy[index]); | 490 pts2[index] = q2.ptAtT(roots2Copy[index]); |
484 } | 491 } |
485 if (r1Count == r2Count && r1Count <= 1) { | 492 if (r1Count == r2Count && r1Count <= 1) { |
486 if (r1Count == 1) { | 493 if (r1Count == 1) { |
487 if (pts1[0].approximatelyEqualHalf(pts2[0])) { | 494 if (pts1[0].approximatelyEqual(pts2[0])) { |
488 insert(roots1Copy[0], roots2Copy[0], pts1[0]); | 495 insert(roots1Copy[0], roots2Copy[0], pts1[0]); |
489 } else if (pts1[0].moreRoughlyEqual(pts2[0])) { | 496 } else if (pts1[0].moreRoughlyEqual(pts2[0])) { |
490 // experiment: try to find intersection by chasing t | 497 // experiment: try to find intersection by chasing t |
491 rootCount = findRoots(i2, q1, roots1, useCubic, flip1, 0); | 498 rootCount = findRoots(i2, q1, roots1, useCubic, flip1, 0); |
492 (void) addValidRoots(roots1, rootCount, roots1Copy); | 499 (void) addValidRoots(roots1, rootCount, roots1Copy); |
493 rootCount2 = findRoots(i1, q2, roots2, useCubic, flip2, 0); | 500 rootCount2 = findRoots(i1, q2, roots2, useCubic, flip2, 0); |
494 (void) addValidRoots(roots2, rootCount2, roots2Copy); | 501 (void) addValidRoots(roots2, rootCount2, roots2Copy); |
495 if (binary_search(q1, q2, roots1Copy, roots2Copy, pts1)) { | 502 if (binary_search(q1, q2, roots1Copy, roots2Copy, pts1)) { |
496 insert(roots1Copy[0], roots2Copy[0], pts1[0]); | 503 insert(roots1Copy[0], roots2Copy[0], pts1[0]); |
497 } | 504 } |
498 } | 505 } |
499 } | 506 } |
500 return fUsed; | 507 return fUsed; |
501 } | 508 } |
502 int closest[4]; | 509 int closest[4]; |
503 double dist[4]; | 510 double dist[4]; |
504 bool foundSomething = false; | 511 bool foundSomething = false; |
505 for (index = 0; index < r1Count; ++index) { | 512 for (index = 0; index < r1Count; ++index) { |
506 dist[index] = DBL_MAX; | 513 dist[index] = DBL_MAX; |
507 closest[index] = -1; | 514 closest[index] = -1; |
508 for (int ndex2 = 0; ndex2 < r2Count; ++ndex2) { | 515 for (int ndex2 = 0; ndex2 < r2Count; ++ndex2) { |
509 if (!pts2[ndex2].approximatelyEqualHalf(pts1[index])) { | 516 if (!pts2[ndex2].approximatelyEqual(pts1[index])) { |
510 continue; | 517 continue; |
511 } | 518 } |
512 double dx = pts2[ndex2].fX - pts1[index].fX; | 519 double dx = pts2[ndex2].fX - pts1[index].fX; |
513 double dy = pts2[ndex2].fY - pts1[index].fY; | 520 double dy = pts2[ndex2].fY - pts1[index].fY; |
514 double distance = dx * dx + dy * dy; | 521 double distance = dx * dx + dy * dy; |
515 if (dist[index] <= distance) { | 522 if (dist[index] <= distance) { |
516 continue; | 523 continue; |
517 } | 524 } |
518 for (int outer = 0; outer < index; ++outer) { | 525 for (int outer = 0; outer < index; ++outer) { |
519 if (closest[outer] != ndex2) { | 526 if (closest[outer] != ndex2) { |
520 continue; | 527 continue; |
521 } | 528 } |
522 if (dist[outer] < distance) { | 529 if (dist[outer] < distance) { |
523 goto next; | 530 goto next; |
524 } | 531 } |
525 closest[outer] = -1; | 532 closest[outer] = -1; |
526 } | 533 } |
527 dist[index] = distance; | 534 dist[index] = distance; |
528 closest[index] = ndex2; | 535 closest[index] = ndex2; |
529 foundSomething = true; | 536 foundSomething = true; |
530 next: | 537 next: |
531 ; | 538 ; |
532 } | 539 } |
533 } | 540 } |
534 if (r1Count && r2Count && !foundSomething) { | 541 if (r1Count && r2Count && !foundSomething) { |
535 relaxed_is_linear(q1, q2, this); | 542 relaxed_is_linear(&q1, 0, 1, &q2, 0, 1, this); |
536 return fUsed; | 543 return fUsed; |
537 } | 544 } |
538 int used = 0; | 545 int used = 0; |
539 do { | 546 do { |
540 double lowest = DBL_MAX; | 547 double lowest = DBL_MAX; |
541 int lowestIndex = -1; | 548 int lowestIndex = -1; |
542 for (index = 0; index < r1Count; ++index) { | 549 for (index = 0; index < r1Count; ++index) { |
543 if (closest[index] < 0) { | 550 if (closest[index] < 0) { |
544 continue; | 551 continue; |
545 } | 552 } |
546 if (roots1Copy[index] < lowest) { | 553 if (roots1Copy[index] < lowest) { |
547 lowestIndex = index; | 554 lowestIndex = index; |
548 lowest = roots1Copy[index]; | 555 lowest = roots1Copy[index]; |
549 } | 556 } |
550 } | 557 } |
551 if (lowestIndex < 0) { | 558 if (lowestIndex < 0) { |
552 break; | 559 break; |
553 } | 560 } |
554 insert(roots1Copy[lowestIndex], roots2Copy[closest[lowestIndex]], | 561 insert(roots1Copy[lowestIndex], roots2Copy[closest[lowestIndex]], |
555 pts1[lowestIndex]); | 562 pts1[lowestIndex]); |
556 closest[lowestIndex] = -1; | 563 closest[lowestIndex] = -1; |
557 } while (++used < r1Count); | 564 } while (++used < r1Count); |
558 return fUsed; | 565 return fUsed; |
559 } | 566 } |
OLD | NEW |