Home | History | Annotate | Download | only in pathops
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 #include "SkIntersections.h"
      8 #include "SkOpAngle.h"
      9 #include "SkOpSegment.h"
     10 #include "SkPathOpsCurve.h"
     11 #include "SkTSort.h"
     12 
     13 #if DEBUG_ANGLE
     14 #include "SkString.h"
     15 #endif
     16 
     17 /* Angles are sorted counterclockwise. The smallest angle has a positive x and the smallest
     18    positive y. The largest angle has a positive x and a zero y. */
     19 
     20 #if DEBUG_ANGLE
     21     static bool CompareResult(SkString* bugOut, int append, bool compare) {
     22         SkDebugf("%s %c %d\n", bugOut->c_str(), compare ? 'T' : 'F', append);
     23         return compare;
     24     }
     25 
     26     #define COMPARE_RESULT(append, compare) CompareResult(&bugOut, append, compare)
     27 #else
     28     #define COMPARE_RESULT(append, compare) compare
     29 #endif
     30 
     31 /*             quarter angle values for sector
     32 
     33 31   x > 0, y == 0              horizontal line (to the right)
     34 0    x > 0, y == epsilon        quad/cubic horizontal tangent eventually going +y
     35 1    x > 0, y > 0, x > y        nearer horizontal angle
     36 2                  x + e == y   quad/cubic 45 going horiz
     37 3    x > 0, y > 0, x == y       45 angle
     38 4                  x == y + e   quad/cubic 45 going vert
     39 5    x > 0, y > 0, x < y        nearer vertical angle
     40 6    x == epsilon, y > 0        quad/cubic vertical tangent eventually going +x
     41 7    x == 0, y > 0              vertical line (to the top)
     42 
     43                                       8  7  6
     44                                  9       |       5
     45                               10         |          4
     46                             11           |            3
     47                           12  \          |           / 2
     48                          13              |              1
     49                         14               |               0
     50                         15 --------------+------------- 31
     51                         16               |              30
     52                          17              |             29
     53                           18  /          |          \ 28
     54                             19           |           27
     55                               20         |         26
     56                                  21      |      25
     57                                      22 23 24
     58 */
     59 
     60 // return true if lh < this < rh
     61 bool SkOpAngle::after(const SkOpAngle* test) const {
     62     const SkOpAngle& lh = *test;
     63     const SkOpAngle& rh = *lh.fNext;
     64     SkASSERT(&lh != &rh);
     65 #if DEBUG_ANGLE
     66     SkString bugOut;
     67     bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     68                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     69                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__,
     70             lh.fSegment->debugID(), lh.debugID(), lh.fSectorStart, lh.fSectorEnd,
     71             lh.fSegment->t(lh.fStart), lh.fSegment->t(lh.fEnd),
     72             fSegment->debugID(), debugID(), fSectorStart, fSectorEnd, fSegment->t(fStart),
     73             fSegment->t(fEnd),
     74             rh.fSegment->debugID(), rh.debugID(), rh.fSectorStart, rh.fSectorEnd,
     75             rh.fSegment->t(rh.fStart), rh.fSegment->t(rh.fEnd));
     76 #endif
     77     if (lh.fComputeSector && !const_cast<SkOpAngle&>(lh).computeSector()) {
     78         return COMPARE_RESULT(1, true);
     79     }
     80     if (fComputeSector && !const_cast<SkOpAngle*>(this)->computeSector()) {
     81         return COMPARE_RESULT(2, true);
     82     }
     83     if (rh.fComputeSector && !const_cast<SkOpAngle&>(rh).computeSector()) {
     84         return COMPARE_RESULT(3, true);
     85     }
     86 #if DEBUG_ANGLE  // reset bugOut with computed sectors
     87     bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     88                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     89                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__,
     90             lh.fSegment->debugID(), lh.debugID(), lh.fSectorStart, lh.fSectorEnd,
     91             lh.fSegment->t(lh.fStart), lh.fSegment->t(lh.fEnd),
     92             fSegment->debugID(), debugID(), fSectorStart, fSectorEnd, fSegment->t(fStart),
     93             fSegment->t(fEnd),
     94             rh.fSegment->debugID(), rh.debugID(), rh.fSectorStart, rh.fSectorEnd,
     95             rh.fSegment->t(rh.fStart), rh.fSegment->t(rh.fEnd));
     96 #endif
     97     bool ltrOverlap = (lh.fSectorMask | rh.fSectorMask) & fSectorMask;
     98     bool lrOverlap = lh.fSectorMask & rh.fSectorMask;
     99     int lrOrder;  // set to -1 if either order works
    100     if (!lrOverlap) {  // no lh/rh sector overlap
    101         if (!ltrOverlap) {  // no lh/this/rh sector overlap
    102             return COMPARE_RESULT(4,  (lh.fSectorEnd > rh.fSectorStart)
    103                     ^ (fSectorStart > lh.fSectorEnd) ^ (fSectorStart > rh.fSectorStart));
    104         }
    105         int lrGap = (rh.fSectorStart - lh.fSectorStart + 32) & 0x1f;
    106         /* A tiny change can move the start +/- 4. The order can only be determined if
    107            lr gap is not 12 to 20 or -12 to -20.
    108                -31 ..-21      1
    109                -20 ..-12     -1
    110                -11 .. -1      0
    111                  0          shouldn't get here
    112                 11 ..  1      1
    113                 12 .. 20     -1
    114                 21 .. 31      0
    115          */
    116         lrOrder = lrGap > 20 ? 0 : lrGap > 11 ? -1 : 1;
    117     } else {
    118         lrOrder = (int) lh.orderable(rh);
    119         if (!ltrOverlap) {
    120             return COMPARE_RESULT(5, !lrOrder);
    121         }
    122     }
    123     int ltOrder;
    124     SkASSERT((lh.fSectorMask & fSectorMask) || (rh.fSectorMask & fSectorMask));
    125     if (lh.fSectorMask & fSectorMask) {
    126         ltOrder = (int) lh.orderable(*this);
    127     } else {
    128         int ltGap = (fSectorStart - lh.fSectorStart + 32) & 0x1f;
    129         ltOrder = ltGap > 20 ? 0 : ltGap > 11 ? -1 : 1;
    130     }
    131     int trOrder;
    132     if (rh.fSectorMask & fSectorMask) {
    133         trOrder = (int) orderable(rh);
    134     } else {
    135         int trGap = (rh.fSectorStart - fSectorStart + 32) & 0x1f;
    136         trOrder = trGap > 20 ? 0 : trGap > 11 ? -1 : 1;
    137     }
    138     if (lrOrder >= 0 && ltOrder >= 0 && trOrder >= 0) {
    139         return COMPARE_RESULT(7, lrOrder ? (ltOrder & trOrder) : (ltOrder | trOrder));
    140     }
    141     SkASSERT(lrOrder >= 0 || ltOrder >= 0 || trOrder >= 0);
    142 // There's not enough information to sort. Get the pairs of angles in opposite planes.
    143 // If an order is < 0, the pair is already in an opposite plane. Check the remaining pairs.
    144     // FIXME : once all variants are understood, rewrite this more simply
    145     if (ltOrder == 0 && lrOrder == 0) {
    146         SkASSERT(trOrder < 0);
    147         // FIXME : once this is verified to work, remove one opposite angle call
    148         SkDEBUGCODE(bool lrOpposite = lh.oppositePlanes(rh));
    149         bool ltOpposite = lh.oppositePlanes(*this);
    150         SkASSERT(lrOpposite != ltOpposite);
    151         return COMPARE_RESULT(8, ltOpposite);
    152     } else if (ltOrder == 1 && trOrder == 0) {
    153         SkASSERT(lrOrder < 0);
    154         SkDEBUGCODE(bool ltOpposite = lh.oppositePlanes(*this));
    155         bool trOpposite = oppositePlanes(rh);
    156         SkASSERT(ltOpposite != trOpposite);
    157         return COMPARE_RESULT(9, trOpposite);
    158     } else if (lrOrder == 1 && trOrder == 1) {
    159         SkASSERT(ltOrder < 0);
    160         SkDEBUGCODE(bool trOpposite = oppositePlanes(rh));
    161         bool lrOpposite = lh.oppositePlanes(rh);
    162         SkASSERT(lrOpposite != trOpposite);
    163         return COMPARE_RESULT(10, lrOpposite);
    164     }
    165     if (lrOrder < 0) {
    166         if (ltOrder < 0) {
    167             return COMPARE_RESULT(11, trOrder);
    168         }
    169         return COMPARE_RESULT(12, ltOrder);
    170     }
    171     return COMPARE_RESULT(13, !lrOrder);
    172 }
    173 
    174 // given a line, see if the opposite curve's convex hull is all on one side
    175 // returns -1=not on one side    0=this CW of test   1=this CCW of test
    176 int SkOpAngle::allOnOneSide(const SkOpAngle& test) const {
    177     SkASSERT(!fIsCurve);
    178     SkASSERT(test.fIsCurve);
    179     const SkDPoint& origin = test.fCurvePart[0];
    180     SkVector line;
    181     if (fSegment->verb() == SkPath::kLine_Verb) {
    182         const SkPoint* linePts = fSegment->pts();
    183         int lineStart = fStart < fEnd ? 0 : 1;
    184         line = linePts[lineStart ^ 1] - linePts[lineStart];
    185     } else {
    186         SkPoint shortPts[2] = { fCurvePart[0].asSkPoint(), fCurvePart[1].asSkPoint() };
    187         line = shortPts[1] - shortPts[0];
    188     }
    189     float crosses[3];
    190     SkPath::Verb testVerb = test.fSegment->verb();
    191     int iMax = SkPathOpsVerbToPoints(testVerb);
    192 //    SkASSERT(origin == test.fCurveHalf[0]);
    193     const SkDCubic& testCurve = test.fCurvePart;
    194 //    do {
    195         for (int index = 1; index <= iMax; ++index) {
    196             float xy1 = (float) (line.fX * (testCurve[index].fY - origin.fY));
    197             float xy2 = (float) (line.fY * (testCurve[index].fX - origin.fX));
    198             crosses[index - 1] = AlmostEqualUlps(xy1, xy2) ? 0 : xy1 - xy2;
    199         }
    200         if (crosses[0] * crosses[1] < 0) {
    201             return -1;
    202         }
    203         if (SkPath::kCubic_Verb == testVerb) {
    204             if (crosses[0] * crosses[2] < 0 || crosses[1] * crosses[2] < 0) {
    205                 return -1;
    206             }
    207         }
    208         if (crosses[0]) {
    209             return crosses[0] < 0;
    210         }
    211         if (crosses[1]) {
    212             return crosses[1] < 0;
    213         }
    214         if (SkPath::kCubic_Verb == testVerb && crosses[2]) {
    215             return crosses[2] < 0;
    216         }
    217     fUnorderable = true;
    218     return -1;
    219 }
    220 
    221 bool SkOpAngle::calcSlop(double x, double y, double rx, double ry, bool* result) const {
    222     double absX = fabs(x);
    223     double absY = fabs(y);
    224     double length = absX < absY ? absX / 2 + absY : absX + absY / 2;
    225     int exponent;
    226     (void) frexp(length, &exponent);
    227     double epsilon = ldexp(FLT_EPSILON, exponent);
    228     SkPath::Verb verb = fSegment->verb();
    229     SkASSERT(verb == SkPath::kQuad_Verb || verb == SkPath::kCubic_Verb);
    230     // FIXME: the quad and cubic factors are made up ; determine actual values
    231     double slop = verb == SkPath::kQuad_Verb ? 4 * epsilon : 512 * epsilon;
    232     double xSlop = slop;
    233     double ySlop = x * y < 0 ? -xSlop : xSlop; // OPTIMIZATION: use copysign / _copysign ?
    234     double x1 = x - xSlop;
    235     double y1 = y + ySlop;
    236     double x_ry1 = x1 * ry;
    237     double rx_y1 = rx * y1;
    238     *result = x_ry1 < rx_y1;
    239     double x2 = x + xSlop;
    240     double y2 = y - ySlop;
    241     double x_ry2 = x2 * ry;
    242     double rx_y2 = rx * y2;
    243     bool less2 = x_ry2 < rx_y2;
    244     return *result == less2;
    245 }
    246 
    247 bool SkOpAngle::checkCrossesZero() const {
    248     int start = SkTMin(fSectorStart, fSectorEnd);
    249     int end = SkTMax(fSectorStart, fSectorEnd);
    250     bool crossesZero = end - start > 16;
    251     return crossesZero;
    252 }
    253 
    254 bool SkOpAngle::checkParallel(const SkOpAngle& rh) const {
    255     SkDVector scratch[2];
    256     const SkDVector* sweep, * tweep;
    257     if (!fUnorderedSweep) {
    258         sweep = fSweep;
    259     } else {
    260         scratch[0] = fCurvePart[1] - fCurvePart[0];
    261         sweep = &scratch[0];
    262     }
    263     if (!rh.fUnorderedSweep) {
    264         tweep = rh.fSweep;
    265     } else {
    266         scratch[1] = rh.fCurvePart[1] - rh.fCurvePart[0];
    267         tweep = &scratch[1];
    268     }
    269     double s0xt0 = sweep->crossCheck(*tweep);
    270     if (tangentsDiverge(rh, s0xt0)) {
    271         return s0xt0 < 0;
    272     }
    273     SkDVector m0 = fSegment->dPtAtT(midT()) - fCurvePart[0];
    274     SkDVector m1 = rh.fSegment->dPtAtT(rh.midT()) - rh.fCurvePart[0];
    275     double m0xm1 = m0.crossCheck(m1);
    276     if (m0xm1 == 0) {
    277         fUnorderable = true;
    278         rh.fUnorderable = true;
    279         return true;
    280     }
    281     return m0xm1 < 0;
    282 }
    283 
    284 // the original angle is too short to get meaningful sector information
    285 // lengthen it until it is long enough to be meaningful or leave it unset if lengthening it
    286 // would cause it to intersect one of the adjacent angles
    287 bool SkOpAngle::computeSector() {
    288     if (fComputedSector) {
    289         return !fUnorderable;
    290     }
    291 //    SkASSERT(fSegment->verb() != SkPath::kLine_Verb && small());
    292     fComputedSector = true;
    293     int step = fStart < fEnd ? 1 : -1;
    294     int limit = step > 0 ? fSegment->count() : -1;
    295     int checkEnd = fEnd;
    296     do {
    297 // advance end
    298         const SkOpSpan& span = fSegment->span(checkEnd);
    299         const SkOpSegment* other = span.fOther;
    300         int oCount = other->count();
    301         for (int oIndex = 0; oIndex < oCount; ++oIndex) {
    302             const SkOpSpan& oSpan = other->span(oIndex);
    303             if (oSpan.fOther != fSegment) {
    304                 continue;
    305             }
    306             if (oSpan.fOtherIndex == checkEnd) {
    307                 continue;
    308             }
    309             if (!approximately_equal(oSpan.fOtherT, span.fT)) {
    310                 continue;
    311             }
    312             goto recomputeSector;
    313         }
    314         checkEnd += step;
    315     } while (checkEnd != limit);
    316 recomputeSector:
    317     if (checkEnd == fEnd || checkEnd - step == fEnd) {
    318         fUnorderable = true;
    319         return false;
    320     }
    321     int saveEnd = fEnd;
    322     fComputedEnd = fEnd = checkEnd - step;
    323     setSpans();
    324     setSector();
    325     fEnd = saveEnd;
    326     return !fUnorderable;
    327 }
    328 
    329 // returns -1 if overlaps   0 if no overlap cw    1 if no overlap ccw
    330 int SkOpAngle::convexHullOverlaps(const SkOpAngle& rh) const {
    331     const SkDVector* sweep = fSweep;
    332     const SkDVector* tweep = rh.fSweep;
    333     double s0xs1 = sweep[0].crossCheck(sweep[1]);
    334     double s0xt0 = sweep[0].crossCheck(tweep[0]);
    335     double s1xt0 = sweep[1].crossCheck(tweep[0]);
    336     bool tBetweenS = s0xs1 > 0 ? s0xt0 > 0 && s1xt0 < 0 : s0xt0 < 0 && s1xt0 > 0;
    337     double s0xt1 = sweep[0].crossCheck(tweep[1]);
    338     double s1xt1 = sweep[1].crossCheck(tweep[1]);
    339     tBetweenS |= s0xs1 > 0 ? s0xt1 > 0 && s1xt1 < 0 : s0xt1 < 0 && s1xt1 > 0;
    340     double t0xt1 = tweep[0].crossCheck(tweep[1]);
    341     if (tBetweenS) {
    342         return -1;
    343     }
    344     if ((s0xt0 == 0 && s1xt1 == 0) || (s1xt0 == 0 && s0xt1 == 0)) {  // s0 to s1 equals t0 to t1
    345         return -1;
    346     }
    347     bool sBetweenT = t0xt1 > 0 ? s0xt0 < 0 && s0xt1 > 0 : s0xt0 > 0 && s0xt1 < 0;
    348     sBetweenT |= t0xt1 > 0 ? s1xt0 < 0 && s1xt1 > 0 : s1xt0 > 0 && s1xt1 < 0;
    349     if (sBetweenT) {
    350         return -1;
    351     }
    352     // if all of the sweeps are in the same half plane, then the order of any pair is enough
    353     if (s0xt0 >= 0 && s0xt1 >= 0 && s1xt0 >= 0 && s1xt1 >= 0) {
    354         return 0;
    355     }
    356     if (s0xt0 <= 0 && s0xt1 <= 0 && s1xt0 <= 0 && s1xt1 <= 0) {
    357         return 1;
    358     }
    359     // if the outside sweeps are greater than 180 degress:
    360         // first assume the inital tangents are the ordering
    361         // if the midpoint direction matches the inital order, that is enough
    362     SkDVector m0 = fSegment->dPtAtT(midT()) - fCurvePart[0];
    363     SkDVector m1 = rh.fSegment->dPtAtT(rh.midT()) - rh.fCurvePart[0];
    364     double m0xm1 = m0.crossCheck(m1);
    365     if (s0xt0 > 0 && m0xm1 > 0) {
    366         return 0;
    367     }
    368     if (s0xt0 < 0 && m0xm1 < 0) {
    369         return 1;
    370     }
    371     if (tangentsDiverge(rh, s0xt0)) {
    372         return s0xt0 < 0;
    373     }
    374     return m0xm1 < 0;
    375 }
    376 
    377 // OPTIMIZATION: longest can all be either lazily computed here or precomputed in setup
    378 double SkOpAngle::distEndRatio(double dist) const {
    379     double longest = 0;
    380     const SkOpSegment& segment = *this->segment();
    381     int ptCount = SkPathOpsVerbToPoints(segment.verb());
    382     const SkPoint* pts = segment.pts();
    383     for (int idx1 = 0; idx1 <= ptCount - 1; ++idx1) {
    384         for (int idx2 = idx1 + 1; idx2 <= ptCount; ++idx2) {
    385             if (idx1 == idx2) {
    386                 continue;
    387             }
    388             SkDVector v;
    389             v.set(pts[idx2] - pts[idx1]);
    390             double lenSq = v.lengthSquared();
    391             longest = SkTMax(longest, lenSq);
    392         }
    393     }
    394     return sqrt(longest) / dist;
    395 }
    396 
    397 bool SkOpAngle::endsIntersect(const SkOpAngle& rh) const {
    398     SkPath::Verb lVerb = fSegment->verb();
    399     SkPath::Verb rVerb = rh.fSegment->verb();
    400     int lPts = SkPathOpsVerbToPoints(lVerb);
    401     int rPts = SkPathOpsVerbToPoints(rVerb);
    402     SkDLine rays[] = {{{fCurvePart[0], rh.fCurvePart[rPts]}},
    403             {{fCurvePart[0], fCurvePart[lPts]}}};
    404     if (rays[0][1] == rays[1][1]) {
    405         return checkParallel(rh);
    406     }
    407     double smallTs[2] = {-1, -1};
    408     bool limited[2] = {false, false};
    409     for (int index = 0; index < 2; ++index) {
    410         const SkOpSegment& segment = index ? *rh.fSegment : *fSegment;
    411         SkIntersections i;
    412         (*CurveIntersectRay[index ? rPts : lPts])(segment.pts(), rays[index], &i);
    413 //      SkASSERT(i.used() >= 1);
    414 //        if (i.used() <= 1) {
    415 //            continue;
    416 //        }
    417         double tStart = segment.t(index ? rh.fStart : fStart);
    418         double tEnd = segment.t(index ? rh.fComputedEnd : fComputedEnd);
    419         bool testAscends = index ? rh.fStart < rh.fComputedEnd : fStart < fComputedEnd;
    420         double t = testAscends ? 0 : 1;
    421         for (int idx2 = 0; idx2 < i.used(); ++idx2) {
    422             double testT = i[0][idx2];
    423             if (!approximately_between_orderable(tStart, testT, tEnd)) {
    424                 continue;
    425             }
    426             if (approximately_equal_orderable(tStart, testT)) {
    427                 continue;
    428             }
    429             smallTs[index] = t = testAscends ? SkTMax(t, testT) : SkTMin(t, testT);
    430             limited[index] = approximately_equal_orderable(t, tEnd);
    431         }
    432     }
    433 #if 0
    434     if (smallTs[0] < 0 && smallTs[1] < 0) {  // if neither ray intersects, do endpoint sort
    435         double m0xm1 = 0;
    436         if (lVerb == SkPath::kLine_Verb) {
    437             SkASSERT(rVerb != SkPath::kLine_Verb);
    438             SkDVector m0 = rays[1][1] - fCurvePart[0];
    439             SkDPoint endPt;
    440             endPt.set(rh.fSegment->pts()[rh.fStart < rh.fEnd ? rPts : 0]);
    441             SkDVector m1 = endPt - fCurvePart[0];
    442             m0xm1 = m0.crossCheck(m1);
    443         }
    444         if (rVerb == SkPath::kLine_Verb) {
    445             SkDPoint endPt;
    446             endPt.set(fSegment->pts()[fStart < fEnd ? lPts : 0]);
    447             SkDVector m0 = endPt - fCurvePart[0];
    448             SkDVector m1 = rays[0][1] - fCurvePart[0];
    449             m0xm1 = m0.crossCheck(m1);
    450         }
    451         if (m0xm1 != 0) {
    452             return m0xm1 < 0;
    453         }
    454     }
    455 #endif
    456     bool sRayLonger = false;
    457     SkDVector sCept = {0, 0};
    458     double sCeptT = -1;
    459     int sIndex = -1;
    460     bool useIntersect = false;
    461     for (int index = 0; index < 2; ++index) {
    462         if (smallTs[index] < 0) {
    463             continue;
    464         }
    465         const SkOpSegment& segment = index ? *rh.fSegment : *fSegment;
    466         const SkDPoint& dPt = segment.dPtAtT(smallTs[index]);
    467         SkDVector cept = dPt - rays[index][0];
    468         // If this point is on the curve, it should have been detected earlier by ordinary
    469         // curve intersection. This may be hard to determine in general, but for lines,
    470         // the point could be close to or equal to its end, but shouldn't be near the start.
    471         if ((index ? lPts : rPts) == 1) {
    472             SkDVector total = rays[index][1] - rays[index][0];
    473             if (cept.lengthSquared() * 2 < total.lengthSquared()) {
    474                 continue;
    475             }
    476         }
    477         SkDVector end = rays[index][1] - rays[index][0];
    478         if (cept.fX * end.fX < 0 || cept.fY * end.fY < 0) {
    479             continue;
    480         }
    481         double rayDist = cept.length();
    482         double endDist = end.length();
    483         bool rayLonger = rayDist > endDist;
    484         if (limited[0] && limited[1] && rayLonger) {
    485             useIntersect = true;
    486             sRayLonger = rayLonger;
    487             sCept = cept;
    488             sCeptT = smallTs[index];
    489             sIndex = index;
    490             break;
    491         }
    492         double delta = fabs(rayDist - endDist);
    493         double minX, minY, maxX, maxY;
    494         minX = minY = SK_ScalarInfinity;
    495         maxX = maxY = -SK_ScalarInfinity;
    496         const SkDCubic& curve = index ? rh.fCurvePart : fCurvePart;
    497         int ptCount = index ? rPts : lPts;
    498         for (int idx2 = 0; idx2 <= ptCount; ++idx2) {
    499             minX = SkTMin(minX, curve[idx2].fX);
    500             minY = SkTMin(minY, curve[idx2].fY);
    501             maxX = SkTMax(maxX, curve[idx2].fX);
    502             maxY = SkTMax(maxY, curve[idx2].fY);
    503         }
    504         double maxWidth = SkTMax(maxX - minX, maxY - minY);
    505         delta /= maxWidth;
    506         if (delta > 1e-4 && (useIntersect ^= true)) {  // FIXME: move this magic number
    507             sRayLonger = rayLonger;
    508             sCept = cept;
    509             sCeptT = smallTs[index];
    510             sIndex = index;
    511         }
    512     }
    513     if (useIntersect) {
    514         const SkDCubic& curve = sIndex ? rh.fCurvePart : fCurvePart;
    515         const SkOpSegment& segment = sIndex ? *rh.fSegment : *fSegment;
    516         double tStart = segment.t(sIndex ? rh.fStart : fStart);
    517         SkDVector mid = segment.dPtAtT(tStart + (sCeptT - tStart) / 2) - curve[0];
    518         double septDir = mid.crossCheck(sCept);
    519         if (!septDir) {
    520             return checkParallel(rh);
    521         }
    522         return sRayLonger ^ (sIndex == 0) ^ (septDir < 0);
    523     } else {
    524         return checkParallel(rh);
    525     }
    526 }
    527 
    528 // Most of the time, the first one can be found trivially by detecting the smallest sector value.
    529 // If all angles have the same sector value, actual sorting is required.
    530 const SkOpAngle* SkOpAngle::findFirst() const {
    531     const SkOpAngle* best = this;
    532     int bestStart = SkTMin(fSectorStart, fSectorEnd);
    533     const SkOpAngle* angle = this;
    534     while ((angle = angle->fNext) != this) {
    535         int angleEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd);
    536         if (angleEnd < bestStart) {
    537             return angle;    // we wrapped around
    538         }
    539         int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd);
    540         if (bestStart > angleStart) {
    541             best = angle;
    542             bestStart = angleStart;
    543         }
    544     }
    545     // back up to the first possible angle
    546     const SkOpAngle* firstBest = best;
    547     angle = best;
    548     int bestEnd = SkTMax(best->fSectorStart, best->fSectorEnd);
    549     while ((angle = angle->previous()) != firstBest) {
    550         if (angle->fStop) {
    551             break;
    552         }
    553         int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd);
    554         // angles that are smaller by one aren't necessary better, since the larger may be a line
    555         // and the smaller may be a curve that curls to the other side of the line.
    556         if (bestEnd + 1 < angleStart) {
    557             return best;
    558         }
    559         best = angle;
    560         bestEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd);
    561     }
    562     // in the case where all angles are nearly in the same sector, check the order to find the best
    563     firstBest = best;
    564     angle = best;
    565     do {
    566         angle = angle->fNext;
    567         if (angle->fStop) {
    568             return firstBest;
    569         }
    570         bool orderable = best->orderable(*angle);  // note: may return an unorderable angle
    571         if (orderable == 0) {
    572             return angle;
    573         }
    574         best = angle;
    575     } while (angle != firstBest);
    576     // if the angles are equally ordered, fall back on the initial tangent
    577     bool foundBelow = false;
    578     while ((angle = angle->fNext)) {
    579         SkDVector scratch[2];
    580         const SkDVector* sweep;
    581         if (!angle->fUnorderedSweep) {
    582             sweep = angle->fSweep;
    583         } else {
    584             scratch[0] = angle->fCurvePart[1] - angle->fCurvePart[0];
    585             sweep = &scratch[0];
    586         }
    587         bool isAbove = sweep->fY <= 0;
    588         if (isAbove && foundBelow) {
    589             return angle;
    590         }
    591         foundBelow |= !isAbove;
    592         if (angle == firstBest) {
    593             return NULL; // should not loop around
    594         }
    595     }
    596     SkASSERT(0);  // should never get here
    597     return NULL;
    598 }
    599 
    600 /*      y<0 y==0 y>0  x<0 x==0 x>0 xy<0 xy==0 xy>0
    601     0    x                      x               x
    602     1    x                      x          x
    603     2    x                      x    x
    604     3    x                  x        x
    605     4    x             x             x
    606     5    x             x                   x
    607     6    x             x                        x
    608     7         x        x                        x
    609     8             x    x                        x
    610     9             x    x                   x
    611     10            x    x             x
    612     11            x         x        x
    613     12            x             x    x
    614     13            x             x          x
    615     14            x             x               x
    616     15        x                 x               x
    617 */
    618 int SkOpAngle::findSector(SkPath::Verb verb, double x, double y) const {
    619     double absX = fabs(x);
    620     double absY = fabs(y);
    621     double xy = SkPath::kLine_Verb == verb || !AlmostEqualUlps(absX, absY) ? absX - absY : 0;
    622     // If there are four quadrants and eight octants, and since the Latin for sixteen is sedecim,
    623     // one could coin the term sedecimant for a space divided into 16 sections.
    624    // http://english.stackexchange.com/questions/133688/word-for-something-partitioned-into-16-parts
    625     static const int sedecimant[3][3][3] = {
    626     //       y<0           y==0           y>0
    627     //   x<0 x==0 x>0  x<0 x==0 x>0  x<0 x==0 x>0
    628         {{ 4,  3,  2}, { 7, -1, 15}, {10, 11, 12}},  // abs(x) <  abs(y)
    629         {{ 5, -1,  1}, {-1, -1, -1}, { 9, -1, 13}},  // abs(x) == abs(y)
    630         {{ 6,  3,  0}, { 7, -1, 15}, { 8, 11, 14}},  // abs(x) >  abs(y)
    631     };
    632     int sector = sedecimant[(xy >= 0) + (xy > 0)][(y >= 0) + (y > 0)][(x >= 0) + (x > 0)] * 2 + 1;
    633 //    SkASSERT(SkPath::kLine_Verb == verb || sector >= 0);
    634     return sector;
    635 }
    636 
    637 // OPTIMIZE: if this loops to only one other angle, after first compare fails, insert on other side
    638 // OPTIMIZE: return where insertion succeeded. Then, start next insertion on opposite side
    639 void SkOpAngle::insert(SkOpAngle* angle) {
    640     if (angle->fNext) {
    641         if (loopCount() >= angle->loopCount()) {
    642             if (!merge(angle)) {
    643                 return;
    644             }
    645         } else if (fNext) {
    646             if (!angle->merge(this)) {
    647                 return;
    648             }
    649         } else {
    650             angle->insert(this);
    651         }
    652         return;
    653     }
    654     bool singleton = NULL == fNext;
    655     if (singleton) {
    656         fNext = this;
    657     }
    658     SkOpAngle* next = fNext;
    659     if (next->fNext == this) {
    660         if (angle->overlap(*this)) {
    661             return;
    662         }
    663         if (singleton || angle->after(this)) {
    664             this->fNext = angle;
    665             angle->fNext = next;
    666         } else {
    667             next->fNext = angle;
    668             angle->fNext = this;
    669         }
    670         debugValidateNext();
    671         return;
    672     }
    673     SkOpAngle* last = this;
    674     do {
    675         SkASSERT(last->fNext == next);
    676         if (angle->overlap(*last) || angle->overlap(*next)) {
    677             return;
    678         }
    679         if (angle->after(last)) {
    680             last->fNext = angle;
    681             angle->fNext = next;
    682             debugValidateNext();
    683             return;
    684         }
    685         last = next;
    686         next = next->fNext;
    687         if (last == this && next->fUnorderable) {
    688             fUnorderable = true;
    689             return;
    690         }
    691         SkASSERT(last != this);
    692     } while (true);
    693 }
    694 
    695 bool SkOpAngle::isHorizontal() const {
    696     return !fIsCurve && fSweep[0].fY == 0;
    697 }
    698 
    699 SkOpSpan* SkOpAngle::lastMarked() const {
    700     if (fLastMarked) {
    701         if (fLastMarked->fChased) {
    702             return NULL;
    703         }
    704         fLastMarked->fChased = true;
    705     }
    706     return fLastMarked;
    707 }
    708 
    709 bool SkOpAngle::loopContains(const SkOpAngle& test) const {
    710     if (!fNext) {
    711         return false;
    712     }
    713     const SkOpAngle* first = this;
    714     const SkOpAngle* loop = this;
    715     const SkOpSegment* tSegment = test.fSegment;
    716     double tStart = tSegment->span(test.fStart).fT;
    717     double tEnd = tSegment->span(test.fEnd).fT;
    718     do {
    719         const SkOpSegment* lSegment = loop->fSegment;
    720         // FIXME : use precisely_equal ? or compare points exactly ?
    721         if (lSegment != tSegment) {
    722             continue;
    723         }
    724         double lStart = lSegment->span(loop->fStart).fT;
    725         if (lStart != tEnd) {
    726             continue;
    727         }
    728         double lEnd = lSegment->span(loop->fEnd).fT;
    729         if (lEnd == tStart) {
    730             return true;
    731         }
    732     } while ((loop = loop->fNext) != first);
    733     return false;
    734 }
    735 
    736 int SkOpAngle::loopCount() const {
    737     int count = 0;
    738     const SkOpAngle* first = this;
    739     const SkOpAngle* next = this;
    740     do {
    741         next = next->fNext;
    742         ++count;
    743     } while (next && next != first);
    744     return count;
    745 }
    746 
    747 // OPTIMIZATION: can this be done better in after when angles are sorted?
    748 void SkOpAngle::markStops() {
    749     SkOpAngle* angle = this;
    750     int lastEnd = SkTMax(fSectorStart, fSectorEnd);
    751     do {
    752         angle = angle->fNext;
    753         int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd);
    754         // angles that are smaller by one aren't necessary better, since the larger may be a line
    755         // and the smaller may be a curve that curls to the other side of the line.
    756         if (lastEnd + 1 < angleStart) {
    757             angle->fStop = true;
    758         }
    759         lastEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd);
    760     } while (angle != this);
    761 }
    762 
    763 bool SkOpAngle::merge(SkOpAngle* angle) {
    764     SkASSERT(fNext);
    765     SkASSERT(angle->fNext);
    766     SkOpAngle* working = angle;
    767     do {
    768         if (this == working) {
    769             return false;
    770         }
    771         working = working->fNext;
    772     } while (working != angle);
    773     do {
    774         SkOpAngle* next = working->fNext;
    775         working->fNext = NULL;
    776         insert(working);
    777         working = next;
    778     } while (working != angle);
    779     // it's likely that a pair of the angles are unorderable
    780 #if DEBUG_ANGLE
    781     SkOpAngle* last = angle;
    782     working = angle->fNext;
    783     do {
    784         SkASSERT(last->fNext == working);
    785         last->fNext = working->fNext;
    786         SkASSERT(working->after(last));
    787         last->fNext = working;
    788         last = working;
    789         working = working->fNext;
    790     } while (last != angle);
    791 #endif
    792     debugValidateNext();
    793     return true;
    794 }
    795 
    796 double SkOpAngle::midT() const {
    797     return (fSegment->t(fStart) + fSegment->t(fEnd)) / 2;
    798 }
    799 
    800 bool SkOpAngle::oppositePlanes(const SkOpAngle& rh) const {
    801     int startSpan = abs(rh.fSectorStart - fSectorStart);
    802     return startSpan >= 8;
    803 }
    804 
    805 bool SkOpAngle::orderable(const SkOpAngle& rh) const {
    806     int result;
    807     if (!fIsCurve) {
    808         if (!rh.fIsCurve) {
    809             double leftX = fTangentHalf.dx();
    810             double leftY = fTangentHalf.dy();
    811             double rightX = rh.fTangentHalf.dx();
    812             double rightY = rh.fTangentHalf.dy();
    813             double x_ry = leftX * rightY;
    814             double rx_y = rightX * leftY;
    815             if (x_ry == rx_y) {
    816                 if (leftX * rightX < 0 || leftY * rightY < 0) {
    817                     return true;  // exactly 180 degrees apart
    818                 }
    819                 goto unorderable;
    820             }
    821             SkASSERT(x_ry != rx_y); // indicates an undetected coincidence -- worth finding earlier
    822             return x_ry < rx_y;
    823         }
    824         if ((result = allOnOneSide(rh)) >= 0) {
    825             return result;
    826         }
    827         if (fUnorderable || approximately_zero(rh.fSide)) {
    828             goto unorderable;
    829         }
    830     } else if (!rh.fIsCurve) {
    831         if ((result = rh.allOnOneSide(*this)) >= 0) {
    832             return !result;
    833         }
    834         if (rh.fUnorderable || approximately_zero(fSide)) {
    835             goto unorderable;
    836         }
    837     }
    838     if ((result = convexHullOverlaps(rh)) >= 0) {
    839         return result;
    840     }
    841     return endsIntersect(rh);
    842 unorderable:
    843     fUnorderable = true;
    844     rh.fUnorderable = true;
    845     return true;
    846 }
    847 
    848 bool SkOpAngle::overlap(const SkOpAngle& other) const {
    849     int min = SkTMin(fStart, fEnd);
    850     const SkOpSpan& span = fSegment->span(min);
    851     const SkOpSegment* oSeg = other.fSegment;
    852     int oMin = SkTMin(other.fStart, other.fEnd);
    853     const SkOpSpan& oSpan = oSeg->span(oMin);
    854     if (!span.fSmall && !oSpan.fSmall) {
    855         return false;
    856     }
    857     if (fSegment->span(fStart).fPt != oSeg->span(other.fStart).fPt) {
    858         return false;
    859     }
    860     // see if small span is contained by opposite span
    861     return span.fSmall ? oSeg->containsPt(fSegment->span(fEnd).fPt, other.fEnd, other.fStart)
    862             : fSegment->containsPt(oSeg->span(other.fEnd).fPt, fEnd, fStart);
    863 }
    864 
    865 // OPTIMIZE: if this shows up in a profile, add a previous pointer
    866 // as is, this should be rarely called
    867 SkOpAngle* SkOpAngle::previous() const {
    868     SkOpAngle* last = fNext;
    869     do {
    870         SkOpAngle* next = last->fNext;
    871         if (next == this) {
    872             return last;
    873         }
    874         last = next;
    875     } while (true);
    876 }
    877 
    878 void SkOpAngle::set(const SkOpSegment* segment, int start, int end) {
    879     fSegment = segment;
    880     fStart = start;
    881     fComputedEnd = fEnd = end;
    882     fNext = NULL;
    883     fComputeSector = fComputedSector = false;
    884     fStop = false;
    885     setSpans();
    886     setSector();
    887 }
    888 
    889 void SkOpAngle::setCurveHullSweep() {
    890     fUnorderedSweep = false;
    891     fSweep[0] = fCurvePart[1] - fCurvePart[0];
    892     if (SkPath::kLine_Verb == fSegment->verb()) {
    893         fSweep[1] = fSweep[0];
    894         return;
    895     }
    896     fSweep[1] = fCurvePart[2] - fCurvePart[0];
    897     if (SkPath::kCubic_Verb != fSegment->verb()) {
    898         if (!fSweep[0].fX && !fSweep[0].fY) {
    899             fSweep[0] = fSweep[1];
    900         }
    901         return;
    902     }
    903     SkDVector thirdSweep = fCurvePart[3] - fCurvePart[0];
    904     if (fSweep[0].fX == 0 && fSweep[0].fY == 0) {
    905         fSweep[0] = fSweep[1];
    906         fSweep[1] = thirdSweep;
    907         if (fSweep[0].fX == 0 && fSweep[0].fY == 0) {
    908             fSweep[0] = fSweep[1];
    909             fCurvePart[1] = fCurvePart[3];
    910             fIsCurve = false;
    911         }
    912         return;
    913     }
    914     double s1x3 = fSweep[0].crossCheck(thirdSweep);
    915     double s3x2 = thirdSweep.crossCheck(fSweep[1]);
    916     if (s1x3 * s3x2 >= 0) {  // if third vector is on or between first two vectors
    917         return;
    918     }
    919     double s2x1 = fSweep[1].crossCheck(fSweep[0]);
    920     // FIXME: If the sweep of the cubic is greater than 180 degrees, we're in trouble
    921     // probably such wide sweeps should be artificially subdivided earlier so that never happens
    922     SkASSERT(s1x3 * s2x1 < 0 || s1x3 * s3x2 < 0);
    923     if (s3x2 * s2x1 < 0) {
    924         SkASSERT(s2x1 * s1x3 > 0);
    925         fSweep[0] = fSweep[1];
    926         fUnorderedSweep = true;
    927     }
    928     fSweep[1] = thirdSweep;
    929 }
    930 
    931 void SkOpAngle::setSector() {
    932     SkPath::Verb verb = fSegment->verb();
    933     if (SkPath::kLine_Verb != verb && small()) {
    934         goto deferTilLater;
    935     }
    936     fSectorStart = findSector(verb, fSweep[0].fX, fSweep[0].fY);
    937     if (fSectorStart < 0) {
    938         goto deferTilLater;
    939     }
    940     if (!fIsCurve) {  // if it's a line or line-like, note that both sectors are the same
    941         SkASSERT(fSectorStart >= 0);
    942         fSectorEnd = fSectorStart;
    943         fSectorMask = 1 << fSectorStart;
    944         return;
    945     }
    946     SkASSERT(SkPath::kLine_Verb != verb);
    947     fSectorEnd = findSector(verb, fSweep[1].fX, fSweep[1].fY);
    948     if (fSectorEnd < 0) {
    949 deferTilLater:
    950         fSectorStart = fSectorEnd = -1;
    951         fSectorMask = 0;
    952         fComputeSector = true;  // can't determine sector until segment length can be found
    953         return;
    954     }
    955     if (fSectorEnd == fSectorStart) {
    956         SkASSERT((fSectorStart & 3) != 3);  // if the sector has no span, it can't be an exact angle
    957         fSectorMask = 1 << fSectorStart;
    958         return;
    959     }
    960     bool crossesZero = checkCrossesZero();
    961     int start = SkTMin(fSectorStart, fSectorEnd);
    962     bool curveBendsCCW = (fSectorStart == start) ^ crossesZero;
    963     // bump the start and end of the sector span if they are on exact compass points
    964     if ((fSectorStart & 3) == 3) {
    965         fSectorStart = (fSectorStart + (curveBendsCCW ? 1 : 31)) & 0x1f;
    966     }
    967     if ((fSectorEnd & 3) == 3) {
    968         fSectorEnd = (fSectorEnd + (curveBendsCCW ? 31 : 1)) & 0x1f;
    969     }
    970     crossesZero = checkCrossesZero();
    971     start = SkTMin(fSectorStart, fSectorEnd);
    972     int end = SkTMax(fSectorStart, fSectorEnd);
    973     if (!crossesZero) {
    974         fSectorMask = (unsigned) -1 >> (31 - end + start) << start;
    975     } else {
    976         fSectorMask = (unsigned) -1 >> (31 - start) | (-1 << end);
    977     }
    978 }
    979 
    980 void SkOpAngle::setSpans() {
    981     fUnorderable = fSegment->isTiny(this);
    982     fLastMarked = NULL;
    983     const SkPoint* pts = fSegment->pts();
    984     SkDEBUGCODE(fCurvePart[2].fX = fCurvePart[2].fY = fCurvePart[3].fX = fCurvePart[3].fY
    985             = SK_ScalarNaN);
    986     fSegment->subDivide(fStart, fEnd, &fCurvePart);
    987     setCurveHullSweep();
    988     const SkPath::Verb verb = fSegment->verb();
    989     if (verb != SkPath::kLine_Verb
    990             && !(fIsCurve = fSweep[0].crossCheck(fSweep[1]) != 0)) {
    991         SkDLine lineHalf;
    992         lineHalf[0].set(fCurvePart[0].asSkPoint());
    993         lineHalf[1].set(fCurvePart[SkPathOpsVerbToPoints(verb)].asSkPoint());
    994         fTangentHalf.lineEndPoints(lineHalf);
    995         fSide = 0;
    996     }
    997     switch (verb) {
    998     case SkPath::kLine_Verb: {
    999         SkASSERT(fStart != fEnd);
   1000         const SkPoint& cP1 = pts[fStart < fEnd];
   1001         SkDLine lineHalf;
   1002         lineHalf[0].set(fSegment->span(fStart).fPt);
   1003         lineHalf[1].set(cP1);
   1004         fTangentHalf.lineEndPoints(lineHalf);
   1005         fSide = 0;
   1006         fIsCurve = false;
   1007         } return;
   1008     case SkPath::kQuad_Verb: {
   1009         SkLineParameters tangentPart;
   1010         SkDQuad& quad2 = *SkTCast<SkDQuad*>(&fCurvePart);
   1011         (void) tangentPart.quadEndPoints(quad2);
   1012         fSide = -tangentPart.pointDistance(fCurvePart[2]);  // not normalized -- compare sign only
   1013         } break;
   1014     case SkPath::kCubic_Verb: {
   1015         SkLineParameters tangentPart;
   1016         (void) tangentPart.cubicPart(fCurvePart);
   1017         fSide = -tangentPart.pointDistance(fCurvePart[3]);
   1018         double testTs[4];
   1019         // OPTIMIZATION: keep inflections precomputed with cubic segment?
   1020         int testCount = SkDCubic::FindInflections(pts, testTs);
   1021         double startT = fSegment->t(fStart);
   1022         double endT = fSegment->t(fEnd);
   1023         double limitT = endT;
   1024         int index;
   1025         for (index = 0; index < testCount; ++index) {
   1026             if (!::between(startT, testTs[index], limitT)) {
   1027                 testTs[index] = -1;
   1028             }
   1029         }
   1030         testTs[testCount++] = startT;
   1031         testTs[testCount++] = endT;
   1032         SkTQSort<double>(testTs, &testTs[testCount - 1]);
   1033         double bestSide = 0;
   1034         int testCases = (testCount << 1) - 1;
   1035         index = 0;
   1036         while (testTs[index] < 0) {
   1037             ++index;
   1038         }
   1039         index <<= 1;
   1040         for (; index < testCases; ++index) {
   1041             int testIndex = index >> 1;
   1042             double testT = testTs[testIndex];
   1043             if (index & 1) {
   1044                 testT = (testT + testTs[testIndex + 1]) / 2;
   1045             }
   1046             // OPTIMIZE: could avoid call for t == startT, endT
   1047             SkDPoint pt = dcubic_xy_at_t(pts, testT);
   1048             SkLineParameters tangentPart;
   1049             tangentPart.cubicEndPoints(fCurvePart);
   1050             double testSide = tangentPart.pointDistance(pt);
   1051             if (fabs(bestSide) < fabs(testSide)) {
   1052                 bestSide = testSide;
   1053             }
   1054         }
   1055         fSide = -bestSide;  // compare sign only
   1056         } break;
   1057     default:
   1058         SkASSERT(0);
   1059     }
   1060 }
   1061 
   1062 bool SkOpAngle::small() const {
   1063     int min = SkMin32(fStart, fEnd);
   1064     int max = SkMax32(fStart, fEnd);
   1065     for (int index = min; index < max; ++index) {
   1066         const SkOpSpan& mSpan = fSegment->span(index);
   1067         if (!mSpan.fSmall) {
   1068             return false;
   1069         }
   1070     }
   1071     return true;
   1072 }
   1073 
   1074 bool SkOpAngle::tangentsDiverge(const SkOpAngle& rh, double s0xt0) const {
   1075     if (s0xt0 == 0) {
   1076         return false;
   1077     }
   1078     // if the ctrl tangents are not nearly parallel, use them
   1079     // solve for opposite direction displacement scale factor == m
   1080     // initial dir = v1.cross(v2) == v2.x * v1.y - v2.y * v1.x
   1081     // displacement of q1[1] : dq1 = { -m * v1.y, m * v1.x } + q1[1]
   1082     // straight angle when : v2.x * (dq1.y - q1[0].y) == v2.y * (dq1.x - q1[0].x)
   1083     //                       v2.x * (m * v1.x + v1.y) == v2.y * (-m * v1.y + v1.x)
   1084     // - m * (v2.x * v1.x + v2.y * v1.y) == v2.x * v1.y - v2.y * v1.x
   1085     // m = (v2.y * v1.x - v2.x * v1.y) / (v2.x * v1.x + v2.y * v1.y)
   1086     // m = v1.cross(v2) / v1.dot(v2)
   1087     const SkDVector* sweep = fSweep;
   1088     const SkDVector* tweep = rh.fSweep;
   1089     double s0dt0 = sweep[0].dot(tweep[0]);
   1090     if (!s0dt0) {
   1091         return true;
   1092     }
   1093     SkASSERT(s0dt0 != 0);
   1094     double m = s0xt0 / s0dt0;
   1095     double sDist = sweep[0].length() * m;
   1096     double tDist = tweep[0].length() * m;
   1097     bool useS = fabs(sDist) < fabs(tDist);
   1098     double mFactor = fabs(useS ? distEndRatio(sDist) : rh.distEndRatio(tDist));
   1099     return mFactor < 5000;  // empirically found limit
   1100 }
   1101 
   1102 SkOpAngleSet::SkOpAngleSet()
   1103     : fAngles(NULL)
   1104 #if DEBUG_ANGLE
   1105     , fCount(0)
   1106 #endif
   1107 {
   1108 }
   1109 
   1110 SkOpAngleSet::~SkOpAngleSet() {
   1111     SkDELETE(fAngles);
   1112 }
   1113 
   1114 SkOpAngle& SkOpAngleSet::push_back() {
   1115     if (!fAngles) {
   1116         fAngles = SkNEW_ARGS(SkChunkAlloc, (2));
   1117     }
   1118     void* ptr = fAngles->allocThrow(sizeof(SkOpAngle));
   1119     SkOpAngle* angle = (SkOpAngle*) ptr;
   1120 #if DEBUG_ANGLE
   1121     angle->setID(++fCount);
   1122 #endif
   1123     return *angle;
   1124 }
   1125 
   1126 void SkOpAngleSet::reset() {
   1127     if (fAngles) {
   1128         fAngles->reset();
   1129     }
   1130 }
   1131