| /* |
| * Copyright 2014 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #ifndef SkPathOpsTSect_DEFINED |
| #define SkPathOpsTSect_DEFINED |
| |
| #include "include/private/SkMacros.h" |
| #include "src/core/SkArenaAlloc.h" |
| #include "src/pathops/SkIntersections.h" |
| #include "src/pathops/SkPathOpsBounds.h" |
| #include "src/pathops/SkPathOpsRect.h" |
| #include "src/pathops/SkPathOpsTCurve.h" |
| |
| #include <utility> |
| |
| #ifdef SK_DEBUG |
| typedef uint8_t SkOpDebugBool; |
| #else |
| typedef bool SkOpDebugBool; |
| #endif |
| |
| static inline bool SkDoubleIsNaN(double x) { |
| return x != x; |
| } |
| |
| class SkTCoincident { |
| public: |
| SkTCoincident() { |
| this->init(); |
| } |
| |
| void debugInit() { |
| #ifdef SK_DEBUG |
| this->fPerpPt.fX = this->fPerpPt.fY = SK_ScalarNaN; |
| this->fPerpT = SK_ScalarNaN; |
| this->fMatch = 0xFF; |
| #endif |
| } |
| |
| char dumpIsCoincidentStr() const; |
| void dump() const; |
| |
| bool isMatch() const { |
| SkASSERT(!!fMatch == fMatch); |
| return SkToBool(fMatch); |
| } |
| |
| void init() { |
| fPerpT = -1; |
| fMatch = false; |
| fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN; |
| } |
| |
| void markCoincident() { |
| if (!fMatch) { |
| fPerpT = -1; |
| } |
| fMatch = true; |
| } |
| |
| const SkDPoint& perpPt() const { |
| return fPerpPt; |
| } |
| |
| double perpT() const { |
| return fPerpT; |
| } |
| |
| void setPerp(const SkTCurve& c1, double t, const SkDPoint& cPt, const SkTCurve& ); |
| |
| private: |
| SkDPoint fPerpPt; |
| double fPerpT; // perpendicular intersection on opposite curve |
| SkOpDebugBool fMatch; |
| }; |
| |
| class SkTSect; |
| class SkTSpan; |
| |
| struct SkTSpanBounded { |
| SkTSpan* fBounded; |
| SkTSpanBounded* fNext; |
| }; |
| |
| class SkTSpan { |
| public: |
| SkTSpan(const SkTCurve& curve, SkArenaAlloc& heap) { |
| fPart = curve.make(heap); |
| } |
| |
| void addBounded(SkTSpan* , SkArenaAlloc* ); |
| double closestBoundedT(const SkDPoint& pt) const; |
| bool contains(double t) const; |
| |
| void debugInit(const SkTCurve& curve, SkArenaAlloc& heap) { |
| #ifdef SK_DEBUG |
| SkTCurve* fake = curve.make(heap); |
| fake->debugInit(); |
| init(*fake); |
| initBounds(*fake); |
| fCoinStart.init(); |
| fCoinEnd.init(); |
| #endif |
| } |
| |
| const SkTSect* debugOpp() const; |
| |
| #ifdef SK_DEBUG |
| void debugSetGlobalState(SkOpGlobalState* state) { |
| fDebugGlobalState = state; |
| } |
| |
| const SkTSpan* debugSpan(int ) const; |
| const SkTSpan* debugT(double t) const; |
| bool debugIsBefore(const SkTSpan* span) const; |
| #endif |
| void dump() const; |
| void dumpAll() const; |
| void dumpBounded(int id) const; |
| void dumpBounds() const; |
| void dumpCoin() const; |
| |
| double endT() const { |
| return fEndT; |
| } |
| |
| SkTSpan* findOppSpan(const SkTSpan* opp) const; |
| |
| SkTSpan* findOppT(double t) const { |
| SkTSpan* result = oppT(t); |
| SkOPASSERT(result); |
| return result; |
| } |
| |
| SkDEBUGCODE(SkOpGlobalState* globalState() const { return fDebugGlobalState; }) |
| |
| bool hasOppT(double t) const { |
| return SkToBool(oppT(t)); |
| } |
| |
| int hullsIntersect(SkTSpan* span, bool* start, bool* oppStart); |
| void init(const SkTCurve& ); |
| bool initBounds(const SkTCurve& ); |
| |
| bool isBounded() const { |
| return fBounded != nullptr; |
| } |
| |
| bool linearsIntersect(SkTSpan* span); |
| double linearT(const SkDPoint& ) const; |
| |
| void markCoincident() { |
| fCoinStart.markCoincident(); |
| fCoinEnd.markCoincident(); |
| } |
| |
| const SkTSpan* next() const { |
| return fNext; |
| } |
| |
| bool onlyEndPointsInCommon(const SkTSpan* opp, bool* start, |
| bool* oppStart, bool* ptsInCommon); |
| |
| const SkTCurve& part() const { |
| return *fPart; |
| } |
| |
| int pointCount() const { |
| return fPart->pointCount(); |
| } |
| |
| const SkDPoint& pointFirst() const { |
| return (*fPart)[0]; |
| } |
| |
| const SkDPoint& pointLast() const { |
| return (*fPart)[fPart->pointLast()]; |
| } |
| |
| bool removeAllBounded(); |
| bool removeBounded(const SkTSpan* opp); |
| |
| void reset() { |
| fBounded = nullptr; |
| } |
| |
| void resetBounds(const SkTCurve& curve) { |
| fIsLinear = fIsLine = false; |
| initBounds(curve); |
| } |
| |
| bool split(SkTSpan* work, SkArenaAlloc* heap) { |
| return splitAt(work, (work->fStartT + work->fEndT) * 0.5, heap); |
| } |
| |
| bool splitAt(SkTSpan* work, double t, SkArenaAlloc* heap); |
| |
| double startT() const { |
| return fStartT; |
| } |
| |
| private: |
| |
| // implementation is for testing only |
| int debugID() const { |
| return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); |
| } |
| |
| void dumpID() const; |
| |
| int hullCheck(const SkTSpan* opp, bool* start, bool* oppStart); |
| int linearIntersects(const SkTCurve& ) const; |
| SkTSpan* oppT(double t) const; |
| |
| void validate() const; |
| void validateBounded() const; |
| void validatePerpT(double oppT) const; |
| void validatePerpPt(double t, const SkDPoint& ) const; |
| |
| SkTCurve* fPart; |
| SkTCoincident fCoinStart; |
| SkTCoincident fCoinEnd; |
| SkTSpanBounded* fBounded; |
| SkTSpan* fPrev; |
| SkTSpan* fNext; |
| SkDRect fBounds; |
| double fStartT; |
| double fEndT; |
| double fBoundsMax; |
| SkOpDebugBool fCollapsed; |
| SkOpDebugBool fHasPerp; |
| SkOpDebugBool fIsLinear; |
| SkOpDebugBool fIsLine; |
| SkOpDebugBool fDeleted; |
| SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); |
| SkDEBUGCODE(SkTSect* fDebugSect); |
| PATH_OPS_DEBUG_T_SECT_CODE(int fID); |
| friend class SkTSect; |
| }; |
| |
| class SkTSect { |
| public: |
| SkTSect(const SkTCurve& c |
| SkDEBUGPARAMS(SkOpGlobalState* ) PATH_OPS_DEBUG_T_SECT_PARAMS(int id)); |
| static void BinarySearch(SkTSect* sect1, SkTSect* sect2, |
| SkIntersections* intersections); |
| |
| SkDEBUGCODE(SkOpGlobalState* globalState() { return fDebugGlobalState; }) |
| bool hasBounded(const SkTSpan* ) const; |
| |
| const SkTSect* debugOpp() const { |
| return SkDEBUGRELEASE(fOppSect, nullptr); |
| } |
| |
| #ifdef SK_DEBUG |
| const SkTSpan* debugSpan(int id) const; |
| const SkTSpan* debugT(double t) const; |
| #endif |
| void dump() const; |
| void dumpBoth(SkTSect* ) const; |
| void dumpBounded(int id) const; |
| void dumpBounds() const; |
| void dumpCoin() const; |
| void dumpCoinCurves() const; |
| void dumpCurves() const; |
| |
| private: |
| enum { |
| kZeroS1Set = 1, |
| kOneS1Set = 2, |
| kZeroS2Set = 4, |
| kOneS2Set = 8 |
| }; |
| |
| SkTSpan* addFollowing(SkTSpan* prior); |
| void addForPerp(SkTSpan* span, double t); |
| SkTSpan* addOne(); |
| |
| SkTSpan* addSplitAt(SkTSpan* span, double t) { |
| SkTSpan* result = this->addOne(); |
| SkDEBUGCODE(result->debugSetGlobalState(this->globalState())); |
| result->splitAt(span, t, &fHeap); |
| result->initBounds(fCurve); |
| span->initBounds(fCurve); |
| return result; |
| } |
| |
| bool binarySearchCoin(SkTSect* , double tStart, double tStep, double* t, |
| double* oppT, SkTSpan** oppFirst); |
| SkTSpan* boundsMax(); |
| bool coincidentCheck(SkTSect* sect2); |
| void coincidentForce(SkTSect* sect2, double start1s, double start1e); |
| bool coincidentHasT(double t); |
| int collapsed() const; |
| void computePerpendiculars(SkTSect* sect2, SkTSpan* first, |
| SkTSpan* last); |
| int countConsecutiveSpans(SkTSpan* first, |
| SkTSpan** last) const; |
| |
| int debugID() const { |
| return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); |
| } |
| |
| bool deleteEmptySpans(); |
| void dumpCommon(const SkTSpan* ) const; |
| void dumpCommonCurves(const SkTSpan* ) const; |
| static int EndsEqual(const SkTSect* sect1, const SkTSect* sect2, |
| SkIntersections* ); |
| bool extractCoincident(SkTSect* sect2, SkTSpan* first, |
| SkTSpan* last, SkTSpan** result); |
| SkTSpan* findCoincidentRun(SkTSpan* first, SkTSpan** lastPtr); |
| int intersects(SkTSpan* span, SkTSect* opp, |
| SkTSpan* oppSpan, int* oppResult); |
| bool isParallel(const SkDLine& thisLine, const SkTSect* opp) const; |
| int linesIntersect(SkTSpan* span, SkTSect* opp, |
| SkTSpan* oppSpan, SkIntersections* ); |
| bool markSpanGone(SkTSpan* span); |
| bool matchedDirection(double t, const SkTSect* sect2, double t2) const; |
| void matchedDirCheck(double t, const SkTSect* sect2, double t2, |
| bool* calcMatched, bool* oppMatched) const; |
| void mergeCoincidence(SkTSect* sect2); |
| |
| const SkDPoint& pointLast() const { |
| return fCurve[fCurve.pointLast()]; |
| } |
| |
| SkTSpan* prev(SkTSpan* ) const; |
| bool removeByPerpendicular(SkTSect* opp); |
| void recoverCollapsed(); |
| bool removeCoincident(SkTSpan* span, bool isBetween); |
| void removeAllBut(const SkTSpan* keep, SkTSpan* span, |
| SkTSect* opp); |
| bool removeSpan(SkTSpan* span); |
| void removeSpanRange(SkTSpan* first, SkTSpan* last); |
| bool removeSpans(SkTSpan* span, SkTSect* opp); |
| void removedEndCheck(SkTSpan* span); |
| |
| void resetRemovedEnds() { |
| fRemovedStartT = fRemovedEndT = false; |
| } |
| |
| SkTSpan* spanAtT(double t, SkTSpan** priorSpan); |
| SkTSpan* tail(); |
| bool trim(SkTSpan* span, SkTSect* opp); |
| bool unlinkSpan(SkTSpan* span); |
| bool updateBounded(SkTSpan* first, SkTSpan* last, |
| SkTSpan* oppFirst); |
| void validate() const; |
| void validateBounded() const; |
| |
| const SkTCurve& fCurve; |
| SkSTArenaAlloc<1024> fHeap; |
| SkTSpan* fHead; |
| SkTSpan* fCoincident; |
| SkTSpan* fDeleted; |
| int fActiveCount; |
| bool fRemovedStartT; |
| bool fRemovedEndT; |
| bool fHung; |
| SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); |
| SkDEBUGCODE(SkTSect* fOppSect); |
| PATH_OPS_DEBUG_T_SECT_CODE(int fID); |
| PATH_OPS_DEBUG_T_SECT_CODE(int fDebugCount); |
| #if DEBUG_T_SECT |
| int fDebugAllocatedCount; |
| #endif |
| friend class SkTSpan; |
| }; |
| |
| #endif |