Home | History | Annotate | Download | only in pathops
      1 /*
      2  * Copyright 2013 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 #ifndef SkOpContour_DEFINED
      8 #define SkOpContour_DEFINED
      9 
     10 #include "SkOpSegment.h"
     11 #include "SkTArray.h"
     12 
     13 class SkIntersections;
     14 class SkOpContour;
     15 class SkPathWriter;
     16 
     17 struct SkCoincidence {
     18     SkOpContour* fOther;
     19     int fSegments[2];
     20     double fTs[2][2];
     21     SkPoint fPts[2];
     22 };
     23 
     24 class SkOpContour {
     25 public:
     26     SkOpContour() {
     27         reset();
     28 #ifdef SK_DEBUG
     29         fID = ++SkPathOpsDebug::gContourID;
     30 #endif
     31     }
     32 
     33     bool operator<(const SkOpContour& rh) const {
     34         return fBounds.fTop == rh.fBounds.fTop
     35                 ? fBounds.fLeft < rh.fBounds.fLeft
     36                 : fBounds.fTop < rh.fBounds.fTop;
     37     }
     38 
     39     bool addCoincident(int index, SkOpContour* other, int otherIndex,
     40                        const SkIntersections& ts, bool swap);
     41     void addCoincidentPoints();
     42 
     43     void addCross(const SkOpContour* crosser) {
     44 #ifdef DEBUG_CROSS
     45         for (int index = 0; index < fCrosses.count(); ++index) {
     46             SkASSERT(fCrosses[index] != crosser);
     47         }
     48 #endif
     49         fCrosses.push_back(crosser);
     50     }
     51 
     52     void addCubic(const SkPoint pts[4]) {
     53         fSegments.push_back().addCubic(pts, fOperand, fXor);
     54         fContainsCurves = fContainsCubics = true;
     55     }
     56 
     57     int addLine(const SkPoint pts[2]) {
     58         fSegments.push_back().addLine(pts, fOperand, fXor);
     59         return fSegments.count();
     60     }
     61 
     62     void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
     63         fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
     64     }
     65 
     66     bool addPartialCoincident(int index, SkOpContour* other, int otherIndex,
     67                        const SkIntersections& ts, int ptIndex, bool swap);
     68 
     69     int addQuad(const SkPoint pts[3]) {
     70         fSegments.push_back().addQuad(pts, fOperand, fXor);
     71         fContainsCurves = true;
     72         return fSegments.count();
     73     }
     74 
     75     int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
     76         setContainsIntercepts();
     77         return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
     78     }
     79 
     80     int addSelfT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
     81         setContainsIntercepts();
     82         return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
     83     }
     84 
     85     const SkPathOpsBounds& bounds() const {
     86         return fBounds;
     87     }
     88 
     89     void calcCoincidentWinding();
     90     void calcPartialCoincidentWinding();
     91 
     92     void checkEnds() {
     93         if (!fContainsCurves) {
     94             return;
     95         }
     96         int segmentCount = fSegments.count();
     97         for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
     98             SkOpSegment* segment = &fSegments[sIndex];
     99             if (segment->verb() == SkPath::kLine_Verb) {
    100                 continue;
    101             }
    102             if (segment->done()) {
    103                 continue;   // likely coincident, nothing to do
    104             }
    105             segment->checkEnds();
    106         }
    107     }
    108 
    109     // if same point has different T values, choose a common T
    110     void checkTiny() {
    111         int segmentCount = fSegments.count();
    112         if (segmentCount <= 2) {
    113             return;
    114         }
    115         for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
    116             fSegments[sIndex].checkTiny();
    117         }
    118     }
    119 
    120     void complete() {
    121         setBounds();
    122         fContainsIntercepts = false;
    123     }
    124 
    125     bool containsCubics() const {
    126         return fContainsCubics;
    127     }
    128 
    129     bool crosses(const SkOpContour* crosser) const {
    130         for (int index = 0; index < fCrosses.count(); ++index) {
    131             if (fCrosses[index] == crosser) {
    132                 return true;
    133             }
    134         }
    135         return false;
    136     }
    137 
    138     bool done() const {
    139         return fDone;
    140     }
    141 
    142     const SkPoint& end() const {
    143         const SkOpSegment& segment = fSegments.back();
    144         return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
    145     }
    146 
    147     void fixOtherTIndex() {
    148         int segmentCount = fSegments.count();
    149         for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
    150             fSegments[sIndex].fixOtherTIndex();
    151         }
    152     }
    153 
    154     void joinCoincidence() {
    155         joinCoincidence(fCoincidences, false);
    156         joinCoincidence(fPartialCoincidences, true);
    157     }
    158 
    159     SkOpSegment* nonVerticalSegment(int* start, int* end);
    160 
    161     bool operand() const {
    162         return fOperand;
    163     }
    164 
    165     void reset() {
    166         fSegments.reset();
    167         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
    168         fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
    169     }
    170 
    171     SkTArray<SkOpSegment>& segments() {
    172         return fSegments;
    173     }
    174 
    175     void setContainsIntercepts() {
    176         fContainsIntercepts = true;
    177     }
    178 
    179     void setOperand(bool isOp) {
    180         fOperand = isOp;
    181     }
    182 
    183     void setOppXor(bool isOppXor) {
    184         fOppXor = isOppXor;
    185         int segmentCount = fSegments.count();
    186         for (int test = 0; test < segmentCount; ++test) {
    187             fSegments[test].setOppXor(isOppXor);
    188         }
    189     }
    190 
    191     void setXor(bool isXor) {
    192         fXor = isXor;
    193     }
    194 
    195     void sortSegments();
    196 
    197     const SkPoint& start() const {
    198         return fSegments.front().pts()[0];
    199     }
    200 
    201     void toPath(SkPathWriter* path) const;
    202 
    203     void toPartialBackward(SkPathWriter* path) const {
    204         int segmentCount = fSegments.count();
    205         for (int test = segmentCount - 1; test >= 0; --test) {
    206             fSegments[test].addCurveTo(1, 0, path, true);
    207         }
    208     }
    209 
    210     void toPartialForward(SkPathWriter* path) const {
    211         int segmentCount = fSegments.count();
    212         for (int test = 0; test < segmentCount; ++test) {
    213             fSegments[test].addCurveTo(0, 1, path, true);
    214         }
    215     }
    216 
    217     void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
    218     SkOpSegment* undoneSegment(int* start, int* end);
    219 
    220     int updateSegment(int index, const SkPoint* pts) {
    221         SkOpSegment& segment = fSegments[index];
    222         segment.updatePts(pts);
    223         return SkPathOpsVerbToPoints(segment.verb()) + 1;
    224     }
    225 
    226 #if DEBUG_TEST
    227     SkTArray<SkOpSegment>& debugSegments() {
    228         return fSegments;
    229     }
    230 #endif
    231 
    232 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
    233     void debugShowActiveSpans() {
    234         for (int index = 0; index < fSegments.count(); ++index) {
    235             fSegments[index].debugShowActiveSpans();
    236         }
    237     }
    238 #endif
    239 
    240 #if DEBUG_SHOW_WINDING
    241     int debugShowWindingValues(int totalSegments, int ofInterest);
    242     static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList);
    243 #endif
    244 
    245 private:
    246     void calcCommonCoincidentWinding(const SkCoincidence& );
    247     void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial);
    248     void setBounds();
    249 
    250     SkTArray<SkOpSegment> fSegments;
    251     SkTArray<SkOpSegment*, true> fSortedSegments;
    252     int fFirstSorted;
    253     SkTArray<SkCoincidence, true> fCoincidences;
    254     SkTArray<SkCoincidence, true> fPartialCoincidences;
    255     SkTArray<const SkOpContour*, true> fCrosses;
    256     SkPathOpsBounds fBounds;
    257     bool fContainsIntercepts;  // FIXME: is this used by anybody?
    258     bool fContainsCubics;
    259     bool fContainsCurves;
    260     bool fDone;
    261     bool fOperand;  // true for the second argument to a binary operator
    262     bool fXor;
    263     bool fOppXor;
    264 #ifdef SK_DEBUG
    265     int fID;
    266 #endif
    267 };
    268 
    269 #endif
    270