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 "SkOpAngle.h"
      8 #include "SkOpSegment.h"
      9 #include "SkPathOpsCurve.h"
     10 #include "SkTSort.h"
     11 
     12 /* Angles are sorted counterclockwise. The smallest angle has a positive x and the smallest
     13    positive y. The largest angle has a positive x and a zero y. */
     14 
     15 #if DEBUG_ANGLE
     16     static bool CompareResult(const char* func, SkString* bugOut, SkString* bugPart, int append,
     17              bool compare) {
     18         SkDebugf("%s %c %d\n", bugOut->c_str(), compare ? 'T' : 'F', append);
     19         SkDebugf("%sPart %s\n", func, bugPart[0].c_str());
     20         SkDebugf("%sPart %s\n", func, bugPart[1].c_str());
     21         SkDebugf("%sPart %s\n", func, bugPart[2].c_str());
     22         return compare;
     23     }
     24 
     25     #define COMPARE_RESULT(append, compare) CompareResult(__FUNCTION__, &bugOut, bugPart, append, \
     26             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(SkOpAngle* test) {
     62     SkOpAngle* lh = test;
     63     SkOpAngle* rh = lh->fNext;
     64     SkASSERT(lh != rh);
     65     fPart.fCurve = fOriginalCurvePart;
     66     lh->fPart.fCurve = lh->fOriginalCurvePart;
     67     lh->fPart.fCurve.offset(lh->segment()->verb(), fPart.fCurve[0] - lh->fPart.fCurve[0]);
     68     rh->fPart.fCurve = rh->fOriginalCurvePart;
     69     rh->fPart.fCurve.offset(rh->segment()->verb(), fPart.fCurve[0] - rh->fPart.fCurve[0]);
     70 
     71 #if DEBUG_ANGLE
     72     SkString bugOut;
     73     bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     74                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     75                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__,
     76             lh->segment()->debugID(), lh->debugID(), lh->fSectorStart, lh->fSectorEnd,
     77             lh->fStart->t(), lh->fEnd->t(),
     78             segment()->debugID(), debugID(), fSectorStart, fSectorEnd, fStart->t(), fEnd->t(),
     79             rh->segment()->debugID(), rh->debugID(), rh->fSectorStart, rh->fSectorEnd,
     80             rh->fStart->t(), rh->fEnd->t());
     81     SkString bugPart[3] = { lh->debugPart(), this->debugPart(), rh->debugPart() };
     82 #endif
     83     if (lh->fComputeSector && !lh->computeSector()) {
     84         return COMPARE_RESULT(1, true);
     85     }
     86     if (fComputeSector && !this->computeSector()) {
     87         return COMPARE_RESULT(2, true);
     88     }
     89     if (rh->fComputeSector && !rh->computeSector()) {
     90         return COMPARE_RESULT(3, true);
     91     }
     92 #if DEBUG_ANGLE  // reset bugOut with computed sectors
     93     bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     94                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g"
     95                   " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__,
     96             lh->segment()->debugID(), lh->debugID(), lh->fSectorStart, lh->fSectorEnd,
     97             lh->fStart->t(), lh->fEnd->t(),
     98             segment()->debugID(), debugID(), fSectorStart, fSectorEnd, fStart->t(), fEnd->t(),
     99             rh->segment()->debugID(), rh->debugID(), rh->fSectorStart, rh->fSectorEnd,
    100             rh->fStart->t(), rh->fEnd->t());
    101 #endif
    102     bool ltrOverlap = (lh->fSectorMask | rh->fSectorMask) & fSectorMask;
    103     bool lrOverlap = lh->fSectorMask & rh->fSectorMask;
    104     int lrOrder;  // set to -1 if either order works
    105     if (!lrOverlap) {  // no lh/rh sector overlap
    106         if (!ltrOverlap) {  // no lh/this/rh sector overlap
    107             return COMPARE_RESULT(4,  (lh->fSectorEnd > rh->fSectorStart)
    108                     ^ (fSectorStart > lh->fSectorEnd) ^ (fSectorStart > rh->fSectorStart));
    109         }
    110         int lrGap = (rh->fSectorStart - lh->fSectorStart + 32) & 0x1f;
    111         /* A tiny change can move the start +/- 4. The order can only be determined if
    112            lr gap is not 12 to 20 or -12 to -20.
    113                -31 ..-21      1
    114                -20 ..-12     -1
    115                -11 .. -1      0
    116                  0          shouldn't get here
    117                 11 ..  1      1
    118                 12 .. 20     -1
    119                 21 .. 31      0
    120          */
    121         lrOrder = lrGap > 20 ? 0 : lrGap > 11 ? -1 : 1;
    122     } else {
    123         lrOrder = (int) lh->orderable(rh);
    124         if (!ltrOverlap) {
    125             return COMPARE_RESULT(5, !lrOrder);
    126         }
    127     }
    128     int ltOrder;
    129     SkASSERT((lh->fSectorMask & fSectorMask) || (rh->fSectorMask & fSectorMask));
    130     if (lh->fSectorMask & fSectorMask) {
    131         ltOrder = (int) lh->orderable(this);
    132     } else {
    133         int ltGap = (fSectorStart - lh->fSectorStart + 32) & 0x1f;
    134         ltOrder = ltGap > 20 ? 0 : ltGap > 11 ? -1 : 1;
    135     }
    136     int trOrder;
    137     if (rh->fSectorMask & fSectorMask) {
    138         trOrder = (int) orderable(rh);
    139     } else {
    140         int trGap = (rh->fSectorStart - fSectorStart + 32) & 0x1f;
    141         trOrder = trGap > 20 ? 0 : trGap > 11 ? -1 : 1;
    142     }
    143     this->alignmentSameSide(lh, &ltOrder);
    144     this->alignmentSameSide(rh, &trOrder);
    145     if (lrOrder >= 0 && ltOrder >= 0 && trOrder >= 0) {
    146         return COMPARE_RESULT(7, lrOrder ? (ltOrder & trOrder) : (ltOrder | trOrder));
    147     }
    148     SkASSERT(lrOrder >= 0 || ltOrder >= 0 || trOrder >= 0);
    149 // There's not enough information to sort. Get the pairs of angles in opposite planes.
    150 // If an order is < 0, the pair is already in an opposite plane. Check the remaining pairs.
    151     // FIXME : once all variants are understood, rewrite this more simply
    152     if (ltOrder == 0 && lrOrder == 0) {
    153         SkASSERT(trOrder < 0);
    154         // FIXME : once this is verified to work, remove one opposite angle call
    155         SkDEBUGCODE(bool lrOpposite = lh->oppositePlanes(rh));
    156         bool ltOpposite = lh->oppositePlanes(this);
    157         SkOPASSERT(lrOpposite != ltOpposite);
    158         return COMPARE_RESULT(8, ltOpposite);
    159     } else if (ltOrder == 1 && trOrder == 0) {
    160         SkASSERT(lrOrder < 0);
    161         bool trOpposite = oppositePlanes(rh);
    162         return COMPARE_RESULT(9, trOpposite);
    163     } else if (lrOrder == 1 && trOrder == 1) {
    164         SkASSERT(ltOrder < 0);
    165 //        SkDEBUGCODE(bool trOpposite = oppositePlanes(rh));
    166         bool lrOpposite = lh->oppositePlanes(rh);
    167 //        SkASSERT(lrOpposite != trOpposite);
    168         return COMPARE_RESULT(10, lrOpposite);
    169     }
    170     if (lrOrder < 0) {
    171         if (ltOrder < 0) {
    172             return COMPARE_RESULT(11, trOrder);
    173         }
    174         return COMPARE_RESULT(12, ltOrder);
    175     }
    176     return COMPARE_RESULT(13, !lrOrder);
    177 }
    178 
    179 // given a line, see if the opposite curve's convex hull is all on one side
    180 // returns -1=not on one side    0=this CW of test   1=this CCW of test
    181 int SkOpAngle::allOnOneSide(const SkOpAngle* test) {
    182     SkASSERT(!fPart.isCurve());
    183     SkASSERT(test->fPart.isCurve());
    184     SkDPoint origin = fPart.fCurve[0];
    185     SkDVector line = fPart.fCurve[1] - origin;
    186     double crosses[3];
    187     SkPath::Verb testVerb = test->segment()->verb();
    188     int iMax = SkPathOpsVerbToPoints(testVerb);
    189 //    SkASSERT(origin == test.fCurveHalf[0]);
    190     const SkDCurve& testCurve = test->fPart.fCurve;
    191     for (int index = 1; index <= iMax; ++index) {
    192         double xy1 = line.fX * (testCurve[index].fY - origin.fY);
    193         double xy2 = line.fY * (testCurve[index].fX - origin.fX);
    194         crosses[index - 1] = AlmostBequalUlps(xy1, xy2) ? 0 : xy1 - xy2;
    195     }
    196     if (crosses[0] * crosses[1] < 0) {
    197         return -1;
    198     }
    199     if (SkPath::kCubic_Verb == testVerb) {
    200         if (crosses[0] * crosses[2] < 0 || crosses[1] * crosses[2] < 0) {
    201             return -1;
    202         }
    203     }
    204     if (crosses[0]) {
    205         return crosses[0] < 0;
    206     }
    207     if (crosses[1]) {
    208         return crosses[1] < 0;
    209     }
    210     if (SkPath::kCubic_Verb == testVerb && crosses[2]) {
    211         return crosses[2] < 0;
    212     }
    213     fUnorderable = true;
    214     return -1;
    215 }
    216 
    217 // To sort the angles, all curves are translated to have the same starting point.
    218 // If the curve's control point in its original position is on one side of a compared line,
    219 // and translated is on the opposite side, reverse the previously computed order.
    220 void SkOpAngle::alignmentSameSide(const SkOpAngle* test, int* order) const {
    221     if (*order < 0) {
    222         return;
    223     }
    224     if (fPart.isCurve()) {
    225         // This should support all curve types, but only bug that requires this has lines
    226         // Turning on for curves causes existing tests to fail
    227         return;
    228     }
    229     if (test->fPart.isCurve()) {
    230         return;
    231     }
    232     const SkDPoint& xOrigin = test->fPart.fCurve.fLine[0];
    233     const SkDPoint& oOrigin = test->fOriginalCurvePart.fLine[0];
    234     if (xOrigin == oOrigin) {
    235         return;
    236     }
    237     int iMax = SkPathOpsVerbToPoints(this->segment()->verb());
    238     SkDVector xLine = test->fPart.fCurve.fLine[1] - xOrigin;
    239     SkDVector oLine = test->fOriginalCurvePart.fLine[1] - oOrigin;
    240     for (int index = 1; index <= iMax; ++index) {
    241         const SkDPoint& testPt = fPart.fCurve[index];
    242         double xCross = oLine.crossCheck(testPt - xOrigin);
    243         double oCross = xLine.crossCheck(testPt - oOrigin);
    244         if (oCross * xCross < 0) {
    245             *order ^= 1;
    246             break;
    247         }
    248     }
    249 }
    250 
    251 bool SkOpAngle::checkCrossesZero() const {
    252     int start = SkTMin(fSectorStart, fSectorEnd);
    253     int end = SkTMax(fSectorStart, fSectorEnd);
    254     bool crossesZero = end - start > 16;
    255     return crossesZero;
    256 }
    257 
    258 bool SkOpAngle::checkParallel(SkOpAngle* rh) {
    259     SkDVector scratch[2];
    260     const SkDVector* sweep, * tweep;
    261     if (this->fPart.isOrdered()) {
    262         sweep = this->fPart.fSweep;
    263     } else {
    264         scratch[0] = this->fPart.fCurve[1] - this->fPart.fCurve[0];
    265         sweep = &scratch[0];
    266     }
    267     if (rh->fPart.isOrdered()) {
    268         tweep = rh->fPart.fSweep;
    269     } else {
    270         scratch[1] = rh->fPart.fCurve[1] - rh->fPart.fCurve[0];
    271         tweep = &scratch[1];
    272     }
    273     double s0xt0 = sweep->crossCheck(*tweep);
    274     if (tangentsDiverge(rh, s0xt0)) {
    275         return s0xt0 < 0;
    276     }
    277     // compute the perpendicular to the endpoints and see where it intersects the opposite curve
    278     // if the intersections within the t range, do a cross check on those
    279     bool inside;
    280     if (!fEnd->contains(rh->fEnd)) {
    281         if (this->endToSide(rh, &inside)) {
    282             return inside;
    283         }
    284         if (rh->endToSide(this, &inside)) {
    285             return !inside;
    286         }
    287     }
    288     if (this->midToSide(rh, &inside)) {
    289         return inside;
    290     }
    291     if (rh->midToSide(this, &inside)) {
    292         return !inside;
    293     }
    294     // compute the cross check from the mid T values (last resort)
    295     SkDVector m0 = segment()->dPtAtT(this->midT()) - this->fPart.fCurve[0];
    296     SkDVector m1 = rh->segment()->dPtAtT(rh->midT()) - rh->fPart.fCurve[0];
    297     double m0xm1 = m0.crossCheck(m1);
    298     if (m0xm1 == 0) {
    299         this->fUnorderable = true;
    300         rh->fUnorderable = true;
    301         return true;
    302     }
    303     return m0xm1 < 0;
    304 }
    305 
    306 // the original angle is too short to get meaningful sector information
    307 // lengthen it until it is long enough to be meaningful or leave it unset if lengthening it
    308 // would cause it to intersect one of the adjacent angles
    309 bool SkOpAngle::computeSector() {
    310     if (fComputedSector) {
    311         return !fUnorderable;
    312     }
    313     fComputedSector = true;
    314     bool stepUp = fStart->t() < fEnd->t();
    315     SkOpSpanBase* checkEnd = fEnd;
    316     if (checkEnd->final() && stepUp) {
    317         fUnorderable = true;
    318         return false;
    319     }
    320     do {
    321 // advance end
    322         const SkOpSegment* other = checkEnd->segment();
    323         const SkOpSpanBase* oSpan = other->head();
    324         do {
    325             if (oSpan->segment() != segment()) {
    326                 continue;
    327             }
    328             if (oSpan == checkEnd) {
    329                 continue;
    330             }
    331             if (!approximately_equal(oSpan->t(), checkEnd->t())) {
    332                 continue;
    333             }
    334             goto recomputeSector;
    335         } while (!oSpan->final() && (oSpan = oSpan->upCast()->next()));
    336         checkEnd = stepUp ? !checkEnd->final()
    337                 ? checkEnd->upCast()->next() : nullptr
    338                 : checkEnd->prev();
    339     } while (checkEnd);
    340 recomputeSector:
    341     SkOpSpanBase* computedEnd = stepUp ? checkEnd ? checkEnd->prev() : fEnd->segment()->head()
    342             : checkEnd ? checkEnd->upCast()->next() : fEnd->segment()->tail();
    343     if (checkEnd == fEnd || computedEnd == fEnd || computedEnd == fStart) {
    344         fUnorderable = true;
    345         return false;
    346     }
    347     if (stepUp != (fStart->t() < computedEnd->t())) {
    348         fUnorderable = true;
    349         return false;
    350     }
    351     SkOpSpanBase* saveEnd = fEnd;
    352     fComputedEnd = fEnd = computedEnd;
    353     setSpans();
    354     setSector();
    355     fEnd = saveEnd;
    356     return !fUnorderable;
    357 }
    358 
    359 int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) {
    360     const SkDVector* sweep = this->fPart.fSweep;
    361     const SkDVector* tweep = rh->fPart.fSweep;
    362     double s0xs1 = sweep[0].crossCheck(sweep[1]);
    363     double s0xt0 = sweep[0].crossCheck(tweep[0]);
    364     double s1xt0 = sweep[1].crossCheck(tweep[0]);
    365     bool tBetweenS = s0xs1 > 0 ? s0xt0 > 0 && s1xt0 < 0 : s0xt0 < 0 && s1xt0 > 0;
    366     double s0xt1 = sweep[0].crossCheck(tweep[1]);
    367     double s1xt1 = sweep[1].crossCheck(tweep[1]);
    368     tBetweenS |= s0xs1 > 0 ? s0xt1 > 0 && s1xt1 < 0 : s0xt1 < 0 && s1xt1 > 0;
    369     double t0xt1 = tweep[0].crossCheck(tweep[1]);
    370     if (tBetweenS) {
    371         return -1;
    372     }
    373     if ((s0xt0 == 0 && s1xt1 == 0) || (s1xt0 == 0 && s0xt1 == 0)) {  // s0 to s1 equals t0 to t1
    374         return -1;
    375     }
    376     bool sBetweenT = t0xt1 > 0 ? s0xt0 < 0 && s0xt1 > 0 : s0xt0 > 0 && s0xt1 < 0;
    377     sBetweenT |= t0xt1 > 0 ? s1xt0 < 0 && s1xt1 > 0 : s1xt0 > 0 && s1xt1 < 0;
    378     if (sBetweenT) {
    379         return -1;
    380     }
    381     // if all of the sweeps are in the same half plane, then the order of any pair is enough
    382     if (s0xt0 >= 0 && s0xt1 >= 0 && s1xt0 >= 0 && s1xt1 >= 0) {
    383         return 0;
    384     }
    385     if (s0xt0 <= 0 && s0xt1 <= 0 && s1xt0 <= 0 && s1xt1 <= 0) {
    386         return 1;
    387     }
    388     // if the outside sweeps are greater than 180 degress:
    389         // first assume the inital tangents are the ordering
    390         // if the midpoint direction matches the inital order, that is enough
    391     SkDVector m0 = this->segment()->dPtAtT(this->midT()) - this->fPart.fCurve[0];
    392     SkDVector m1 = rh->segment()->dPtAtT(rh->midT()) - rh->fPart.fCurve[0];
    393     double m0xm1 = m0.crossCheck(m1);
    394     if (s0xt0 > 0 && m0xm1 > 0) {
    395         return 0;
    396     }
    397     if (s0xt0 < 0 && m0xm1 < 0) {
    398         return 1;
    399     }
    400     if (tangentsDiverge(rh, s0xt0)) {
    401         return s0xt0 < 0;
    402     }
    403     return m0xm1 < 0;
    404 }
    405 
    406 // OPTIMIZATION: longest can all be either lazily computed here or precomputed in setup
    407 double SkOpAngle::distEndRatio(double dist) const {
    408     double longest = 0;
    409     const SkOpSegment& segment = *this->segment();
    410     int ptCount = SkPathOpsVerbToPoints(segment.verb());
    411     const SkPoint* pts = segment.pts();
    412     for (int idx1 = 0; idx1 <= ptCount - 1; ++idx1) {
    413         for (int idx2 = idx1 + 1; idx2 <= ptCount; ++idx2) {
    414             if (idx1 == idx2) {
    415                 continue;
    416             }
    417             SkDVector v;
    418             v.set(pts[idx2] - pts[idx1]);
    419             double lenSq = v.lengthSquared();
    420             longest = SkTMax(longest, lenSq);
    421         }
    422     }
    423     return sqrt(longest) / dist;
    424 }
    425 
    426 bool SkOpAngle::endsIntersect(SkOpAngle* rh) {
    427     SkPath::Verb lVerb = this->segment()->verb();
    428     SkPath::Verb rVerb = rh->segment()->verb();
    429     int lPts = SkPathOpsVerbToPoints(lVerb);
    430     int rPts = SkPathOpsVerbToPoints(rVerb);
    431     SkDLine rays[] = {{{this->fPart.fCurve[0], rh->fPart.fCurve[rPts]}},
    432             {{this->fPart.fCurve[0], this->fPart.fCurve[lPts]}}};
    433     if (this->fEnd->contains(rh->fEnd)) {
    434         return checkParallel(rh);
    435     }
    436     double smallTs[2] = {-1, -1};
    437     bool limited[2] = {false, false};
    438     for (int index = 0; index < 2; ++index) {
    439         SkPath::Verb cVerb = index ? rVerb : lVerb;
    440         // if the curve is a line, then the line and the ray intersect only at their crossing
    441         if (cVerb == SkPath::kLine_Verb) {
    442             continue;
    443         }
    444         const SkOpSegment& segment = index ? *rh->segment() : *this->segment();
    445         SkIntersections i;
    446         (*CurveIntersectRay[cVerb])(segment.pts(), segment.weight(), rays[index], &i);
    447         double tStart = index ? rh->fStart->t() : this->fStart->t();
    448         double tEnd = index ? rh->fComputedEnd->t() : this->fComputedEnd->t();
    449         bool testAscends = tStart < (index ? rh->fComputedEnd->t() : this->fComputedEnd->t());
    450         double t = testAscends ? 0 : 1;
    451         for (int idx2 = 0; idx2 < i.used(); ++idx2) {
    452             double testT = i[0][idx2];
    453             if (!approximately_between_orderable(tStart, testT, tEnd)) {
    454                 continue;
    455             }
    456             if (approximately_equal_orderable(tStart, testT)) {
    457                 continue;
    458             }
    459             smallTs[index] = t = testAscends ? SkTMax(t, testT) : SkTMin(t, testT);
    460             limited[index] = approximately_equal_orderable(t, tEnd);
    461         }
    462     }
    463     bool sRayLonger = false;
    464     SkDVector sCept = {0, 0};
    465     double sCeptT = -1;
    466     int sIndex = -1;
    467     bool useIntersect = false;
    468     for (int index = 0; index < 2; ++index) {
    469         if (smallTs[index] < 0) {
    470             continue;
    471         }
    472         const SkOpSegment& segment = index ? *rh->segment() : *this->segment();
    473         const SkDPoint& dPt = segment.dPtAtT(smallTs[index]);
    474         SkDVector cept = dPt - rays[index][0];
    475         // If this point is on the curve, it should have been detected earlier by ordinary
    476         // curve intersection. This may be hard to determine in general, but for lines,
    477         // the point could be close to or equal to its end, but shouldn't be near the start.
    478         if ((index ? lPts : rPts) == 1) {
    479             SkDVector total = rays[index][1] - rays[index][0];
    480             if (cept.lengthSquared() * 2 < total.lengthSquared()) {
    481                 continue;
    482             }
    483         }
    484         SkDVector end = rays[index][1] - rays[index][0];
    485         if (cept.fX * end.fX < 0 || cept.fY * end.fY < 0) {
    486             continue;
    487         }
    488         double rayDist = cept.length();
    489         double endDist = end.length();
    490         bool rayLonger = rayDist > endDist;
    491         if (limited[0] && limited[1] && rayLonger) {
    492             useIntersect = true;
    493             sRayLonger = rayLonger;
    494             sCept = cept;
    495             sCeptT = smallTs[index];
    496             sIndex = index;
    497             break;
    498         }
    499         double delta = fabs(rayDist - endDist);
    500         double minX, minY, maxX, maxY;
    501         minX = minY = SK_ScalarInfinity;
    502         maxX = maxY = -SK_ScalarInfinity;
    503         const SkDCurve& curve = index ? rh->fPart.fCurve : this->fPart.fCurve;
    504         int ptCount = index ? rPts : lPts;
    505         for (int idx2 = 0; idx2 <= ptCount; ++idx2) {
    506             minX = SkTMin(minX, curve[idx2].fX);
    507             minY = SkTMin(minY, curve[idx2].fY);
    508             maxX = SkTMax(maxX, curve[idx2].fX);
    509             maxY = SkTMax(maxY, curve[idx2].fY);
    510         }
    511         double maxWidth = SkTMax(maxX - minX, maxY - minY);
    512         delta /= maxWidth;
    513         if (delta > 1e-3 && (useIntersect ^= true)) {  // FIXME: move this magic number
    514             sRayLonger = rayLonger;
    515             sCept = cept;
    516             sCeptT = smallTs[index];
    517             sIndex = index;
    518         }
    519     }
    520     if (useIntersect) {
    521         const SkDCurve& curve = sIndex ? rh->fPart.fCurve : this->fPart.fCurve;
    522         const SkOpSegment& segment = sIndex ? *rh->segment() : *this->segment();
    523         double tStart = sIndex ? rh->fStart->t() : fStart->t();
    524         SkDVector mid = segment.dPtAtT(tStart + (sCeptT - tStart) / 2) - curve[0];
    525         double septDir = mid.crossCheck(sCept);
    526         if (!septDir) {
    527             return checkParallel(rh);
    528         }
    529         return sRayLonger ^ (sIndex == 0) ^ (septDir < 0);
    530     } else {
    531         return checkParallel(rh);
    532     }
    533 }
    534 
    535 bool SkOpAngle::endToSide(const SkOpAngle* rh, bool* inside) const {
    536     const SkOpSegment* segment = this->segment();
    537     SkPath::Verb verb = segment->verb();
    538     SkDLine rayEnd;
    539     rayEnd[0].set(this->fEnd->pt());
    540     rayEnd[1] = rayEnd[0];
    541     SkDVector slopeAtEnd = (*CurveDSlopeAtT[verb])(segment->pts(), segment->weight(),
    542             this->fEnd->t());
    543     rayEnd[1].fX += slopeAtEnd.fY;
    544     rayEnd[1].fY -= slopeAtEnd.fX;
    545     SkIntersections iEnd;
    546     const SkOpSegment* oppSegment = rh->segment();
    547     SkPath::Verb oppVerb = oppSegment->verb();
    548     (*CurveIntersectRay[oppVerb])(oppSegment->pts(), oppSegment->weight(), rayEnd, &iEnd);
    549     double endDist;
    550     int closestEnd = iEnd.closestTo(rh->fStart->t(), rh->fEnd->t(), rayEnd[0], &endDist);
    551     if (closestEnd < 0) {
    552         return false;
    553     }
    554     if (!endDist) {
    555         return false;
    556     }
    557     SkDPoint start;
    558     start.set(this->fStart->pt());
    559     // OPTIMIZATION: multiple times in the code we find the max scalar
    560     double minX, minY, maxX, maxY;
    561     minX = minY = SK_ScalarInfinity;
    562     maxX = maxY = -SK_ScalarInfinity;
    563     const SkDCurve& curve = rh->fPart.fCurve;
    564     int oppPts = SkPathOpsVerbToPoints(oppVerb);
    565     for (int idx2 = 0; idx2 <= oppPts; ++idx2) {
    566         minX = SkTMin(minX, curve[idx2].fX);
    567         minY = SkTMin(minY, curve[idx2].fY);
    568         maxX = SkTMax(maxX, curve[idx2].fX);
    569         maxY = SkTMax(maxY, curve[idx2].fY);
    570     }
    571     double maxWidth = SkTMax(maxX - minX, maxY - minY);
    572     endDist /= maxWidth;
    573     if (endDist < 5e-12) {  // empirically found
    574         return false;
    575     }
    576     const SkDPoint* endPt = &rayEnd[0];
    577     SkDPoint oppPt = iEnd.pt(closestEnd);
    578     SkDVector vLeft = *endPt - start;
    579     SkDVector vRight = oppPt - start;
    580     double dir = vLeft.crossNoNormalCheck(vRight);
    581     if (!dir) {
    582         return false;
    583     }
    584     *inside = dir < 0;
    585     return true;
    586 }
    587 
    588 /*      y<0 y==0 y>0  x<0 x==0 x>0 xy<0 xy==0 xy>0
    589     0    x                      x               x
    590     1    x                      x          x
    591     2    x                      x    x
    592     3    x                  x        x
    593     4    x             x             x
    594     5    x             x                   x
    595     6    x             x                        x
    596     7         x        x                        x
    597     8             x    x                        x
    598     9             x    x                   x
    599     10            x    x             x
    600     11            x         x        x
    601     12            x             x    x
    602     13            x             x          x
    603     14            x             x               x
    604     15        x                 x               x
    605 */
    606 int SkOpAngle::findSector(SkPath::Verb verb, double x, double y) const {
    607     double absX = fabs(x);
    608     double absY = fabs(y);
    609     double xy = SkPath::kLine_Verb == verb || !AlmostEqualUlps(absX, absY) ? absX - absY : 0;
    610     // If there are four quadrants and eight octants, and since the Latin for sixteen is sedecim,
    611     // one could coin the term sedecimant for a space divided into 16 sections.
    612    // http://english.stackexchange.com/questions/133688/word-for-something-partitioned-into-16-parts
    613     static const int sedecimant[3][3][3] = {
    614     //       y<0           y==0           y>0
    615     //   x<0 x==0 x>0  x<0 x==0 x>0  x<0 x==0 x>0
    616         {{ 4,  3,  2}, { 7, -1, 15}, {10, 11, 12}},  // abs(x) <  abs(y)
    617         {{ 5, -1,  1}, {-1, -1, -1}, { 9, -1, 13}},  // abs(x) == abs(y)
    618         {{ 6,  3,  0}, { 7, -1, 15}, { 8, 11, 14}},  // abs(x) >  abs(y)
    619     };
    620     int sector = sedecimant[(xy >= 0) + (xy > 0)][(y >= 0) + (y > 0)][(x >= 0) + (x > 0)] * 2 + 1;
    621 //    SkASSERT(SkPath::kLine_Verb == verb || sector >= 0);
    622     return sector;
    623 }
    624 
    625 SkOpGlobalState* SkOpAngle::globalState() const {
    626     return this->segment()->globalState();
    627 }
    628 
    629 
    630 // OPTIMIZE: if this loops to only one other angle, after first compare fails, insert on other side
    631 // OPTIMIZE: return where insertion succeeded. Then, start next insertion on opposite side
    632 bool SkOpAngle::insert(SkOpAngle* angle) {
    633     if (angle->fNext) {
    634         if (loopCount() >= angle->loopCount()) {
    635             if (!merge(angle)) {
    636                 return true;
    637             }
    638         } else if (fNext) {
    639             if (!angle->merge(this)) {
    640                 return true;
    641             }
    642         } else {
    643             angle->insert(this);
    644         }
    645         return true;
    646     }
    647     bool singleton = nullptr == fNext;
    648     if (singleton) {
    649         fNext = this;
    650     }
    651     SkOpAngle* next = fNext;
    652     if (next->fNext == this) {
    653         if (singleton || angle->after(this)) {
    654             this->fNext = angle;
    655             angle->fNext = next;
    656         } else {
    657             next->fNext = angle;
    658             angle->fNext = this;
    659         }
    660         debugValidateNext();
    661         return true;
    662     }
    663     SkOpAngle* last = this;
    664     bool flipAmbiguity = false;
    665     do {
    666         SkASSERT(last->fNext == next);
    667         if (angle->after(last) ^ (angle->tangentsAmbiguous() & flipAmbiguity)) {
    668             last->fNext = angle;
    669             angle->fNext = next;
    670             debugValidateNext();
    671             return true;
    672         }
    673         last = next;
    674         if (last == this) {
    675             FAIL_IF(flipAmbiguity);
    676             // We're in a loop. If a sort was ambiguous, flip it to end the loop.
    677             flipAmbiguity = true;
    678         }
    679         next = next->fNext;
    680     } while (true);
    681     return true;
    682 }
    683 
    684 SkOpSpanBase* SkOpAngle::lastMarked() const {
    685     if (fLastMarked) {
    686         if (fLastMarked->chased()) {
    687             return nullptr;
    688         }
    689         fLastMarked->setChased(true);
    690     }
    691     return fLastMarked;
    692 }
    693 
    694 bool SkOpAngle::loopContains(const SkOpAngle* angle) const {
    695     if (!fNext) {
    696         return false;
    697     }
    698     const SkOpAngle* first = this;
    699     const SkOpAngle* loop = this;
    700     const SkOpSegment* tSegment = angle->fStart->segment();
    701     double tStart = angle->fStart->t();
    702     double tEnd = angle->fEnd->t();
    703     do {
    704         const SkOpSegment* lSegment = loop->fStart->segment();
    705         if (lSegment != tSegment) {
    706             continue;
    707         }
    708         double lStart = loop->fStart->t();
    709         if (lStart != tEnd) {
    710             continue;
    711         }
    712         double lEnd = loop->fEnd->t();
    713         if (lEnd == tStart) {
    714             return true;
    715         }
    716     } while ((loop = loop->fNext) != first);
    717     return false;
    718 }
    719 
    720 int SkOpAngle::loopCount() const {
    721     int count = 0;
    722     const SkOpAngle* first = this;
    723     const SkOpAngle* next = this;
    724     do {
    725         next = next->fNext;
    726         ++count;
    727     } while (next && next != first);
    728     return count;
    729 }
    730 
    731 bool SkOpAngle::merge(SkOpAngle* angle) {
    732     SkASSERT(fNext);
    733     SkASSERT(angle->fNext);
    734     SkOpAngle* working = angle;
    735     do {
    736         if (this == working) {
    737             return false;
    738         }
    739         working = working->fNext;
    740     } while (working != angle);
    741     do {
    742         SkOpAngle* next = working->fNext;
    743         working->fNext = nullptr;
    744         insert(working);
    745         working = next;
    746     } while (working != angle);
    747     // it's likely that a pair of the angles are unorderable
    748     debugValidateNext();
    749     return true;
    750 }
    751 
    752 double SkOpAngle::midT() const {
    753     return (fStart->t() + fEnd->t()) / 2;
    754 }
    755 
    756 bool SkOpAngle::midToSide(const SkOpAngle* rh, bool* inside) const {
    757     const SkOpSegment* segment = this->segment();
    758     SkPath::Verb verb = segment->verb();
    759     const SkPoint& startPt = this->fStart->pt();
    760     const SkPoint& endPt = this->fEnd->pt();
    761     SkDPoint dStartPt;
    762     dStartPt.set(startPt);
    763     SkDLine rayMid;
    764     rayMid[0].fX = (startPt.fX + endPt.fX) / 2;
    765     rayMid[0].fY = (startPt.fY + endPt.fY) / 2;
    766     rayMid[1].fX = rayMid[0].fX + (endPt.fY - startPt.fY);
    767     rayMid[1].fY = rayMid[0].fY - (endPt.fX - startPt.fX);
    768     SkIntersections iMid;
    769     (*CurveIntersectRay[verb])(segment->pts(), segment->weight(), rayMid, &iMid);
    770     int iOutside = iMid.mostOutside(this->fStart->t(), this->fEnd->t(), dStartPt);
    771     if (iOutside < 0) {
    772         return false;
    773     }
    774     const SkOpSegment* oppSegment = rh->segment();
    775     SkPath::Verb oppVerb = oppSegment->verb();
    776     SkIntersections oppMid;
    777     (*CurveIntersectRay[oppVerb])(oppSegment->pts(), oppSegment->weight(), rayMid, &oppMid);
    778     int oppOutside = oppMid.mostOutside(rh->fStart->t(), rh->fEnd->t(), dStartPt);
    779     if (oppOutside < 0) {
    780         return false;
    781     }
    782     SkDVector iSide = iMid.pt(iOutside) - dStartPt;
    783     SkDVector oppSide = oppMid.pt(oppOutside) - dStartPt;
    784     double dir = iSide.crossCheck(oppSide);
    785     if (!dir) {
    786         return false;
    787     }
    788     *inside = dir < 0;
    789     return true;
    790 }
    791 
    792 bool SkOpAngle::oppositePlanes(const SkOpAngle* rh) const {
    793     int startSpan = SkTAbs(rh->fSectorStart - fSectorStart);
    794     return startSpan >= 8;
    795 }
    796 
    797 bool SkOpAngle::orderable(SkOpAngle* rh) {
    798     int result;
    799     if (!fPart.isCurve()) {
    800         if (!rh->fPart.isCurve()) {
    801             double leftX = fTangentHalf.dx();
    802             double leftY = fTangentHalf.dy();
    803             double rightX = rh->fTangentHalf.dx();
    804             double rightY = rh->fTangentHalf.dy();
    805             double x_ry = leftX * rightY;
    806             double rx_y = rightX * leftY;
    807             if (x_ry == rx_y) {
    808                 if (leftX * rightX < 0 || leftY * rightY < 0) {
    809                     return true;  // exactly 180 degrees apart
    810                 }
    811                 goto unorderable;
    812             }
    813             SkASSERT(x_ry != rx_y); // indicates an undetected coincidence -- worth finding earlier
    814             return x_ry < rx_y;
    815         }
    816         if ((result = this->allOnOneSide(rh)) >= 0) {
    817             return result;
    818         }
    819         if (fUnorderable || approximately_zero(rh->fSide)) {
    820             goto unorderable;
    821         }
    822     } else if (!rh->fPart.isCurve()) {
    823         if ((result = rh->allOnOneSide(this)) >= 0) {
    824             return !result;
    825         }
    826         if (rh->fUnorderable || approximately_zero(fSide)) {
    827             goto unorderable;
    828         }
    829     } else if ((result = this->convexHullOverlaps(rh)) >= 0) {
    830         return result;
    831     }
    832     return this->endsIntersect(rh);
    833 unorderable:
    834     fUnorderable = true;
    835     rh->fUnorderable = true;
    836     return true;
    837 }
    838 
    839 // OPTIMIZE: if this shows up in a profile, add a previous pointer
    840 // as is, this should be rarely called
    841 SkOpAngle* SkOpAngle::previous() const {
    842     SkOpAngle* last = fNext;
    843     do {
    844         SkOpAngle* next = last->fNext;
    845         if (next == this) {
    846             return last;
    847         }
    848         last = next;
    849     } while (true);
    850 }
    851 
    852 SkOpSegment* SkOpAngle::segment() const {
    853     return fStart->segment();
    854 }
    855 
    856 void SkOpAngle::set(SkOpSpanBase* start, SkOpSpanBase* end) {
    857     fStart = start;
    858     fComputedEnd = fEnd = end;
    859     SkASSERT(start != end);
    860     fNext = nullptr;
    861     fComputeSector = fComputedSector = fCheckCoincidence = fTangentsAmbiguous = false;
    862     setSpans();
    863     setSector();
    864     SkDEBUGCODE(fID = start ? start->globalState()->nextAngleID() : -1);
    865 }
    866 
    867 void SkOpAngle::setSpans() {
    868     fUnorderable = false;
    869     fLastMarked = nullptr;
    870     if (!fStart) {
    871         fUnorderable = true;
    872         return;
    873     }
    874     const SkOpSegment* segment = fStart->segment();
    875     const SkPoint* pts = segment->pts();
    876     SkDEBUGCODE(fPart.fCurve.fVerb = SkPath::kCubic_Verb);  // required for SkDCurve debug check
    877     SkDEBUGCODE(fPart.fCurve[2].fX = fPart.fCurve[2].fY = fPart.fCurve[3].fX = fPart.fCurve[3].fY
    878             = SK_ScalarNaN);   //  make the non-line part uninitialized
    879     SkDEBUGCODE(fPart.fCurve.fVerb = segment->verb());  //  set the curve type for real
    880     segment->subDivide(fStart, fEnd, &fPart.fCurve);  //  set at least the line part if not more
    881     fOriginalCurvePart = fPart.fCurve;
    882     const SkPath::Verb verb = segment->verb();
    883     fPart.setCurveHullSweep(verb);
    884     if (SkPath::kLine_Verb != verb && !fPart.isCurve()) {
    885         SkDLine lineHalf;
    886         fPart.fCurve[1] = fPart.fCurve[SkPathOpsVerbToPoints(verb)];
    887         fOriginalCurvePart[1] = fPart.fCurve[1];
    888         lineHalf[0].set(fPart.fCurve[0].asSkPoint());
    889         lineHalf[1].set(fPart.fCurve[1].asSkPoint());
    890         fTangentHalf.lineEndPoints(lineHalf);
    891         fSide = 0;
    892     }
    893     switch (verb) {
    894     case SkPath::kLine_Verb: {
    895         SkASSERT(fStart != fEnd);
    896         const SkPoint& cP1 = pts[fStart->t() < fEnd->t()];
    897         SkDLine lineHalf;
    898         lineHalf[0].set(fStart->pt());
    899         lineHalf[1].set(cP1);
    900         fTangentHalf.lineEndPoints(lineHalf);
    901         fSide = 0;
    902         } return;
    903     case SkPath::kQuad_Verb:
    904     case SkPath::kConic_Verb: {
    905         SkLineParameters tangentPart;
    906         (void) tangentPart.quadEndPoints(fPart.fCurve.fQuad);
    907         fSide = -tangentPart.pointDistance(fPart.fCurve[2]);  // not normalized -- compare sign only
    908         } break;
    909     case SkPath::kCubic_Verb: {
    910         SkLineParameters tangentPart;
    911         (void) tangentPart.cubicPart(fPart.fCurve.fCubic);
    912         fSide = -tangentPart.pointDistance(fPart.fCurve[3]);
    913         double testTs[4];
    914         // OPTIMIZATION: keep inflections precomputed with cubic segment?
    915         int testCount = SkDCubic::FindInflections(pts, testTs);
    916         double startT = fStart->t();
    917         double endT = fEnd->t();
    918         double limitT = endT;
    919         int index;
    920         for (index = 0; index < testCount; ++index) {
    921             if (!::between(startT, testTs[index], limitT)) {
    922                 testTs[index] = -1;
    923             }
    924         }
    925         testTs[testCount++] = startT;
    926         testTs[testCount++] = endT;
    927         SkTQSort<double>(testTs, &testTs[testCount - 1]);
    928         double bestSide = 0;
    929         int testCases = (testCount << 1) - 1;
    930         index = 0;
    931         while (testTs[index] < 0) {
    932             ++index;
    933         }
    934         index <<= 1;
    935         for (; index < testCases; ++index) {
    936             int testIndex = index >> 1;
    937             double testT = testTs[testIndex];
    938             if (index & 1) {
    939                 testT = (testT + testTs[testIndex + 1]) / 2;
    940             }
    941             // OPTIMIZE: could avoid call for t == startT, endT
    942             SkDPoint pt = dcubic_xy_at_t(pts, segment->weight(), testT);
    943             SkLineParameters tangentPart;
    944             tangentPart.cubicEndPoints(fPart.fCurve.fCubic);
    945             double testSide = tangentPart.pointDistance(pt);
    946             if (fabs(bestSide) < fabs(testSide)) {
    947                 bestSide = testSide;
    948             }
    949         }
    950         fSide = -bestSide;  // compare sign only
    951         } break;
    952     default:
    953         SkASSERT(0);
    954     }
    955 }
    956 
    957 void SkOpAngle::setSector() {
    958     if (!fStart) {
    959         fUnorderable = true;
    960         return;
    961     }
    962     const SkOpSegment* segment = fStart->segment();
    963     SkPath::Verb verb = segment->verb();
    964     fSectorStart = this->findSector(verb, fPart.fSweep[0].fX, fPart.fSweep[0].fY);
    965     if (fSectorStart < 0) {
    966         goto deferTilLater;
    967     }
    968     if (!fPart.isCurve()) {  // if it's a line or line-like, note that both sectors are the same
    969         SkASSERT(fSectorStart >= 0);
    970         fSectorEnd = fSectorStart;
    971         fSectorMask = 1 << fSectorStart;
    972         return;
    973     }
    974     SkASSERT(SkPath::kLine_Verb != verb);
    975     fSectorEnd = this->findSector(verb, fPart.fSweep[1].fX, fPart.fSweep[1].fY);
    976     if (fSectorEnd < 0) {
    977 deferTilLater:
    978         fSectorStart = fSectorEnd = -1;
    979         fSectorMask = 0;
    980         fComputeSector = true;  // can't determine sector until segment length can be found
    981         return;
    982     }
    983     if (fSectorEnd == fSectorStart
    984             && (fSectorStart & 3) != 3) { // if the sector has no span, it can't be an exact angle
    985         fSectorMask = 1 << fSectorStart;
    986         return;
    987     }
    988     bool crossesZero = this->checkCrossesZero();
    989     int start = SkTMin(fSectorStart, fSectorEnd);
    990     bool curveBendsCCW = (fSectorStart == start) ^ crossesZero;
    991     // bump the start and end of the sector span if they are on exact compass points
    992     if ((fSectorStart & 3) == 3) {
    993         fSectorStart = (fSectorStart + (curveBendsCCW ? 1 : 31)) & 0x1f;
    994     }
    995     if ((fSectorEnd & 3) == 3) {
    996         fSectorEnd = (fSectorEnd + (curveBendsCCW ? 31 : 1)) & 0x1f;
    997     }
    998     crossesZero = this->checkCrossesZero();
    999     start = SkTMin(fSectorStart, fSectorEnd);
   1000     int end = SkTMax(fSectorStart, fSectorEnd);
   1001     if (!crossesZero) {
   1002         fSectorMask = (unsigned) -1 >> (31 - end + start) << start;
   1003     } else {
   1004         fSectorMask = (unsigned) -1 >> (31 - start) | ((unsigned) -1 << end);
   1005     }
   1006 }
   1007 
   1008 SkOpSpan* SkOpAngle::starter() {
   1009     return fStart->starter(fEnd);
   1010 }
   1011 
   1012 bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) {
   1013     if (s0xt0 == 0) {
   1014         return false;
   1015     }
   1016     // if the ctrl tangents are not nearly parallel, use them
   1017     // solve for opposite direction displacement scale factor == m
   1018     // initial dir = v1.cross(v2) == v2.x * v1.y - v2.y * v1.x
   1019     // displacement of q1[1] : dq1 = { -m * v1.y, m * v1.x } + q1[1]
   1020     // straight angle when : v2.x * (dq1.y - q1[0].y) == v2.y * (dq1.x - q1[0].x)
   1021     //                       v2.x * (m * v1.x + v1.y) == v2.y * (-m * v1.y + v1.x)
   1022     // - m * (v2.x * v1.x + v2.y * v1.y) == v2.x * v1.y - v2.y * v1.x
   1023     // m = (v2.y * v1.x - v2.x * v1.y) / (v2.x * v1.x + v2.y * v1.y)
   1024     // m = v1.cross(v2) / v1.dot(v2)
   1025     const SkDVector* sweep = fPart.fSweep;
   1026     const SkDVector* tweep = rh->fPart.fSweep;
   1027     double s0dt0 = sweep[0].dot(tweep[0]);
   1028     if (!s0dt0) {
   1029         return true;
   1030     }
   1031     SkASSERT(s0dt0 != 0);
   1032     double m = s0xt0 / s0dt0;
   1033     double sDist = sweep[0].length() * m;
   1034     double tDist = tweep[0].length() * m;
   1035     bool useS = fabs(sDist) < fabs(tDist);
   1036     double mFactor = fabs(useS ? this->distEndRatio(sDist) : rh->distEndRatio(tDist));
   1037     fTangentsAmbiguous = mFactor >= 50 && mFactor < 200;
   1038     return mFactor < 50;   // empirically found limit
   1039 }
   1040