Home | History | Annotate | Download | only in Intersection
      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 
      8 #include "Simplify.h"
      9 
     10 namespace Op {
     11 
     12 #define INCLUDED_BY_SHAPE_OPS 1
     13 
     14 #include "Simplify.cpp"
     15 
     16 // FIXME: this and find chase should be merge together, along with
     17 // other code that walks winding in angles
     18 // OPTIMIZATION: Probably, the walked winding should be rolled into the angle structure
     19 // so it isn't duplicated by walkers like this one
     20 static Segment* findChaseOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd) {
     21     while (chase.count()) {
     22         Span* span;
     23         chase.pop(&span);
     24         const Span& backPtr = span->fOther->span(span->fOtherIndex);
     25         Segment* segment = backPtr.fOther;
     26         nextStart = backPtr.fOtherIndex;
     27         SkTDArray<Angle> angles;
     28         int done = 0;
     29         if (segment->activeAngle(nextStart, done, angles)) {
     30             Angle* last = angles.end() - 1;
     31             nextStart = last->start();
     32             nextEnd = last->end();
     33    #if TRY_ROTATE
     34             *chase.insert(0) = span;
     35    #else
     36             *chase.append() = span;
     37    #endif
     38             return last->segment();
     39         }
     40         if (done == angles.count()) {
     41             continue;
     42         }
     43         SkTDArray<Angle*> sorted;
     44         bool sortable = Segment::SortAngles(angles, sorted);
     45         int angleCount = sorted.count();
     46 #if DEBUG_SORT
     47         sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0);
     48 #endif
     49         if (!sortable) {
     50             continue;
     51         }
     52         // find first angle, initialize winding to computed fWindSum
     53         int firstIndex = -1;
     54         const Angle* angle;
     55         do {
     56             angle = sorted[++firstIndex];
     57             segment = angle->segment();
     58         } while (segment->windSum(angle) == SK_MinS32);
     59     #if DEBUG_SORT
     60         segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
     61     #endif
     62         int sumMiWinding = segment->updateWindingReverse(angle);
     63         int sumSuWinding = segment->updateOppWindingReverse(angle);
     64         if (segment->operand()) {
     65             SkTSwap<int>(sumMiWinding, sumSuWinding);
     66         }
     67         int nextIndex = firstIndex + 1;
     68         int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
     69         Segment* first = NULL;
     70         do {
     71             SkASSERT(nextIndex != firstIndex);
     72             if (nextIndex == angleCount) {
     73                 nextIndex = 0;
     74             }
     75             angle = sorted[nextIndex];
     76             segment = angle->segment();
     77             int start = angle->start();
     78             int end = angle->end();
     79             int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
     80             segment->setUpWindings(start, end, sumMiWinding, sumSuWinding,
     81                     maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
     82             if (!segment->done(angle)) {
     83                 if (!first) {
     84                     first = segment;
     85                     nextStart = start;
     86                     nextEnd = end;
     87                 }
     88                 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
     89                     oppSumWinding, true, angle);
     90             }
     91         } while (++nextIndex != lastIndex);
     92         if (first) {
     93        #if TRY_ROTATE
     94             *chase.insert(0) = span;
     95        #else
     96             *chase.append() = span;
     97        #endif
     98             return first;
     99         }
    100     }
    101     return NULL;
    102 }
    103 
    104 /*
    105 static bool windingIsActive(int winding, int oppWinding, int spanWinding, int oppSpanWinding,
    106         bool windingIsOp, ShapeOp op) {
    107     bool active = windingIsActive(winding, spanWinding);
    108     if (!active) {
    109         return false;
    110     }
    111     if (oppSpanWinding && windingIsActive(oppWinding, oppSpanWinding)) {
    112         switch (op) {
    113             case kIntersect_Op:
    114             case kUnion_Op:
    115                 return true;
    116             case kDifference_Op: {
    117                 int absSpan = abs(spanWinding);
    118                 int absOpp = abs(oppSpanWinding);
    119                 return windingIsOp ? absSpan < absOpp : absSpan > absOpp;
    120             }
    121             case kXor_Op:
    122                 return spanWinding != oppSpanWinding;
    123             default:
    124                 SkASSERT(0);
    125         }
    126     }
    127     bool opActive = oppWinding != 0;
    128     return gOpLookup[op][opActive][windingIsOp];
    129 }
    130 */
    131 
    132 static bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
    133         const int xorMask, const int xorOpMask, PathWrapper& simple) {
    134     bool firstContour = true;
    135     bool unsortable = false;
    136     bool topUnsortable = false;
    137     SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
    138     do {
    139         int index, endIndex;
    140         bool done;
    141         Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
    142                 topUnsortable, done, true);
    143         if (!current) {
    144             if (topUnsortable || !done) {
    145                 topUnsortable = false;
    146                 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
    147                 topLeft.fX = topLeft.fY = SK_ScalarMin;
    148                 continue;
    149             }
    150             break;
    151         }
    152         SkTDArray<Span*> chaseArray;
    153         do {
    154             if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) {
    155                 do {
    156             #if DEBUG_ACTIVE_SPANS
    157                     if (!unsortable && current->done()) {
    158                         debugShowActiveSpans(contourList);
    159                     }
    160             #endif
    161                     SkASSERT(unsortable || !current->done());
    162                     int nextStart = index;
    163                     int nextEnd = endIndex;
    164                     Segment* next = current->findNextOp(chaseArray, nextStart, nextEnd,
    165                             unsortable, op, xorMask, xorOpMask);
    166                     if (!next) {
    167                         if (!unsortable && simple.hasMove()
    168                                 && current->verb() != SkPath::kLine_Verb
    169                                 && !simple.isClosed()) {
    170                             current->addCurveTo(index, endIndex, simple, true);
    171                             SkASSERT(simple.isClosed());
    172                         }
    173                         break;
    174                     }
    175         #if DEBUG_FLOW
    176             SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
    177                     current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
    178                     current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
    179         #endif
    180                     current->addCurveTo(index, endIndex, simple, true);
    181                     current = next;
    182                     index = nextStart;
    183                     endIndex = nextEnd;
    184                 } while (!simple.isClosed() && ((!unsortable)
    185                         || !current->done(SkMin32(index, endIndex))));
    186                 if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
    187                     SkASSERT(unsortable);
    188                     int min = SkMin32(index, endIndex);
    189                     if (!current->done(min)) {
    190                         current->addCurveTo(index, endIndex, simple, true);
    191                         current->markDoneBinary(min);
    192                     }
    193                 }
    194                 simple.close();
    195             } else {
    196                 Span* last = current->markAndChaseDoneBinary(index, endIndex);
    197                 if (last && !last->fLoop) {
    198                     *chaseArray.append() = last;
    199                 }
    200             }
    201             current = findChaseOp(chaseArray, index, endIndex);
    202         #if DEBUG_ACTIVE_SPANS
    203             debugShowActiveSpans(contourList);
    204         #endif
    205             if (!current) {
    206                 break;
    207             }
    208         } while (true);
    209     } while (true);
    210     return simple.someAssemblyRequired();
    211 }
    212 
    213 } // end of Op namespace
    214 
    215 
    216 void operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) {
    217 #if DEBUG_SORT || DEBUG_SWAP_TOP
    218     Op::gDebugSortCount = Op::gDebugSortCountDefault;
    219 #endif
    220     result.reset();
    221     result.setFillType(SkPath::kEvenOdd_FillType);
    222     // turn path into list of segments
    223     SkTArray<Op::Contour> contours;
    224     // FIXME: add self-intersecting cubics' T values to segment
    225     Op::EdgeBuilder builder(one, contours);
    226     const int xorMask = builder.xorMask();
    227     builder.addOperand(two);
    228     builder.finish();
    229     const int xorOpMask = builder.xorMask();
    230     SkTDArray<Op::Contour*> contourList;
    231     makeContourList(contours, contourList, xorMask == kEvenOdd_Mask,
    232             xorOpMask == kEvenOdd_Mask);
    233     Op::Contour** currentPtr = contourList.begin();
    234     if (!currentPtr) {
    235         return;
    236     }
    237     Op::Contour** listEnd = contourList.end();
    238     // find all intersections between segments
    239     do {
    240         Op::Contour** nextPtr = currentPtr;
    241         Op::Contour* current = *currentPtr++;
    242         if (current->containsCubics()) {
    243             addSelfIntersectTs(current);
    244         }
    245         Op::Contour* next;
    246         do {
    247             next = *nextPtr++;
    248         } while (addIntersectTs(current, next) && nextPtr != listEnd);
    249     } while (currentPtr != listEnd);
    250     // eat through coincident edges
    251 
    252     int total = 0;
    253     int index;
    254     for (index = 0; index < contourList.count(); ++index) {
    255         total += contourList[index]->segments().count();
    256     }
    257 #if DEBUG_SHOW_WINDING
    258     Op::Contour::debugShowWindingValues(contourList);
    259 #endif
    260     coincidenceCheck(contourList, total);
    261 #if DEBUG_SHOW_WINDING
    262     Op::Contour::debugShowWindingValues(contourList);
    263 #endif
    264     fixOtherTIndex(contourList);
    265     sortSegments(contourList);
    266 #if DEBUG_ACTIVE_SPANS
    267     debugShowActiveSpans(contourList);
    268 #endif
    269     // construct closed contours
    270     Op::PathWrapper wrapper(result);
    271     bridgeOp(contourList, op, xorMask, xorOpMask, wrapper);
    272     { // if some edges could not be resolved, assemble remaining fragments
    273         SkPath temp;
    274         temp.setFillType(SkPath::kEvenOdd_FillType);
    275         Op::PathWrapper assembled(temp);
    276         assemble(wrapper, assembled);
    277         result = *assembled.nativePath();
    278     }
    279 }
    280