| 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 | 7 | 
| 8 #include "SkIntersections.h" | 8 #include "SkIntersections.h" | 
| 9 #include "SkPathOpsCubic.h" | 9 #include "SkPathOpsCubic.h" | 
| 10 #include "SkPathOpsLine.h" | 10 #include "SkPathOpsLine.h" | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 107                     && tLimits1[1][0] >= t2Start && tLimits1[1][1] <= t2) { | 107                     && tLimits1[1][0] >= t2Start && tLimits1[1][1] <= t2) { | 
| 108                 SkDebugf("%.*s %s t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)", i.depth()*
     2, tab, | 108                 SkDebugf("%.*s %s t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)", i.depth()*
     2, tab, | 
| 109                         __FUNCTION__, t1Start, t1, t2Start, t2); | 109                         __FUNCTION__, t1Start, t1, t2Start, t2); | 
| 110                 SkIntersections xlocals; | 110                 SkIntersections xlocals; | 
| 111                 intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, xlocals); | 111                 intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, xlocals); | 
| 112                 SkDebugf(" xlocals.fUsed=%d\n", xlocals.used()); | 112                 SkDebugf(" xlocals.fUsed=%d\n", xlocals.used()); | 
| 113             } | 113             } | 
| 114         #endif | 114         #endif | 
| 115             SkIntersections locals; | 115             SkIntersections locals; | 
| 116             intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, locals); | 116             intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, locals); | 
| 117             double coStart[2] = { -1 }; |  | 
| 118             SkDPoint coPoint; |  | 
| 119             int tCount = locals.used(); | 117             int tCount = locals.used(); | 
| 120             for (int tIdx = 0; tIdx < tCount; ++tIdx) { | 118             for (int tIdx = 0; tIdx < tCount; ++tIdx) { | 
| 121                 double to1 = t1Start + (t1 - t1Start) * locals[0][tIdx]; | 119                 double to1 = t1Start + (t1 - t1Start) * locals[0][tIdx]; | 
| 122                 double to2 = t2Start + (t2 - t2Start) * locals[1][tIdx]; | 120                 double to2 = t2Start + (t2 - t2Start) * locals[1][tIdx]; | 
| 123     // if the computed t is not sufficiently precise, iterate | 121     // if the computed t is not sufficiently precise, iterate | 
| 124                 SkDPoint p1 = cubic1.xyAtT(to1); | 122                 SkDPoint p1 = cubic1.ptAtT(to1); | 
| 125                 SkDPoint p2 = cubic2.xyAtT(to2); | 123                 SkDPoint p2 = cubic2.ptAtT(to2); | 
| 126                 if (p1.approximatelyEqual(p2)) { | 124                 if (p1.approximatelyEqual(p2)) { | 
| 127                     if (locals.isCoincident(tIdx)) { | 125                     SkASSERT(!locals.isCoincident(tIdx)); | 
| 128                         if (coStart[0] < 0) { | 126                     if (&cubic1 != &cubic2 || !approximately_equal(to1, to2)) { | 
| 129                             coStart[0] = to1; |  | 
| 130                             coStart[1] = to2; |  | 
| 131                             coPoint = p1; |  | 
| 132                         } else { |  | 
| 133                             i.insertCoincidentPair(coStart[0], to1, coStart[1], 
     to2, coPoint, p1); |  | 
| 134                             coStart[0] = -1; |  | 
| 135                         } |  | 
| 136                     } else if (&cubic1 != &cubic2 || !approximately_equal(to1, t
     o2)) { |  | 
| 137                         if (i.swapped()) {  //  FIXME: insert should respect swa
     p | 127                         if (i.swapped()) {  //  FIXME: insert should respect swa
     p | 
| 138                             i.insert(to2, to1, p1); | 128                             i.insert(to2, to1, p1); | 
| 139                         } else { | 129                         } else { | 
| 140                             i.insert(to1, to2, p1); | 130                             i.insert(to1, to2, p1); | 
| 141                         } | 131                         } | 
| 142                     } | 132                     } | 
| 143                 } else { | 133                 } else { | 
| 144                     double offset = precisionScale / 16;  // FIME: const is arbi
     trary: test, refine | 134                     double offset = precisionScale / 16;  // FIME: const is arbi
     trary: test, refine | 
| 145                     double c1Bottom = tIdx == 0 ? 0 : | 135                     double c1Bottom = tIdx == 0 ? 0 : | 
| 146                             (t1Start + (t1 - t1Start) * locals[0][tIdx - 1] + to
     1) / 2; | 136                             (t1Start + (t1 - t1Start) * locals[0][tIdx - 1] + to
     1) / 2; | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 243                             i.used(), i.used() > 0 ? i[0][i.used() - 1] : -1); | 233                             i.used(), i.used() > 0 ? i[0][i.used() - 1] : -1); | 
| 244                 #endif | 234                 #endif | 
| 245                     } | 235                     } | 
| 246           //          intersect(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offs
     et, i); | 236           //          intersect(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offs
     et, i); | 
| 247                     // FIXME: if no intersection is found, either quadratics int
     ersected where | 237                     // FIXME: if no intersection is found, either quadratics int
     ersected where | 
| 248                     // cubics did not, or the intersection was missed. In the fo
     rmer case, expect | 238                     // cubics did not, or the intersection was missed. In the fo
     rmer case, expect | 
| 249                     // the quadratics to be nearly parallel at the point of inte
     rsection, and check | 239                     // the quadratics to be nearly parallel at the point of inte
     rsection, and check | 
| 250                     // for that. | 240                     // for that. | 
| 251                 } | 241                 } | 
| 252             } | 242             } | 
| 253             SkASSERT(coStart[0] == -1); |  | 
| 254             t2Start = t2; | 243             t2Start = t2; | 
| 255         } | 244         } | 
| 256         t1Start = t1; | 245         t1Start = t1; | 
| 257     } | 246     } | 
| 258     i.downDepth(); | 247     i.downDepth(); | 
| 259 } | 248 } | 
| 260 | 249 | 
| 261 #define LINE_FRACTION 0.1 | 250 #define LINE_FRACTION 0.1 | 
| 262 | 251 | 
| 263 // intersect the end of the cubic with the other. Try lines from the end to cont
     rol and opposite | 252 // intersect the end of the cubic with the other. Try lines from the end to cont
     rol and opposite | 
| 264 // end to determine range of t on opposite cubic. | 253 // end to determine range of t on opposite cubic. | 
| 265 static void intersectEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cub
     ic2, | 254 static void intersectEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cub
     ic2, | 
| 266                          const SkDRect& bounds2, SkIntersections& i) { | 255                          const SkDRect& bounds2, bool selfIntersect, SkIntersect
     ions& i) { | 
| 267     SkDLine line; | 256     SkDLine line; | 
| 268     int t1Index = start ? 0 : 3; | 257     int t1Index = start ? 0 : 3; | 
|  | 258     bool swap = i.swapped(); | 
|  | 259     double testT = (double) !start; | 
|  | 260     // quad/quad at this point checks to see if exact matches have already been 
     found | 
|  | 261     // cubic/cubic can't reject so easily since cubics can intersect same point 
     more than once | 
|  | 262     if (!selfIntersect) { | 
|  | 263         SkDLine tmpLine; | 
|  | 264         tmpLine[0] = tmpLine[1] = cubic2[t1Index]; | 
|  | 265         tmpLine[1].fX += cubic2[2 - start].fY - cubic2[t1Index].fY; | 
|  | 266         tmpLine[1].fY -= cubic2[2 - start].fX - cubic2[t1Index].fX; | 
|  | 267         SkIntersections impTs; | 
|  | 268         impTs.intersectRay(cubic1, tmpLine); | 
|  | 269         for (int index = 0; index < impTs.used(); ++index) { | 
|  | 270             SkDPoint realPt = impTs.pt(index); | 
|  | 271             if (!tmpLine[0].approximatelyEqualHalf(realPt)) { | 
|  | 272                 continue; | 
|  | 273             } | 
|  | 274             if (swap) { | 
|  | 275                 i.insert(testT, impTs[0][index], tmpLine[0]); | 
|  | 276             } else { | 
|  | 277                 i.insert(impTs[0][index], testT, tmpLine[0]); | 
|  | 278             } | 
|  | 279             return; | 
|  | 280         } | 
|  | 281     } | 
| 269     // don't bother if the two cubics are connnected | 282     // don't bother if the two cubics are connnected | 
| 270 #if 1 |  | 
| 271     static const int kPointsInCubic = 4; // FIXME: move to DCubic, replace '4' w
     ith this | 283     static const int kPointsInCubic = 4; // FIXME: move to DCubic, replace '4' w
     ith this | 
| 272     static const int kMaxLineCubicIntersections = 3; | 284     static const int kMaxLineCubicIntersections = 3; | 
| 273     SkSTArray<(kMaxLineCubicIntersections - 1) * kMaxLineCubicIntersections, dou
     ble, true> tVals; | 285     SkSTArray<(kMaxLineCubicIntersections - 1) * kMaxLineCubicIntersections, dou
     ble, true> tVals; | 
| 274     line[0] = cubic1[t1Index]; | 286     line[0] = cubic1[t1Index]; | 
| 275     // this variant looks for intersections with the end point and lines paralle
     l to other points | 287     // this variant looks for intersections with the end point and lines paralle
     l to other points | 
| 276     for (int index = 0; index < kPointsInCubic; ++index) { | 288     for (int index = 0; index < kPointsInCubic; ++index) { | 
| 277         if (index == t1Index) { | 289         if (index == t1Index) { | 
| 278             continue; | 290             continue; | 
| 279         } | 291         } | 
| 280         SkDVector dxy1 = cubic1[index] - line[0]; | 292         SkDVector dxy1 = cubic1[index] - line[0]; | 
| 281         dxy1 /= SkDCubic::gPrecisionUnit; | 293         dxy1 /= SkDCubic::gPrecisionUnit; | 
| 282         line[1] = line[0] + dxy1; | 294         line[1] = line[0] + dxy1; | 
| 283         SkDRect lineBounds; | 295         SkDRect lineBounds; | 
| 284         lineBounds.setBounds(line); | 296         lineBounds.setBounds(line); | 
| 285         if (!bounds2.intersects(&lineBounds)) { | 297         if (!bounds2.intersects(&lineBounds)) { | 
| 286             continue; | 298             continue; | 
| 287         } | 299         } | 
| 288         SkIntersections local; | 300         SkIntersections local; | 
| 289         if (!local.intersect(cubic2, line)) { | 301         if (!local.intersect(cubic2, line)) { | 
| 290             continue; | 302             continue; | 
| 291         } | 303         } | 
| 292         for (int idx2 = 0; idx2 < local.used(); ++idx2) { | 304         for (int idx2 = 0; idx2 < local.used(); ++idx2) { | 
| 293             double foundT = local[0][idx2]; | 305             double foundT = local[0][idx2]; | 
| 294             if (approximately_less_than_zero(foundT) | 306             if (approximately_less_than_zero(foundT) | 
| 295                     || approximately_greater_than_one(foundT)) { | 307                     || approximately_greater_than_one(foundT)) { | 
| 296                 continue; | 308                 continue; | 
| 297             } | 309             } | 
| 298             if (local.pt(idx2).approximatelyEqual(line[0])) { | 310             if (local.pt(idx2).approximatelyEqual(line[0])) { | 
| 299                 if (i.swapped()) {  // FIXME: insert should respect swap | 311                 if (i.swapped()) {  // FIXME: insert should respect swap | 
| 300                     i.insert(foundT, start ? 0 : 1, line[0]); | 312                     i.insert(foundT, testT, line[0]); | 
| 301                 } else { | 313                 } else { | 
| 302                     i.insert(start ? 0 : 1, foundT, line[0]); | 314                     i.insert(testT, foundT, line[0]); | 
| 303                 } | 315                 } | 
| 304             } else { | 316             } else { | 
| 305                 tVals.push_back(foundT); | 317                 tVals.push_back(foundT); | 
| 306             } | 318             } | 
| 307         } | 319         } | 
| 308     } | 320     } | 
| 309     if (tVals.count() == 0) { | 321     if (tVals.count() == 0) { | 
| 310         return; | 322         return; | 
| 311     } | 323     } | 
| 312     SkTQSort<double>(tVals.begin(), tVals.end() - 1); | 324     SkTQSort<double>(tVals.begin(), tVals.end() - 1); | 
| 313     double tMin1 = start ? 0 : 1 - LINE_FRACTION; | 325     double tMin1 = start ? 0 : 1 - LINE_FRACTION; | 
| 314     double tMax1 = start ? LINE_FRACTION : 1; | 326     double tMax1 = start ? LINE_FRACTION : 1; | 
| 315     int tIdx = 0; | 327     int tIdx = 0; | 
| 316     do { | 328     do { | 
| 317         int tLast = tIdx; | 329         int tLast = tIdx; | 
| 318         while (tLast + 1 < tVals.count() && roughly_equal(tVals[tLast + 1], tVal
     s[tIdx])) { | 330         while (tLast + 1 < tVals.count() && roughly_equal(tVals[tLast + 1], tVal
     s[tIdx])) { | 
| 319             ++tLast; | 331             ++tLast; | 
| 320         } | 332         } | 
| 321         double tMin2 = SkTMax(tVals[tIdx] - LINE_FRACTION, 0.0); | 333         double tMin2 = SkTMax(tVals[tIdx] - LINE_FRACTION, 0.0); | 
| 322         double tMax2 = SkTMin(tVals[tLast] + LINE_FRACTION, 1.0); | 334         double tMax2 = SkTMin(tVals[tLast] + LINE_FRACTION, 1.0); | 
| 323         int lastUsed = i.used(); | 335         int lastUsed = i.used(); | 
| 324         intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | 336         intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | 
| 325         if (lastUsed == i.used()) { | 337         if (lastUsed == i.used()) { | 
| 326             tMin2 = SkTMax(tVals[tIdx] - (1.0 / SkDCubic::gPrecisionUnit), 0.0); | 338             tMin2 = SkTMax(tVals[tIdx] - (1.0 / SkDCubic::gPrecisionUnit), 0.0); | 
| 327             tMax2 = SkTMin(tVals[tLast] + (1.0 / SkDCubic::gPrecisionUnit), 1.0)
     ; | 339             tMax2 = SkTMin(tVals[tLast] + (1.0 / SkDCubic::gPrecisionUnit), 1.0)
     ; | 
| 328             intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | 340             intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | 
| 329         } | 341         } | 
| 330         tIdx = tLast + 1; | 342         tIdx = tLast + 1; | 
| 331     } while (tIdx < tVals.count()); | 343     } while (tIdx < tVals.count()); | 
| 332 #else |  | 
| 333     const SkDPoint& endPt = cubic1[t1Index]; |  | 
| 334     if (!bounds2.contains(endPt)) { |  | 
| 335         return; |  | 
| 336     } |  | 
| 337     // this variant looks for intersections within an 'x' of the endpoint |  | 
| 338     double delta = SkTMax(bounds2.width(), bounds2.height()); |  | 
| 339     for (int index = 0; index < 2; ++index) { |  | 
| 340         if (index == 0) { |  | 
| 341             line[0].fY = line[1].fY = endPt.fY; |  | 
| 342             line[0].fX = endPt.fX - delta; |  | 
| 343             line[1].fX = endPt.fX + delta; |  | 
| 344         } else { |  | 
| 345             line[0].fX = line[1].fX = cubic1[t1Index].fX; |  | 
| 346             line[0].fY = endPt.fY - delta; |  | 
| 347             line[1].fY = endPt.fY + delta; |  | 
| 348         } |  | 
| 349         SkIntersections local; |  | 
| 350         local.intersectRay(cubic2, line); // OPTIMIZE: special for horizontal/ve
     rtical lines |  | 
| 351         int used = local.used(); |  | 
| 352         for (int index = 0; index < used; ++index) { |  | 
| 353             double foundT = local[0][index]; |  | 
| 354             if (approximately_less_than_zero(foundT) || approximately_greater_th
     an_one(foundT)) { |  | 
| 355                 continue; |  | 
| 356             } |  | 
| 357             if (!local.pt(index).approximatelyEqual(endPt)) { |  | 
| 358                 continue; |  | 
| 359             } |  | 
| 360             if (i.swapped()) {  // FIXME: insert should respect swap |  | 
| 361                 i.insert(foundT, start ? 0 : 1, endPt); |  | 
| 362             } else { |  | 
| 363                 i.insert(start ? 0 : 1, foundT, endPt); |  | 
| 364             } |  | 
| 365             return; |  | 
| 366         } |  | 
| 367     } |  | 
| 368 // the above doesn't catch when the end of the cubic missed the other cubic beca
     use the quad |  | 
| 369 // approximation moved too far away, so something like the below is still needed
     . The enabled |  | 
| 370 // code above tries to avoid this heavy lifting unless the convex hull intersect
     ed the cubic. |  | 
| 371     double tMin1 = start ? 0 : 1 - LINE_FRACTION; |  | 
| 372     double tMax1 = start ? LINE_FRACTION : 1; |  | 
| 373     double tMin2 = SkTMax(foundT - LINE_FRACTION, 0.0); |  | 
| 374     double tMax2 = SkTMin(foundT + LINE_FRACTION, 1.0); |  | 
| 375     int lastUsed = i.used(); |  | 
| 376     intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); |  | 
| 377     if (lastUsed == i.used()) { |  | 
| 378         tMin2 = SkTMax(foundT - (1.0 / SkDCubic::gPrecisionUnit), 0.0); |  | 
| 379         tMax2 = SkTMin(foundT + (1.0 / SkDCubic::gPrecisionUnit), 1.0); |  | 
| 380         intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); |  | 
| 381     } |  | 
| 382 #endif |  | 
| 383     return; | 344     return; | 
| 384 } | 345 } | 
| 385 | 346 | 
| 386 const double CLOSE_ENOUGH = 0.001; | 347 const double CLOSE_ENOUGH = 0.001; | 
| 387 | 348 | 
| 388 static bool closeStart(const SkDCubic& cubic, int cubicIndex, SkIntersections& i
     , SkDPoint& pt) { | 349 static bool closeStart(const SkDCubic& cubic, int cubicIndex, SkIntersections& i
     , SkDPoint& pt) { | 
| 389     if (i[cubicIndex][0] != 0 || i[cubicIndex][1] > CLOSE_ENOUGH) { | 350     if (i[cubicIndex][0] != 0 || i[cubicIndex][1] > CLOSE_ENOUGH) { | 
| 390         return false; | 351         return false; | 
| 391     } | 352     } | 
| 392     pt = cubic.xyAtT((i[cubicIndex][0] + i[cubicIndex][1]) / 2); | 353     pt = cubic.ptAtT((i[cubicIndex][0] + i[cubicIndex][1]) / 2); | 
| 393     return true; | 354     return true; | 
| 394 } | 355 } | 
| 395 | 356 | 
| 396 static bool closeEnd(const SkDCubic& cubic, int cubicIndex, SkIntersections& i, 
     SkDPoint& pt) { | 357 static bool closeEnd(const SkDCubic& cubic, int cubicIndex, SkIntersections& i, 
     SkDPoint& pt) { | 
| 397     int last = i.used() - 1; | 358     int last = i.used() - 1; | 
| 398     if (i[cubicIndex][last] != 1 || i[cubicIndex][last - 1] < 1 - CLOSE_ENOUGH) 
     { | 359     if (i[cubicIndex][last] != 1 || i[cubicIndex][last - 1] < 1 - CLOSE_ENOUGH) 
     { | 
| 399         return false; | 360         return false; | 
| 400     } | 361     } | 
| 401     pt = cubic.xyAtT((i[cubicIndex][last] + i[cubicIndex][last - 1]) / 2); | 362     pt = cubic.ptAtT((i[cubicIndex][last] + i[cubicIndex][last - 1]) / 2); | 
| 402     return true; | 363     return true; | 
| 403 } | 364 } | 
| 404 | 365 | 
|  | 366 static bool only_end_pts_in_common(const SkDCubic& c1, const SkDCubic& c2) { | 
|  | 367 // the idea here is to see at minimum do a quick reject by rotating all points | 
|  | 368 // to either side of the line formed by connecting the endpoints | 
|  | 369 // if the opposite curves points are on the line or on the other side, the | 
|  | 370 // curves at most intersect at the endpoints | 
|  | 371     for (int oddMan = 0; oddMan < 4; ++oddMan) { | 
|  | 372         const SkDPoint* endPt[3]; | 
|  | 373         for (int opp = 1; opp < 4; ++opp) { | 
|  | 374             int end = oddMan ^ opp;  // choose a value not equal to oddMan | 
|  | 375             endPt[opp - 1] = &c1[end]; | 
|  | 376         } | 
|  | 377         for (int triTest = 0; triTest < 3; ++triTest) { | 
|  | 378             double origX = endPt[triTest]->fX; | 
|  | 379             double origY = endPt[triTest]->fY; | 
|  | 380             int oppTest = triTest + 1; | 
|  | 381             if (3 == oppTest) { | 
|  | 382                 oppTest = 0; | 
|  | 383             } | 
|  | 384             double adj = endPt[oppTest]->fX - origX; | 
|  | 385             double opp = endPt[oppTest]->fY - origY; | 
|  | 386             double sign = (c1[oddMan].fY - origY) * adj - (c1[oddMan].fX - origX
     ) * opp; | 
|  | 387             if (approximately_zero(sign)) { | 
|  | 388                 goto tryNextHalfPlane; | 
|  | 389             } | 
|  | 390             for (int n = 0; n < 4; ++n) { | 
|  | 391                 double test = (c2[n].fY - origY) * adj - (c2[n].fX - origX) * op
     p; | 
|  | 392                 if (test * sign > 0 && !precisely_zero(test)) { | 
|  | 393                     goto tryNextHalfPlane; | 
|  | 394                 } | 
|  | 395             } | 
|  | 396         } | 
|  | 397         return true; | 
|  | 398 tryNextHalfPlane: | 
|  | 399         ; | 
|  | 400     } | 
|  | 401     return false; | 
|  | 402 } | 
|  | 403 | 
| 405 int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) { | 404 int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) { | 
| 406     ::intersect(c1, 0, 1, c2, 0, 1, 1, *this); | 405     bool selfIntersect = &c1 == &c2; | 
|  | 406     if (selfIntersect) { | 
|  | 407         if (c1[0].approximatelyEqualHalf(c1[3])) { | 
|  | 408             insert(0, 1, c1[0]); | 
|  | 409         } | 
|  | 410     } else { | 
|  | 411         for (int i1 = 0; i1 < 4; i1 += 3) { | 
|  | 412             for (int i2 = 0; i2 < 4; i2 += 3) { | 
|  | 413                 if (c1[i1].approximatelyEqualHalf(c2[i2])) { | 
|  | 414                     insert(i1 >> 1, i2 >> 1, c1[i1]); | 
|  | 415                 } | 
|  | 416             } | 
|  | 417         } | 
|  | 418     } | 
|  | 419     SkASSERT(fUsed < 4); | 
|  | 420     if (!selfIntersect) { | 
|  | 421         if (only_end_pts_in_common(c1, c2)) { | 
|  | 422             return fUsed; | 
|  | 423         } | 
|  | 424         if (only_end_pts_in_common(c2, c1)) { | 
|  | 425             return fUsed; | 
|  | 426         } | 
|  | 427     } | 
|  | 428     // quad/quad does linear test here -- cubic does not | 
|  | 429     // cubics which are really lines should have been detected in reduce step ea
     rlier | 
|  | 430     SkDRect c1Bounds, c2Bounds; | 
| 407     // FIXME: pass in cached bounds from caller | 431     // FIXME: pass in cached bounds from caller | 
| 408     SkDRect c1Bounds, c2Bounds; |  | 
| 409     c1Bounds.setBounds(c1);  // OPTIMIZE use setRawBounds ? | 432     c1Bounds.setBounds(c1);  // OPTIMIZE use setRawBounds ? | 
| 410     c2Bounds.setBounds(c2); | 433     c2Bounds.setBounds(c2); | 
| 411     intersectEnd(c1, false, c2, c2Bounds, *this); | 434     intersectEnd(c1, false, c2, c2Bounds, selfIntersect, *this); | 
| 412     intersectEnd(c1, true, c2, c2Bounds, *this); | 435     intersectEnd(c1, true, c2, c2Bounds, selfIntersect, *this); | 
| 413     bool selfIntersect = &c1 == &c2; | 436     if (selfIntersect) { | 
| 414     if (!selfIntersect) { | 437         if (fUsed) { | 
|  | 438             return fUsed; | 
|  | 439         } | 
|  | 440     } else { | 
| 415         swap(); | 441         swap(); | 
| 416         intersectEnd(c2, false, c1, c1Bounds, *this); | 442         intersectEnd(c2, false, c1, c1Bounds, false, *this); | 
| 417         intersectEnd(c2, true, c1, c1Bounds, *this); | 443         intersectEnd(c2, true, c1, c1Bounds, false, *this); | 
| 418         swap(); | 444         swap(); | 
| 419     } | 445     } | 
|  | 446     // if two ends intersect, check middle for coincidence | 
|  | 447     if (fUsed >= 2) { | 
|  | 448         SkASSERT(!selfIntersect); | 
|  | 449         int last = fUsed - 1; | 
|  | 450         double tRange1 = fT[0][last] - fT[0][0]; | 
|  | 451         double tRange2 = fT[1][last] - fT[1][0]; | 
|  | 452         for (int index = 1; index < 5; ++index) { | 
|  | 453             double testT1 = fT[0][0] + tRange1 * index / 5; | 
|  | 454             double testT2 = fT[1][0] + tRange2 * index / 5; | 
|  | 455             SkDPoint testPt1 = c1.ptAtT(testT1); | 
|  | 456             SkDPoint testPt2 = c2.ptAtT(testT2); | 
|  | 457             if (!testPt1.approximatelyEqual(testPt2)) { | 
|  | 458                 goto skipCoincidence; | 
|  | 459             } | 
|  | 460         } | 
|  | 461         if (fUsed > 2) { | 
|  | 462             fPt[1] = fPt[last]; | 
|  | 463             fT[0][1] = fT[0][last]; | 
|  | 464             fT[1][1] = fT[1][last]; | 
|  | 465             fUsed = 2; | 
|  | 466         } | 
|  | 467         fIsCoincident[0] = fIsCoincident[1] = 0x03; | 
|  | 468         return fUsed; | 
|  | 469     } | 
|  | 470 skipCoincidence: | 
|  | 471     ::intersect(c1, 0, 1, c2, 0, 1, 1, *this); | 
| 420     // If an end point and a second point very close to the end is returned, the
      second | 472     // If an end point and a second point very close to the end is returned, the
      second | 
| 421     // point may have been detected because the approximate quads | 473     // point may have been detected because the approximate quads | 
| 422     // intersected at the end and close to it. Verify that the second point is v
     alid. | 474     // intersected at the end and close to it. Verify that the second point is v
     alid. | 
| 423     if (fUsed <= 1 || coincidentUsed()) { | 475     if (fUsed <= 1) { | 
| 424         return fUsed; | 476         return fUsed; | 
| 425     } | 477     } | 
| 426     SkDPoint pt[2]; | 478     SkDPoint pt[2]; | 
| 427     if (closeStart(c1, 0, *this, pt[0]) && closeStart(c2, 1, *this, pt[1]) | 479     if (closeStart(c1, 0, *this, pt[0]) && closeStart(c2, 1, *this, pt[1]) | 
| 428             && pt[0].approximatelyEqual(pt[1])) { | 480             && pt[0].approximatelyEqual(pt[1])) { | 
| 429         removeOne(1); | 481         removeOne(1); | 
| 430     } | 482     } | 
| 431     if (closeEnd(c1, 0, *this, pt[0]) && closeEnd(c2, 1, *this, pt[1]) | 483     if (closeEnd(c1, 0, *this, pt[0]) && closeEnd(c2, 1, *this, pt[1]) | 
| 432             && pt[0].approximatelyEqual(pt[1])) { | 484             && pt[0].approximatelyEqual(pt[1])) { | 
| 433         removeOne(used() - 2); | 485         removeOne(used() - 2); | 
| 434     } | 486     } | 
| 435     // vet the pairs of t values to see if the mid value is also on the curve. I
     f so, mark | 487     // vet the pairs of t values to see if the mid value is also on the curve. I
     f so, mark | 
| 436     // the span as coincident | 488     // the span as coincident | 
| 437     if (fUsed >= 2 && !coincidentUsed()) { | 489     if (fUsed >= 2 && !coincidentUsed()) { | 
| 438         int last = fUsed - 1; | 490         int last = fUsed - 1; | 
| 439         int match = 0; | 491         int match = 0; | 
| 440         for (int index = 0; index < last; ++index) { | 492         for (int index = 0; index < last; ++index) { | 
| 441             double mid1 = (fT[0][index] + fT[0][index + 1]) / 2; | 493             double mid1 = (fT[0][index] + fT[0][index + 1]) / 2; | 
| 442             double mid2 = (fT[1][index] + fT[1][index + 1]) / 2; | 494             double mid2 = (fT[1][index] + fT[1][index + 1]) / 2; | 
| 443             pt[0] = c1.xyAtT(mid1); | 495             pt[0] = c1.ptAtT(mid1); | 
| 444             pt[1] = c2.xyAtT(mid2); | 496             pt[1] = c2.ptAtT(mid2); | 
| 445             if (pt[0].approximatelyEqual(pt[1])) { | 497             if (pt[0].approximatelyEqual(pt[1])) { | 
| 446                 match |= 1 << index; | 498                 match |= 1 << index; | 
| 447             } | 499             } | 
| 448         } | 500         } | 
| 449         if (match) { | 501         if (match) { | 
| 450             if (((match + 1) & match) != 0) { | 502             if (((match + 1) & match) != 0) { | 
| 451                 SkDebugf("%s coincident hole\n", __FUNCTION__); | 503                 SkDebugf("%s coincident hole\n", __FUNCTION__); | 
| 452             } | 504             } | 
| 453             // for now, assume that everything from start to finish is coinciden
     t | 505             // for now, assume that everything from start to finish is coinciden
     t | 
| 454             if (fUsed > 2) { | 506             if (fUsed > 2) { | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 487     } | 539     } | 
| 488     (void) intersect(c, c); | 540     (void) intersect(c, c); | 
| 489     if (used() > 0) { | 541     if (used() > 0) { | 
| 490         SkASSERT(used() == 1); | 542         SkASSERT(used() == 1); | 
| 491         if (fT[0][0] > fT[1][0]) { | 543         if (fT[0][0] > fT[1][0]) { | 
| 492             swapPts(); | 544             swapPts(); | 
| 493         } | 545         } | 
| 494     } | 546     } | 
| 495     return used(); | 547     return used(); | 
| 496 } | 548 } | 
| OLD | NEW | 
|---|