caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 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 | */ |
deanm | 12670eb | 2016-04-26 14:09:01 -0700 | [diff] [blame] | 7 | #ifndef SkPathOpsTSect_DEFINED |
| 8 | #define SkPathOpsTSect_DEFINED |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 9 | |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 10 | #include "SkArenaAlloc.h" |
Hal Canary | 50dbc09 | 2018-06-12 14:50:37 -0400 | [diff] [blame] | 11 | #include "SkIntersections.h" |
| 12 | #include "SkMacros.h" |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 13 | #include "SkPathOpsBounds.h" |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 14 | #include "SkPathOpsRect.h" |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 15 | #include "SkTSort.h" |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 16 | |
Ben Wagner | f08d1d0 | 2018-06-18 15:11:00 -0400 | [diff] [blame] | 17 | #include <utility> |
| 18 | |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 19 | #ifdef SK_DEBUG |
| 20 | typedef uint8_t SkOpDebugBool; |
| 21 | #else |
| 22 | typedef bool SkOpDebugBool; |
| 23 | #endif |
| 24 | |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 25 | static inline bool SkDoubleIsNaN(double x) { |
| 26 | return x != x; |
| 27 | } |
| 28 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 29 | /* TCurve and OppCurve are one of { SkDQuadratic, SkDConic, SkDCubic } */ |
| 30 | template<typename TCurve, typename OppCurve> |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 31 | class SkTCoincident { |
| 32 | public: |
caryclark | 697ac1c | 2015-04-13 09:36:01 -0700 | [diff] [blame] | 33 | SkTCoincident() { |
caryclark | df386c5 | 2015-04-21 05:27:02 -0700 | [diff] [blame] | 34 | this->init(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 35 | } |
| 36 | |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 37 | void debugInit() { |
| 38 | #ifdef SK_DEBUG |
| 39 | this->fPerpPt.fX = this->fPerpPt.fY = SK_ScalarNaN; |
| 40 | this->fPerpT = SK_ScalarNaN; |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 41 | this->fMatch = 0xFF; |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 42 | #endif |
| 43 | } |
| 44 | |
| 45 | char dumpIsCoincidentStr() const; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 46 | void dump() const; |
| 47 | |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 48 | bool isMatch() const { |
| 49 | SkASSERT(!!fMatch == fMatch); |
| 50 | return SkToBool(fMatch); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 51 | } |
| 52 | |
| 53 | void init() { |
caryclark | df386c5 | 2015-04-21 05:27:02 -0700 | [diff] [blame] | 54 | fPerpT = -1; |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 55 | fMatch = false; |
caryclark | df386c5 | 2015-04-21 05:27:02 -0700 | [diff] [blame] | 56 | fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 57 | } |
| 58 | |
| 59 | void markCoincident() { |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 60 | if (!fMatch) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 61 | fPerpT = -1; |
| 62 | } |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 63 | fMatch = true; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | const SkDPoint& perpPt() const { |
| 67 | return fPerpPt; |
| 68 | } |
| 69 | |
| 70 | double perpT() const { |
| 71 | return fPerpT; |
| 72 | } |
| 73 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 74 | void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve& ); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 75 | |
| 76 | private: |
| 77 | SkDPoint fPerpPt; |
| 78 | double fPerpT; // perpendicular intersection on opposite curve |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 79 | SkOpDebugBool fMatch; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 80 | }; |
| 81 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 82 | template<typename TCurve, typename OppCurve> class SkTSect; |
| 83 | template<typename TCurve, typename OppCurve> class SkTSpan; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 84 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 85 | template<typename TCurve, typename OppCurve> |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 86 | struct SkTSpanBounded { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 87 | SkTSpan<TCurve, OppCurve>* fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 88 | SkTSpanBounded* fNext; |
| 89 | }; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 90 | |
| 91 | /* Curve is either TCurve or SkDCubic */ |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 92 | template<typename TCurve, typename OppCurve> |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 93 | class SkTSpan { |
| 94 | public: |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 95 | void addBounded(SkTSpan<OppCurve, TCurve>* , SkArenaAlloc* ); |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 96 | double closestBoundedT(const SkDPoint& pt) const; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 97 | bool contains(double t) const; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 98 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 99 | void debugInit() { |
| 100 | TCurve dummy; |
| 101 | dummy.debugInit(); |
| 102 | init(dummy); |
| 103 | initBounds(dummy); |
caryclark | df386c5 | 2015-04-21 05:27:02 -0700 | [diff] [blame] | 104 | fCoinStart.init(); |
| 105 | fCoinEnd.init(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | const SkTSect<OppCurve, TCurve>* debugOpp() const; |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 109 | |
| 110 | #ifdef SK_DEBUG |
| 111 | void debugSetGlobalState(SkOpGlobalState* state) { |
| 112 | fDebugGlobalState = state; |
| 113 | } |
| 114 | #endif |
| 115 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 116 | const SkTSpan* debugSpan(int ) const; |
| 117 | const SkTSpan* debugT(double t) const; |
| 118 | #ifdef SK_DEBUG |
| 119 | bool debugIsBefore(const SkTSpan* span) const; |
| 120 | #endif |
| 121 | void dump() const; |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 122 | void dumpAll() const; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 123 | void dumpBounded(int id) const; |
| 124 | void dumpBounds() const; |
| 125 | void dumpCoin() const; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 126 | |
| 127 | double endT() const { |
| 128 | return fEndT; |
| 129 | } |
| 130 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 131 | SkTSpan<OppCurve, TCurve>* findOppSpan(const SkTSpan<OppCurve, TCurve>* opp) const; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 132 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 133 | SkTSpan<OppCurve, TCurve>* findOppT(double t) const { |
| 134 | SkTSpan<OppCurve, TCurve>* result = oppT(t); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 135 | SkOPASSERT(result); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 136 | return result; |
| 137 | } |
| 138 | |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 139 | SkDEBUGCODE(SkOpGlobalState* globalState() const { return fDebugGlobalState; }) |
| 140 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 141 | bool hasOppT(double t) const { |
| 142 | return SkToBool(oppT(t)); |
| 143 | } |
| 144 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 145 | int hullsIntersect(SkTSpan<OppCurve, TCurve>* span, bool* start, bool* oppStart); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 146 | void init(const TCurve& ); |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 147 | bool initBounds(const TCurve& ); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 148 | |
| 149 | bool isBounded() const { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 150 | return fBounded != nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 151 | } |
| 152 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 153 | bool linearsIntersect(SkTSpan<OppCurve, TCurve>* span); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 154 | double linearT(const SkDPoint& ) const; |
| 155 | |
| 156 | void markCoincident() { |
| 157 | fCoinStart.markCoincident(); |
| 158 | fCoinEnd.markCoincident(); |
| 159 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 160 | |
| 161 | const SkTSpan* next() const { |
| 162 | return fNext; |
| 163 | } |
| 164 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 165 | bool onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, bool* start, |
| 166 | bool* oppStart, bool* ptsInCommon); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 167 | |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 168 | const TCurve& part() const { |
| 169 | return fPart; |
| 170 | } |
| 171 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 172 | bool removeAllBounded(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 173 | bool removeBounded(const SkTSpan<OppCurve, TCurve>* opp); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 174 | |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 175 | void reset() { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 176 | fBounded = nullptr; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 177 | } |
| 178 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 179 | void resetBounds(const TCurve& curve) { |
| 180 | fIsLinear = fIsLine = false; |
| 181 | initBounds(curve); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 182 | } |
| 183 | |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 184 | bool split(SkTSpan* work, SkArenaAlloc* heap) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 185 | return splitAt(work, (work->fStartT + work->fEndT) * 0.5, heap); |
| 186 | } |
| 187 | |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 188 | bool splitAt(SkTSpan* work, double t, SkArenaAlloc* heap); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 189 | |
| 190 | double startT() const { |
| 191 | return fStartT; |
| 192 | } |
| 193 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 194 | private: |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 195 | |
| 196 | // implementation is for testing only |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 197 | int debugID() const { |
| 198 | return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 199 | } |
| 200 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 201 | void dumpID() const; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 202 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 203 | int hullCheck(const SkTSpan<OppCurve, TCurve>* opp, bool* start, bool* oppStart); |
| 204 | int linearIntersects(const OppCurve& ) const; |
| 205 | SkTSpan<OppCurve, TCurve>* oppT(double t) const; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 206 | |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 207 | void validate() const; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 208 | void validateBounded() const; |
| 209 | void validatePerpT(double oppT) const; |
| 210 | void validatePerpPt(double t, const SkDPoint& ) const; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 211 | |
| 212 | TCurve fPart; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 213 | SkTCoincident<TCurve, OppCurve> fCoinStart; |
| 214 | SkTCoincident<TCurve, OppCurve> fCoinEnd; |
| 215 | SkTSpanBounded<OppCurve, TCurve>* fBounded; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 216 | SkTSpan* fPrev; |
| 217 | SkTSpan* fNext; |
| 218 | SkDRect fBounds; |
| 219 | double fStartT; |
| 220 | double fEndT; |
| 221 | double fBoundsMax; |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 222 | SkOpDebugBool fCollapsed; |
| 223 | SkOpDebugBool fHasPerp; |
| 224 | SkOpDebugBool fIsLinear; |
| 225 | SkOpDebugBool fIsLine; |
| 226 | SkOpDebugBool fDeleted; |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 227 | SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); |
csmartdalton | ceeaa78 | 2016-08-10 10:07:57 -0700 | [diff] [blame] | 228 | SkDEBUGCODE(SkTSect<TCurve, OppCurve>* fDebugSect); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 229 | PATH_OPS_DEBUG_T_SECT_CODE(int fID); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 230 | friend class SkTSect<TCurve, OppCurve>; |
| 231 | friend class SkTSect<OppCurve, TCurve>; |
| 232 | friend class SkTSpan<OppCurve, TCurve>; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 233 | }; |
| 234 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 235 | template<typename TCurve, typename OppCurve> |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 236 | class SkTSect { |
| 237 | public: |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 238 | SkTSect(const TCurve& c SkDEBUGPARAMS(SkOpGlobalState* ) PATH_OPS_DEBUG_T_SECT_PARAMS(int id)); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 239 | static void BinarySearch(SkTSect* sect1, SkTSect<OppCurve, TCurve>* sect2, |
| 240 | SkIntersections* intersections); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 241 | |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 242 | SkDEBUGCODE(SkOpGlobalState* globalState() { return fDebugGlobalState; }) |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 243 | bool hasBounded(const SkTSpan<OppCurve, TCurve>* ) const; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 244 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 245 | const SkTSect<OppCurve, TCurve>* debugOpp() const { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 246 | return SkDEBUGRELEASE(fOppSect, nullptr); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 247 | } |
| 248 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 249 | const SkTSpan<TCurve, OppCurve>* debugSpan(int id) const; |
| 250 | const SkTSpan<TCurve, OppCurve>* debugT(double t) const; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 251 | void dump() const; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 252 | void dumpBoth(SkTSect<OppCurve, TCurve>* ) const; |
| 253 | void dumpBounded(int id) const; |
| 254 | void dumpBounds() const; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 255 | void dumpCoin() const; |
| 256 | void dumpCoinCurves() const; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 257 | void dumpCurves() const; |
| 258 | |
| 259 | private: |
| 260 | enum { |
| 261 | kZeroS1Set = 1, |
| 262 | kOneS1Set = 2, |
| 263 | kZeroS2Set = 4, |
| 264 | kOneS2Set = 8 |
| 265 | }; |
| 266 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 267 | SkTSpan<TCurve, OppCurve>* addFollowing(SkTSpan<TCurve, OppCurve>* prior); |
| 268 | void addForPerp(SkTSpan<OppCurve, TCurve>* span, double t); |
| 269 | SkTSpan<TCurve, OppCurve>* addOne(); |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 270 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 271 | SkTSpan<TCurve, OppCurve>* addSplitAt(SkTSpan<TCurve, OppCurve>* span, double t) { |
| 272 | SkTSpan<TCurve, OppCurve>* result = this->addOne(); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 273 | SkDEBUGCODE(result->debugSetGlobalState(this->globalState())); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 274 | result->splitAt(span, t, &fHeap); |
| 275 | result->initBounds(fCurve); |
| 276 | span->initBounds(fCurve); |
| 277 | return result; |
| 278 | } |
| 279 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 280 | bool binarySearchCoin(SkTSect<OppCurve, TCurve>* , double tStart, double tStep, double* t, |
Cary Clark | 74b4290 | 2018-03-09 07:38:47 -0500 | [diff] [blame] | 281 | double* oppT, SkTSpan<OppCurve, TCurve>** oppFirst); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 282 | SkTSpan<TCurve, OppCurve>* boundsMax() const; |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 283 | bool coincidentCheck(SkTSect<OppCurve, TCurve>* sect2); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 284 | void coincidentForce(SkTSect<OppCurve, TCurve>* sect2, double start1s, double start1e); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 285 | bool coincidentHasT(double t); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 286 | int collapsed() const; |
| 287 | void computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first, |
| 288 | SkTSpan<TCurve, OppCurve>* last); |
| 289 | int countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first, |
| 290 | SkTSpan<TCurve, OppCurve>** last) const; |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 291 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 292 | int debugID() const { |
| 293 | return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); |
| 294 | } |
| 295 | |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 296 | bool deleteEmptySpans(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 297 | void dumpCommon(const SkTSpan<TCurve, OppCurve>* ) const; |
| 298 | void dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* ) const; |
| 299 | static int EndsEqual(const SkTSect* sect1, const SkTSect<OppCurve, TCurve>* sect2, |
| 300 | SkIntersections* ); |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 301 | bool extractCoincident(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first, |
| 302 | SkTSpan<TCurve, OppCurve>* last, SkTSpan<TCurve, OppCurve>** result); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 303 | SkTSpan<TCurve, OppCurve>* findCoincidentRun(SkTSpan<TCurve, OppCurve>* first, |
| 304 | SkTSpan<TCurve, OppCurve>** lastPtr); |
| 305 | int intersects(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp, |
| 306 | SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult); |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 307 | bool isParallel(const SkDLine& thisLine, const SkTSect<OppCurve, TCurve>* opp) const; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 308 | int linesIntersect(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp, |
| 309 | SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* ); |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 310 | bool markSpanGone(SkTSpan<TCurve, OppCurve>* span); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 311 | bool matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2) const; |
| 312 | void matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2, |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 313 | bool* calcMatched, bool* oppMatched) const; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 314 | void mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2); |
| 315 | SkTSpan<TCurve, OppCurve>* prev(SkTSpan<TCurve, OppCurve>* ) const; |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 316 | bool removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 317 | void recoverCollapsed(); |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 318 | bool removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 319 | void removeAllBut(const SkTSpan<OppCurve, TCurve>* keep, SkTSpan<TCurve, OppCurve>* span, |
| 320 | SkTSect<OppCurve, TCurve>* opp); |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 321 | bool removeSpan(SkTSpan<TCurve, OppCurve>* span); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 322 | void removeSpanRange(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last); |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 323 | bool removeSpans(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 324 | void removedEndCheck(SkTSpan<TCurve, OppCurve>* span); |
| 325 | |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 326 | void resetRemovedEnds() { |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 327 | fRemovedStartT = fRemovedEndT = false; |
| 328 | } |
| 329 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 330 | SkTSpan<TCurve, OppCurve>* spanAtT(double t, SkTSpan<TCurve, OppCurve>** priorSpan); |
| 331 | SkTSpan<TCurve, OppCurve>* tail(); |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 332 | bool trim(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 333 | bool unlinkSpan(SkTSpan<TCurve, OppCurve>* span); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 334 | bool updateBounded(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last, |
| 335 | SkTSpan<OppCurve, TCurve>* oppFirst); |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 336 | void validate() const; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 337 | void validateBounded() const; |
| 338 | |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 339 | const TCurve& fCurve; |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 340 | SkArenaAlloc fHeap; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 341 | SkTSpan<TCurve, OppCurve>* fHead; |
| 342 | SkTSpan<TCurve, OppCurve>* fCoincident; |
| 343 | SkTSpan<TCurve, OppCurve>* fDeleted; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 344 | int fActiveCount; |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 345 | bool fRemovedStartT; |
| 346 | bool fRemovedEndT; |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 347 | SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); |
csmartdalton | ceeaa78 | 2016-08-10 10:07:57 -0700 | [diff] [blame] | 348 | SkDEBUGCODE(SkTSect<OppCurve, TCurve>* fOppSect); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 349 | PATH_OPS_DEBUG_T_SECT_CODE(int fID); |
| 350 | PATH_OPS_DEBUG_T_SECT_CODE(int fDebugCount); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 351 | #if DEBUG_T_SECT |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 352 | int fDebugAllocatedCount; |
| 353 | #endif |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 354 | friend class SkTSpan<TCurve, OppCurve>; |
| 355 | friend class SkTSpan<OppCurve, TCurve>; |
| 356 | friend class SkTSect<OppCurve, TCurve>; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 357 | }; |
| 358 | |
| 359 | #define COINCIDENT_SPAN_COUNT 9 |
| 360 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 361 | template<typename TCurve, typename OppCurve> |
| 362 | void SkTCoincident<TCurve, OppCurve>::setPerp(const TCurve& c1, double t, |
| 363 | const SkDPoint& cPt, const OppCurve& c2) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 364 | SkDVector dxdy = c1.dxdyAtT(t); |
| 365 | SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 366 | SkIntersections i SkDEBUGCODE((c1.globalState())); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 367 | int used = i.intersectRay(c2, perp); |
| 368 | // only keep closest |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 369 | if (used == 0 || used == 3) { |
caryclark | df386c5 | 2015-04-21 05:27:02 -0700 | [diff] [blame] | 370 | this->init(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 371 | return; |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 372 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 373 | fPerpT = i[0][0]; |
| 374 | fPerpPt = i.pt(0); |
| 375 | SkASSERT(used <= 2); |
| 376 | if (used == 2) { |
| 377 | double distSq = (fPerpPt - cPt).lengthSquared(); |
| 378 | double dist2Sq = (i.pt(1) - cPt).lengthSquared(); |
| 379 | if (dist2Sq < distSq) { |
| 380 | fPerpT = i[0][1]; |
| 381 | fPerpPt = i.pt(1); |
| 382 | } |
| 383 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 384 | #if DEBUG_T_SECT |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 385 | SkDebugf("setPerp t=%1.9g cPt=(%1.9g,%1.9g) %s oppT=%1.9g fPerpPt=(%1.9g,%1.9g)\n", |
| 386 | t, cPt.fX, cPt.fY, |
| 387 | cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpT, fPerpPt.fX, fPerpPt.fY); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 388 | #endif |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 389 | fMatch = cPt.approximatelyEqual(fPerpPt); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 390 | #if DEBUG_T_SECT |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 391 | if (fMatch) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 392 | SkDebugf(""); // allow setting breakpoint |
| 393 | } |
| 394 | #endif |
| 395 | } |
| 396 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 397 | template<typename TCurve, typename OppCurve> |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 398 | void SkTSpan<TCurve, OppCurve>::addBounded(SkTSpan<OppCurve, TCurve>* span, SkArenaAlloc* heap) { |
| 399 | SkTSpanBounded<OppCurve, TCurve>* bounded = heap->make<SkTSpanBounded<OppCurve, TCurve>>(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 400 | bounded->fBounded = span; |
| 401 | bounded->fNext = fBounded; |
| 402 | fBounded = bounded; |
| 403 | } |
| 404 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 405 | template<typename TCurve, typename OppCurve> |
| 406 | SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addFollowing( |
| 407 | SkTSpan<TCurve, OppCurve>* prior) { |
| 408 | SkTSpan<TCurve, OppCurve>* result = this->addOne(); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 409 | SkDEBUGCODE(result->debugSetGlobalState(this->globalState())); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 410 | result->fStartT = prior ? prior->fEndT : 0; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 411 | SkTSpan<TCurve, OppCurve>* next = prior ? prior->fNext : fHead; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 412 | result->fEndT = next ? next->fStartT : 1; |
| 413 | result->fPrev = prior; |
| 414 | result->fNext = next; |
| 415 | if (prior) { |
| 416 | prior->fNext = result; |
| 417 | } else { |
| 418 | fHead = result; |
| 419 | } |
| 420 | if (next) { |
| 421 | next->fPrev = result; |
| 422 | } |
| 423 | result->resetBounds(fCurve); |
Cary Clark | b8421ed | 2018-03-14 15:55:02 -0400 | [diff] [blame] | 424 | // world may not be consistent to call validate here |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 425 | result->validate(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 426 | return result; |
| 427 | } |
| 428 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 429 | template<typename TCurve, typename OppCurve> |
| 430 | void SkTSect<TCurve, OppCurve>::addForPerp(SkTSpan<OppCurve, TCurve>* span, double t) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 431 | if (!span->hasOppT(t)) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 432 | SkTSpan<TCurve, OppCurve>* priorSpan; |
| 433 | SkTSpan<TCurve, OppCurve>* opp = this->spanAtT(t, &priorSpan); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 434 | if (!opp) { |
| 435 | opp = this->addFollowing(priorSpan); |
| 436 | #if DEBUG_PERP |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 437 | SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan ? |
| 438 | priorSpan->debugID() : -1, t, opp->debugID()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 439 | #endif |
| 440 | } |
| 441 | #if DEBUG_PERP |
| 442 | opp->dump(); SkDebugf("\n"); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 443 | SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan ? |
| 444 | priorSpan->debugID() : -1, opp->debugID()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 445 | #endif |
| 446 | opp->addBounded(span, &fHeap); |
| 447 | span->addBounded(opp, &fHeap); |
| 448 | } |
| 449 | this->validate(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 450 | #if DEBUG_T_SECT |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 451 | span->validatePerpT(t); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 452 | #endif |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 453 | } |
| 454 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 455 | template<typename TCurve, typename OppCurve> |
| 456 | double SkTSpan<TCurve, OppCurve>::closestBoundedT(const SkDPoint& pt) const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 457 | double result = -1; |
caryclark | 343382e | 2016-06-29 08:18:38 -0700 | [diff] [blame] | 458 | double closest = DBL_MAX; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 459 | const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 460 | while (testBounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 461 | const SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 462 | double startDist = test->fPart[0].distanceSquared(pt); |
| 463 | if (closest > startDist) { |
| 464 | closest = startDist; |
| 465 | result = test->fStartT; |
| 466 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 467 | double endDist = test->fPart[OppCurve::kPointLast].distanceSquared(pt); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 468 | if (closest > endDist) { |
| 469 | closest = endDist; |
| 470 | result = test->fEndT; |
| 471 | } |
| 472 | testBounded = testBounded->fNext; |
| 473 | } |
| 474 | SkASSERT(between(0, result, 1)); |
| 475 | return result; |
| 476 | } |
| 477 | |
| 478 | #ifdef SK_DEBUG |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 479 | template<typename TCurve, typename OppCurve> |
| 480 | bool SkTSpan<TCurve, OppCurve>::debugIsBefore(const SkTSpan* span) const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 481 | const SkTSpan* work = this; |
| 482 | do { |
| 483 | if (span == work) { |
| 484 | return true; |
| 485 | } |
| 486 | } while ((work = work->fNext)); |
| 487 | return false; |
| 488 | } |
| 489 | #endif |
| 490 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 491 | template<typename TCurve, typename OppCurve> |
| 492 | bool SkTSpan<TCurve, OppCurve>::contains(double t) const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 493 | const SkTSpan* work = this; |
| 494 | do { |
| 495 | if (between(work->fStartT, t, work->fEndT)) { |
| 496 | return true; |
| 497 | } |
| 498 | } while ((work = work->fNext)); |
| 499 | return false; |
| 500 | } |
| 501 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 502 | template<typename TCurve, typename OppCurve> |
| 503 | const SkTSect<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::debugOpp() const { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 504 | return SkDEBUGRELEASE(fDebugSect->debugOpp(), nullptr); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 505 | } |
| 506 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 507 | template<typename TCurve, typename OppCurve> |
| 508 | SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::findOppSpan( |
| 509 | const SkTSpan<OppCurve, TCurve>* opp) const { |
| 510 | SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 511 | while (bounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 512 | SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 513 | if (opp == test) { |
| 514 | return test; |
| 515 | } |
| 516 | bounded = bounded->fNext; |
| 517 | } |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 518 | return nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 519 | } |
| 520 | |
| 521 | // returns 0 if no hull intersection |
| 522 | // 1 if hulls intersect |
| 523 | // 2 if hulls only share a common endpoint |
| 524 | // -1 if linear and further checking is required |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 525 | template<typename TCurve, typename OppCurve> |
| 526 | int SkTSpan<TCurve, OppCurve>::hullCheck(const SkTSpan<OppCurve, TCurve>* opp, |
| 527 | bool* start, bool* oppStart) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 528 | if (fIsLinear) { |
| 529 | return -1; |
| 530 | } |
| 531 | bool ptsInCommon; |
| 532 | if (onlyEndPointsInCommon(opp, start, oppStart, &ptsInCommon)) { |
| 533 | SkASSERT(ptsInCommon); |
| 534 | return 2; |
| 535 | } |
| 536 | bool linear; |
| 537 | if (fPart.hullIntersects(opp->fPart, &linear)) { |
| 538 | if (!linear) { // check set true if linear |
| 539 | return 1; |
| 540 | } |
| 541 | fIsLinear = true; |
| 542 | fIsLine = fPart.controlsInside(); |
caryclark | 2bec26a | 2016-05-26 09:01:47 -0700 | [diff] [blame] | 543 | return ptsInCommon ? 1 : -1; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 544 | } else { // hull is not linear; check set true if intersected at the end points |
| 545 | return ((int) ptsInCommon) << 1; // 0 or 2 |
| 546 | } |
| 547 | return 0; |
| 548 | } |
| 549 | |
| 550 | // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear, |
| 551 | // use line intersection to guess a better split than 0.5 |
| 552 | // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all future splits are linear |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 553 | template<typename TCurve, typename OppCurve> |
| 554 | int SkTSpan<TCurve, OppCurve>::hullsIntersect(SkTSpan<OppCurve, TCurve>* opp, |
| 555 | bool* start, bool* oppStart) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 556 | if (!fBounds.intersects(opp->fBounds)) { |
| 557 | return 0; |
| 558 | } |
| 559 | int hullSect = this->hullCheck(opp, start, oppStart); |
| 560 | if (hullSect >= 0) { |
| 561 | return hullSect; |
| 562 | } |
| 563 | hullSect = opp->hullCheck(this, oppStart, start); |
| 564 | if (hullSect >= 0) { |
| 565 | return hullSect; |
| 566 | } |
| 567 | return -1; |
| 568 | } |
| 569 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 570 | template<typename TCurve, typename OppCurve> |
| 571 | void SkTSpan<TCurve, OppCurve>::init(const TCurve& c) { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 572 | fPrev = fNext = nullptr; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 573 | fStartT = 0; |
| 574 | fEndT = 1; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 575 | fBounded = nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 576 | resetBounds(c); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 577 | } |
| 578 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 579 | template<typename TCurve, typename OppCurve> |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 580 | bool SkTSpan<TCurve, OppCurve>::initBounds(const TCurve& c) { |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 581 | if (SkDoubleIsNaN(fStartT) || SkDoubleIsNaN(fEndT)) { |
| 582 | return false; |
| 583 | } |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 584 | fPart = c.subDivide(fStartT, fEndT); |
| 585 | fBounds.setBounds(fPart); |
| 586 | fCoinStart.init(); |
| 587 | fCoinEnd.init(); |
| 588 | fBoundsMax = SkTMax(fBounds.width(), fBounds.height()); |
| 589 | fCollapsed = fPart.collapsed(); |
| 590 | fHasPerp = false; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 591 | fDeleted = false; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 592 | #if DEBUG_T_SECT |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 593 | if (fCollapsed) { |
| 594 | SkDebugf(""); // for convenient breakpoints |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 595 | } |
| 596 | #endif |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 597 | return fBounds.valid(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 598 | } |
| 599 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 600 | template<typename TCurve, typename OppCurve> |
| 601 | bool SkTSpan<TCurve, OppCurve>::linearsIntersect(SkTSpan<OppCurve, TCurve>* span) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 602 | int result = this->linearIntersects(span->fPart); |
| 603 | if (result <= 1) { |
| 604 | return SkToBool(result); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 605 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 606 | SkASSERT(span->fIsLinear); |
| 607 | result = span->linearIntersects(this->fPart); |
| 608 | // SkASSERT(result <= 1); |
| 609 | return SkToBool(result); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 610 | } |
| 611 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 612 | template<typename TCurve, typename OppCurve> |
| 613 | double SkTSpan<TCurve, OppCurve>::linearT(const SkDPoint& pt) const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 614 | SkDVector len = fPart[TCurve::kPointLast] - fPart[0]; |
| 615 | return fabs(len.fX) > fabs(len.fY) |
| 616 | ? (pt.fX - fPart[0].fX) / len.fX |
| 617 | : (pt.fY - fPart[0].fY) / len.fY; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 618 | } |
| 619 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 620 | template<typename TCurve, typename OppCurve> |
| 621 | int SkTSpan<TCurve, OppCurve>::linearIntersects(const OppCurve& q2) const { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 622 | // looks like q1 is near-linear |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 623 | int start = 0, end = TCurve::kPointLast; // the outside points are usually the extremes |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 624 | if (!fPart.controlsInside()) { |
| 625 | double dist = 0; // if there's any question, compute distance to find best outsiders |
| 626 | for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) { |
| 627 | for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) { |
| 628 | double test = (fPart[outer] - fPart[inner]).lengthSquared(); |
| 629 | if (dist > test) { |
| 630 | continue; |
| 631 | } |
| 632 | dist = test; |
| 633 | start = outer; |
| 634 | end = inner; |
| 635 | } |
| 636 | } |
| 637 | } |
| 638 | // see if q2 is on one side of the line formed by the extreme points |
| 639 | double origX = fPart[start].fX; |
| 640 | double origY = fPart[start].fY; |
| 641 | double adj = fPart[end].fX - origX; |
| 642 | double opp = fPart[end].fY - origY; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 643 | double maxPart = SkTMax(fabs(adj), fabs(opp)); |
| 644 | double sign = 0; // initialization to shut up warning in release build |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 645 | for (int n = 0; n < OppCurve::kPointCount; ++n) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 646 | double dx = q2[n].fY - origY; |
| 647 | double dy = q2[n].fX - origX; |
| 648 | double maxVal = SkTMax(maxPart, SkTMax(fabs(dx), fabs(dy))); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 649 | double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 650 | if (precisely_zero_when_compared_to(test, maxVal)) { |
| 651 | return 1; |
| 652 | } |
| 653 | if (approximately_zero_when_compared_to(test, maxVal)) { |
| 654 | return 3; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 655 | } |
| 656 | if (n == 0) { |
| 657 | sign = test; |
| 658 | continue; |
| 659 | } |
| 660 | if (test * sign < 0) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 661 | return 1; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 662 | } |
| 663 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 664 | return 0; |
| 665 | } |
| 666 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 667 | template<typename TCurve, typename OppCurve> |
| 668 | bool SkTSpan<TCurve, OppCurve>::onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, |
| 669 | bool* start, bool* oppStart, bool* ptsInCommon) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 670 | if (opp->fPart[0] == fPart[0]) { |
| 671 | *start = *oppStart = true; |
| 672 | } else if (opp->fPart[0] == fPart[TCurve::kPointLast]) { |
| 673 | *start = false; |
| 674 | *oppStart = true; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 675 | } else if (opp->fPart[OppCurve::kPointLast] == fPart[0]) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 676 | *start = true; |
| 677 | *oppStart = false; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 678 | } else if (opp->fPart[OppCurve::kPointLast] == fPart[TCurve::kPointLast]) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 679 | *start = *oppStart = false; |
| 680 | } else { |
| 681 | *ptsInCommon = false; |
| 682 | return false; |
| 683 | } |
| 684 | *ptsInCommon = true; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 685 | const SkDPoint* otherPts[TCurve::kPointCount - 1], * oppOtherPts[OppCurve::kPointCount - 1]; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 686 | int baseIndex = *start ? 0 : TCurve::kPointLast; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 687 | fPart.otherPts(baseIndex, otherPts); |
| 688 | opp->fPart.otherPts(*oppStart ? 0 : OppCurve::kPointLast, oppOtherPts); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 689 | const SkDPoint& base = fPart[baseIndex]; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 690 | for (int o1 = 0; o1 < (int) SK_ARRAY_COUNT(otherPts); ++o1) { |
| 691 | SkDVector v1 = *otherPts[o1] - base; |
| 692 | for (int o2 = 0; o2 < (int) SK_ARRAY_COUNT(oppOtherPts); ++o2) { |
| 693 | SkDVector v2 = *oppOtherPts[o2] - base; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 694 | if (v2.dot(v1) >= 0) { |
| 695 | return false; |
| 696 | } |
| 697 | } |
| 698 | } |
| 699 | return true; |
| 700 | } |
| 701 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 702 | template<typename TCurve, typename OppCurve> |
| 703 | SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::oppT(double t) const { |
| 704 | SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 705 | while (bounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 706 | SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 707 | if (between(test->fStartT, t, test->fEndT)) { |
| 708 | return test; |
| 709 | } |
| 710 | bounded = bounded->fNext; |
| 711 | } |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 712 | return nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 713 | } |
| 714 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 715 | template<typename TCurve, typename OppCurve> |
| 716 | bool SkTSpan<TCurve, OppCurve>::removeAllBounded() { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 717 | bool deleteSpan = false; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 718 | SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 719 | while (bounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 720 | SkTSpan<OppCurve, TCurve>* opp = bounded->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 721 | deleteSpan |= opp->removeBounded(this); |
| 722 | bounded = bounded->fNext; |
| 723 | } |
| 724 | return deleteSpan; |
| 725 | } |
| 726 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 727 | template<typename TCurve, typename OppCurve> |
| 728 | bool SkTSpan<TCurve, OppCurve>::removeBounded(const SkTSpan<OppCurve, TCurve>* opp) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 729 | if (fHasPerp) { |
| 730 | bool foundStart = false; |
| 731 | bool foundEnd = false; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 732 | SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 733 | while (bounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 734 | SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 735 | if (opp != test) { |
| 736 | foundStart |= between(test->fStartT, fCoinStart.perpT(), test->fEndT); |
| 737 | foundEnd |= between(test->fStartT, fCoinEnd.perpT(), test->fEndT); |
| 738 | } |
| 739 | bounded = bounded->fNext; |
| 740 | } |
| 741 | if (!foundStart || !foundEnd) { |
| 742 | fHasPerp = false; |
| 743 | fCoinStart.init(); |
| 744 | fCoinEnd.init(); |
| 745 | } |
| 746 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 747 | SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 748 | SkTSpanBounded<OppCurve, TCurve>* prev = nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 749 | while (bounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 750 | SkTSpanBounded<OppCurve, TCurve>* boundedNext = bounded->fNext; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 751 | if (opp == bounded->fBounded) { |
| 752 | if (prev) { |
| 753 | prev->fNext = boundedNext; |
| 754 | return false; |
| 755 | } else { |
| 756 | fBounded = boundedNext; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 757 | return fBounded == nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 758 | } |
| 759 | } |
| 760 | prev = bounded; |
| 761 | bounded = boundedNext; |
| 762 | } |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 763 | SkOPASSERT(0); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 764 | return false; |
| 765 | } |
| 766 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 767 | template<typename TCurve, typename OppCurve> |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 768 | bool SkTSpan<TCurve, OppCurve>::splitAt(SkTSpan* work, double t, SkArenaAlloc* heap) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 769 | fStartT = t; |
| 770 | fEndT = work->fEndT; |
| 771 | if (fStartT == fEndT) { |
| 772 | fCollapsed = true; |
| 773 | return false; |
| 774 | } |
| 775 | work->fEndT = t; |
| 776 | if (work->fStartT == work->fEndT) { |
| 777 | work->fCollapsed = true; |
| 778 | return false; |
| 779 | } |
| 780 | fPrev = work; |
| 781 | fNext = work->fNext; |
| 782 | fIsLinear = work->fIsLinear; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 783 | fIsLine = work->fIsLine; |
| 784 | |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 785 | work->fNext = this; |
| 786 | if (fNext) { |
| 787 | fNext->fPrev = this; |
| 788 | } |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 789 | this->validate(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 790 | SkTSpanBounded<OppCurve, TCurve>* bounded = work->fBounded; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 791 | fBounded = nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 792 | while (bounded) { |
| 793 | this->addBounded(bounded->fBounded, heap); |
| 794 | bounded = bounded->fNext; |
| 795 | } |
| 796 | bounded = fBounded; |
| 797 | while (bounded) { |
| 798 | bounded->fBounded->addBounded(this, heap); |
| 799 | bounded = bounded->fNext; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 800 | } |
| 801 | return true; |
| 802 | } |
| 803 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 804 | template<typename TCurve, typename OppCurve> |
| 805 | void SkTSpan<TCurve, OppCurve>::validate() const { |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 806 | #if DEBUG_VALIDATE |
| 807 | SkASSERT(this != fPrev); |
| 808 | SkASSERT(this != fNext); |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 809 | SkASSERT(fNext == nullptr || fNext != fPrev); |
| 810 | SkASSERT(fNext == nullptr || this == fNext->fPrev); |
| 811 | SkASSERT(fPrev == nullptr || this == fPrev->fNext); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 812 | this->validateBounded(); |
| 813 | #endif |
| 814 | #if DEBUG_T_SECT |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 815 | SkASSERT(fBounds.width() || fBounds.height() || fCollapsed); |
caryclark | e839e78 | 2016-09-15 07:48:18 -0700 | [diff] [blame] | 816 | SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height()) || fCollapsed == 0xFF); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 817 | SkASSERT(0 <= fStartT); |
| 818 | SkASSERT(fEndT <= 1); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 819 | SkASSERT(fStartT <= fEndT); |
caryclark | e839e78 | 2016-09-15 07:48:18 -0700 | [diff] [blame] | 820 | SkASSERT(fBounded || fCollapsed == 0xFF); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 821 | if (fHasPerp) { |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 822 | if (fCoinStart.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 823 | validatePerpT(fCoinStart.perpT()); |
| 824 | validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt()); |
| 825 | } |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 826 | if (fCoinEnd.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 827 | validatePerpT(fCoinEnd.perpT()); |
| 828 | validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt()); |
| 829 | } |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 830 | } |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 831 | #endif |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 832 | } |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 833 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 834 | template<typename TCurve, typename OppCurve> |
| 835 | void SkTSpan<TCurve, OppCurve>::validateBounded() const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 836 | #if DEBUG_VALIDATE |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 837 | const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 838 | while (testBounded) { |
csmartdalton | ceeaa78 | 2016-08-10 10:07:57 -0700 | [diff] [blame] | 839 | SkDEBUGCODE(const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 840 | SkASSERT(!overlap->fDeleted); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 841 | #if DEBUG_T_SECT |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 842 | SkASSERT(((this->debugID() ^ overlap->debugID()) & 1) == 1); |
| 843 | SkASSERT(overlap->findOppSpan(this)); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 844 | #endif |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 845 | testBounded = testBounded->fNext; |
| 846 | } |
| 847 | #endif |
| 848 | } |
| 849 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 850 | template<typename TCurve, typename OppCurve> |
| 851 | void SkTSpan<TCurve, OppCurve>::validatePerpT(double oppT) const { |
| 852 | const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 853 | while (testBounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 854 | const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded; |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 855 | if (precisely_between(overlap->fStartT, oppT, overlap->fEndT)) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 856 | return; |
| 857 | } |
| 858 | testBounded = testBounded->fNext; |
| 859 | } |
| 860 | SkASSERT(0); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 861 | } |
| 862 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 863 | template<typename TCurve, typename OppCurve> |
| 864 | void SkTSpan<TCurve, OppCurve>::validatePerpPt(double t, const SkDPoint& pt) const { |
| 865 | SkASSERT(fDebugSect->fOppSect->fCurve.ptAtT(t) == pt); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 866 | } |
| 867 | |
| 868 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 869 | template<typename TCurve, typename OppCurve> |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 870 | SkTSect<TCurve, OppCurve>::SkTSect(const TCurve& c |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 871 | SkDEBUGPARAMS(SkOpGlobalState* debugGlobalState) |
| 872 | PATH_OPS_DEBUG_T_SECT_PARAMS(int id)) |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 873 | : fCurve(c) |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 874 | , fHeap(sizeof(SkTSpan<TCurve, OppCurve>) * 4) |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 875 | , fCoincident(nullptr) |
| 876 | , fDeleted(nullptr) |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 877 | , fActiveCount(0) |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 878 | SkDEBUGPARAMS(fDebugGlobalState(debugGlobalState)) |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 879 | PATH_OPS_DEBUG_T_SECT_PARAMS(fID(id)) |
| 880 | PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0)) |
| 881 | PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0)) |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 882 | { |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 883 | this->resetRemovedEnds(); |
| 884 | fHead = this->addOne(); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 885 | SkDEBUGCODE(fHead->debugSetGlobalState(debugGlobalState)); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 886 | fHead->init(c); |
| 887 | } |
| 888 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 889 | template<typename TCurve, typename OppCurve> |
| 890 | SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addOne() { |
| 891 | SkTSpan<TCurve, OppCurve>* result; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 892 | if (fDeleted) { |
| 893 | result = fDeleted; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 894 | fDeleted = result->fNext; |
| 895 | } else { |
Herb Derby | c3cc5fa | 2017-03-07 11:11:47 -0500 | [diff] [blame] | 896 | result = fHeap.make<SkTSpan<TCurve, OppCurve>>(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 897 | #if DEBUG_T_SECT |
| 898 | ++fDebugAllocatedCount; |
| 899 | #endif |
| 900 | } |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 901 | result->reset(); |
caryclark | 08b3249 | 2015-04-06 11:41:29 -0700 | [diff] [blame] | 902 | result->fHasPerp = false; |
| 903 | result->fDeleted = false; |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 904 | ++fActiveCount; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 905 | PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 906 | SkDEBUGCODE(result->fDebugSect = this); |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 907 | #ifdef SK_DEBUG |
| 908 | result->fPart.debugInit(); |
| 909 | result->fCoinStart.debugInit(); |
| 910 | result->fCoinEnd.debugInit(); |
| 911 | result->fPrev = result->fNext = nullptr; |
| 912 | result->fBounds.debugInit(); |
| 913 | result->fStartT = result->fEndT = result->fBoundsMax = SK_ScalarNaN; |
| 914 | result->fCollapsed = result->fIsLinear = result->fIsLine = 0xFF; |
| 915 | #endif |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 916 | return result; |
| 917 | } |
| 918 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 919 | template<typename TCurve, typename OppCurve> |
| 920 | bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect2, double tStart, |
Cary Clark | 74b4290 | 2018-03-09 07:38:47 -0500 | [diff] [blame] | 921 | double tStep, double* resultT, double* oppT, SkTSpan<OppCurve, TCurve>** oppFirst) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 922 | SkTSpan<TCurve, OppCurve> work; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 923 | double result = work.fStartT = work.fEndT = tStart; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 924 | SkDEBUGCODE(work.fDebugSect = this); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 925 | SkDPoint last = fCurve.ptAtT(tStart); |
| 926 | SkDPoint oppPt; |
| 927 | bool flip = false; |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 928 | bool contained = false; |
Cary Clark | 74b4290 | 2018-03-09 07:38:47 -0500 | [diff] [blame] | 929 | bool down = tStep < 0; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 930 | const OppCurve& opp = sect2->fCurve; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 931 | do { |
| 932 | tStep *= 0.5; |
| 933 | work.fStartT += tStep; |
| 934 | if (flip) { |
| 935 | tStep = -tStep; |
| 936 | flip = false; |
| 937 | } |
| 938 | work.initBounds(fCurve); |
| 939 | if (work.fCollapsed) { |
| 940 | return false; |
| 941 | } |
| 942 | if (last.approximatelyEqual(work.fPart[0])) { |
| 943 | break; |
| 944 | } |
| 945 | last = work.fPart[0]; |
| 946 | work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 947 | if (work.fCoinStart.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 948 | #if DEBUG_T_SECT |
| 949 | work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt()); |
| 950 | #endif |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 951 | double oppTTest = work.fCoinStart.perpT(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 952 | if (sect2->fHead->contains(oppTTest)) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 953 | *oppT = oppTTest; |
| 954 | oppPt = work.fCoinStart.perpPt(); |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 955 | contained = true; |
Cary Clark | 74b4290 | 2018-03-09 07:38:47 -0500 | [diff] [blame] | 956 | if (down ? result <= work.fStartT : result >= work.fStartT) { |
| 957 | *oppFirst = nullptr; // signal caller to fail |
| 958 | return false; |
| 959 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 960 | result = work.fStartT; |
| 961 | continue; |
| 962 | } |
| 963 | } |
| 964 | tStep = -tStep; |
| 965 | flip = true; |
| 966 | } while (true); |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 967 | if (!contained) { |
| 968 | return false; |
| 969 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 970 | if (last.approximatelyEqual(fCurve[0])) { |
| 971 | result = 0; |
| 972 | } else if (last.approximatelyEqual(fCurve[TCurve::kPointLast])) { |
| 973 | result = 1; |
| 974 | } |
| 975 | if (oppPt.approximatelyEqual(opp[0])) { |
| 976 | *oppT = 0; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 977 | } else if (oppPt.approximatelyEqual(opp[OppCurve::kPointLast])) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 978 | *oppT = 1; |
| 979 | } |
| 980 | *resultT = result; |
| 981 | return true; |
| 982 | } |
| 983 | |
| 984 | // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in quad span |
| 985 | // so that each quad sect has a pointer to the largest, and can update it as spans |
| 986 | // are split |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 987 | template<typename TCurve, typename OppCurve> |
| 988 | SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::boundsMax() const { |
| 989 | SkTSpan<TCurve, OppCurve>* test = fHead; |
| 990 | SkTSpan<TCurve, OppCurve>* largest = fHead; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 991 | bool lCollapsed = largest->fCollapsed; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 992 | while ((test = test->fNext)) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 993 | bool tCollapsed = test->fCollapsed; |
| 994 | if ((lCollapsed && !tCollapsed) || (lCollapsed == tCollapsed && |
| 995 | largest->fBoundsMax < test->fBoundsMax)) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 996 | largest = test; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 997 | lCollapsed = test->fCollapsed; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 998 | } |
| 999 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1000 | return largest; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1001 | } |
| 1002 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1003 | template<typename TCurve, typename OppCurve> |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1004 | bool SkTSect<TCurve, OppCurve>::coincidentCheck(SkTSect<OppCurve, TCurve>* sect2) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1005 | SkTSpan<TCurve, OppCurve>* first = fHead; |
caryclark | 9feb632 | 2016-10-25 08:58:26 -0700 | [diff] [blame] | 1006 | if (!first) { |
| 1007 | return false; |
| 1008 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1009 | SkTSpan<TCurve, OppCurve>* last, * next; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1010 | do { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1011 | int consecutive = this->countConsecutiveSpans(first, &last); |
| 1012 | next = last->fNext; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1013 | if (consecutive < COINCIDENT_SPAN_COUNT) { |
| 1014 | continue; |
| 1015 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1016 | this->validate(); |
| 1017 | sect2->validate(); |
| 1018 | this->computePerpendiculars(sect2, first, last); |
| 1019 | this->validate(); |
| 1020 | sect2->validate(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1021 | // check to see if a range of points are on the curve |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1022 | SkTSpan<TCurve, OppCurve>* coinStart = first; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1023 | do { |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1024 | bool success = this->extractCoincident(sect2, coinStart, last, &coinStart); |
| 1025 | if (!success) { |
| 1026 | return false; |
| 1027 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1028 | } while (coinStart && !last->fDeleted); |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 1029 | if (!fHead || !sect2->fHead) { |
| 1030 | break; |
| 1031 | } |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1032 | if (!next || next->fDeleted) { |
| 1033 | break; |
| 1034 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1035 | } while ((first = next)); |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1036 | return true; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1037 | } |
| 1038 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1039 | template<typename TCurve, typename OppCurve> |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1040 | void SkTSect<TCurve, OppCurve>::coincidentForce(SkTSect<OppCurve, TCurve>* sect2, |
| 1041 | double start1s, double start1e) { |
| 1042 | SkTSpan<TCurve, OppCurve>* first = fHead; |
| 1043 | SkTSpan<TCurve, OppCurve>* last = this->tail(); |
| 1044 | SkTSpan<OppCurve, TCurve>* oppFirst = sect2->fHead; |
| 1045 | SkTSpan<OppCurve, TCurve>* oppLast = sect2->tail(); |
| 1046 | bool deleteEmptySpans = this->updateBounded(first, last, oppFirst); |
| 1047 | deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first); |
| 1048 | this->removeSpanRange(first, last); |
| 1049 | sect2->removeSpanRange(oppFirst, oppLast); |
| 1050 | first->fStartT = start1s; |
| 1051 | first->fEndT = start1e; |
| 1052 | first->resetBounds(fCurve); |
| 1053 | first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve); |
| 1054 | first->fCoinEnd.setPerp(fCurve, start1e, fCurve[TCurve::kPointLast], sect2->fCurve); |
| 1055 | bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT(); |
caryclark | ef784fb | 2015-10-30 12:03:06 -0700 | [diff] [blame] | 1056 | double oppStartT = first->fCoinStart.perpT() == -1 ? 0 : SkTMax(0., first->fCoinStart.perpT()); |
| 1057 | double oppEndT = first->fCoinEnd.perpT() == -1 ? 1 : SkTMin(1., first->fCoinEnd.perpT()); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1058 | if (!oppMatched) { |
Ben Wagner | f08d1d0 | 2018-06-18 15:11:00 -0400 | [diff] [blame] | 1059 | using std::swap; |
| 1060 | swap(oppStartT, oppEndT); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1061 | } |
| 1062 | oppFirst->fStartT = oppStartT; |
| 1063 | oppFirst->fEndT = oppEndT; |
| 1064 | oppFirst->resetBounds(sect2->fCurve); |
| 1065 | this->removeCoincident(first, false); |
| 1066 | sect2->removeCoincident(oppFirst, true); |
| 1067 | if (deleteEmptySpans) { |
| 1068 | this->deleteEmptySpans(); |
| 1069 | sect2->deleteEmptySpans(); |
| 1070 | } |
| 1071 | } |
| 1072 | |
| 1073 | template<typename TCurve, typename OppCurve> |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1074 | bool SkTSect<TCurve, OppCurve>::coincidentHasT(double t) { |
| 1075 | SkTSpan<TCurve, OppCurve>* test = fCoincident; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1076 | while (test) { |
| 1077 | if (between(test->fStartT, t, test->fEndT)) { |
| 1078 | return true; |
| 1079 | } |
| 1080 | test = test->fNext; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1081 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1082 | return false; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1083 | } |
| 1084 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1085 | template<typename TCurve, typename OppCurve> |
| 1086 | int SkTSect<TCurve, OppCurve>::collapsed() const { |
| 1087 | int result = 0; |
| 1088 | const SkTSpan<TCurve, OppCurve>* test = fHead; |
| 1089 | while (test) { |
| 1090 | if (test->fCollapsed) { |
| 1091 | ++result; |
| 1092 | } |
| 1093 | test = test->next(); |
| 1094 | } |
| 1095 | return result; |
| 1096 | } |
| 1097 | |
| 1098 | template<typename TCurve, typename OppCurve> |
| 1099 | void SkTSect<TCurve, OppCurve>::computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, |
| 1100 | SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last) { |
| 1101 | const OppCurve& opp = sect2->fCurve; |
| 1102 | SkTSpan<TCurve, OppCurve>* work = first; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1103 | SkTSpan<TCurve, OppCurve>* prior = nullptr; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1104 | do { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1105 | if (!work->fHasPerp && !work->fCollapsed) { |
| 1106 | if (prior) { |
| 1107 | work->fCoinStart = prior->fCoinEnd; |
| 1108 | } else { |
| 1109 | work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1110 | } |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1111 | if (work->fCoinStart.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1112 | double perpT = work->fCoinStart.perpT(); |
| 1113 | if (sect2->coincidentHasT(perpT)) { |
caryclark | df386c5 | 2015-04-21 05:27:02 -0700 | [diff] [blame] | 1114 | work->fCoinStart.init(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1115 | } else { |
| 1116 | sect2->addForPerp(work, perpT); |
| 1117 | } |
| 1118 | } |
| 1119 | work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPointLast], opp); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1120 | if (work->fCoinEnd.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1121 | double perpT = work->fCoinEnd.perpT(); |
| 1122 | if (sect2->coincidentHasT(perpT)) { |
caryclark | df386c5 | 2015-04-21 05:27:02 -0700 | [diff] [blame] | 1123 | work->fCoinEnd.init(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1124 | } else { |
| 1125 | sect2->addForPerp(work, perpT); |
| 1126 | } |
| 1127 | } |
| 1128 | work->fHasPerp = true; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1129 | } |
| 1130 | if (work == last) { |
| 1131 | break; |
| 1132 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1133 | prior = work; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1134 | work = work->fNext; |
| 1135 | SkASSERT(work); |
| 1136 | } while (true); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1137 | } |
| 1138 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1139 | template<typename TCurve, typename OppCurve> |
| 1140 | int SkTSect<TCurve, OppCurve>::countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first, |
| 1141 | SkTSpan<TCurve, OppCurve>** lastPtr) const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1142 | int consecutive = 1; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1143 | SkTSpan<TCurve, OppCurve>* last = first; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1144 | do { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1145 | SkTSpan<TCurve, OppCurve>* next = last->fNext; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1146 | if (!next) { |
| 1147 | break; |
| 1148 | } |
| 1149 | if (next->fStartT > last->fEndT) { |
| 1150 | break; |
| 1151 | } |
| 1152 | ++consecutive; |
| 1153 | last = next; |
| 1154 | } while (true); |
| 1155 | *lastPtr = last; |
| 1156 | return consecutive; |
| 1157 | } |
| 1158 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1159 | template<typename TCurve, typename OppCurve> |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 1160 | bool SkTSect<TCurve, OppCurve>::hasBounded(const SkTSpan<OppCurve, TCurve>* span) const { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1161 | const SkTSpan<TCurve, OppCurve>* test = fHead; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1162 | if (!test) { |
| 1163 | return false; |
| 1164 | } |
| 1165 | do { |
| 1166 | if (test->findOppSpan(span)) { |
| 1167 | return true; |
| 1168 | } |
| 1169 | } while ((test = test->next())); |
| 1170 | return false; |
| 1171 | } |
| 1172 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1173 | template<typename TCurve, typename OppCurve> |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1174 | bool SkTSect<TCurve, OppCurve>::deleteEmptySpans() { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1175 | SkTSpan<TCurve, OppCurve>* test; |
| 1176 | SkTSpan<TCurve, OppCurve>* next = fHead; |
Cary Clark | 59ed482 | 2016-12-08 16:17:56 -0500 | [diff] [blame] | 1177 | int safetyHatch = 1000; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1178 | while ((test = next)) { |
| 1179 | next = test->fNext; |
| 1180 | if (!test->fBounded) { |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1181 | if (!this->removeSpan(test)) { |
| 1182 | return false; |
| 1183 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1184 | } |
Cary Clark | 59ed482 | 2016-12-08 16:17:56 -0500 | [diff] [blame] | 1185 | if (--safetyHatch < 0) { |
| 1186 | return false; |
| 1187 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1188 | } |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1189 | return true; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1190 | } |
| 1191 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1192 | template<typename TCurve, typename OppCurve> |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1193 | bool SkTSect<TCurve, OppCurve>::extractCoincident( |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1194 | SkTSect<OppCurve, TCurve>* sect2, |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1195 | SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last, |
| 1196 | SkTSpan<TCurve, OppCurve>** result) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1197 | first = findCoincidentRun(first, &last); |
caryclark | a1b42d9 | 2016-08-16 10:25:29 -0700 | [diff] [blame] | 1198 | if (!first || !last) { |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1199 | *result = nullptr; |
| 1200 | return true; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1201 | } |
| 1202 | // march outwards to find limit of coincidence from here to previous and next spans |
| 1203 | double startT = first->fStartT; |
caryclark | d8bc16b | 2015-03-26 09:05:12 -0700 | [diff] [blame] | 1204 | double oppStartT SK_INIT_TO_AVOID_WARNING; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1205 | double oppEndT SK_INIT_TO_AVOID_WARNING; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1206 | SkTSpan<TCurve, OppCurve>* prev = first->fPrev; |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1207 | SkASSERT(first->fCoinStart.isMatch()); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1208 | SkTSpan<OppCurve, TCurve>* oppFirst = first->findOppT(first->fCoinStart.perpT()); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1209 | SkOPASSERT(last->fCoinEnd.isMatch()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1210 | bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT(); |
| 1211 | double coinStart; |
| 1212 | SkDEBUGCODE(double coinEnd); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1213 | SkTSpan<OppCurve, TCurve>* cutFirst; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1214 | if (prev && prev->fEndT == startT |
| 1215 | && this->binarySearchCoin(sect2, startT, prev->fStartT - startT, &coinStart, |
Cary Clark | 74b4290 | 2018-03-09 07:38:47 -0500 | [diff] [blame] | 1216 | &oppStartT, &oppFirst) |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1217 | && prev->fStartT < coinStart && coinStart < startT |
| 1218 | && (cutFirst = prev->oppT(oppStartT))) { |
| 1219 | oppFirst = cutFirst; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1220 | first = this->addSplitAt(prev, coinStart); |
| 1221 | first->markCoincident(); |
| 1222 | prev->fCoinEnd.markCoincident(); |
| 1223 | if (oppFirst->fStartT < oppStartT && oppStartT < oppFirst->fEndT) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1224 | SkTSpan<OppCurve, TCurve>* oppHalf = sect2->addSplitAt(oppFirst, oppStartT); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1225 | if (oppMatched) { |
| 1226 | oppFirst->fCoinEnd.markCoincident(); |
| 1227 | oppHalf->markCoincident(); |
| 1228 | oppFirst = oppHalf; |
| 1229 | } else { |
| 1230 | oppFirst->markCoincident(); |
| 1231 | oppHalf->fCoinStart.markCoincident(); |
| 1232 | } |
| 1233 | } |
| 1234 | } else { |
Cary Clark | 74b4290 | 2018-03-09 07:38:47 -0500 | [diff] [blame] | 1235 | if (!oppFirst) { |
| 1236 | return false; |
| 1237 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1238 | SkDEBUGCODE(coinStart = first->fStartT); |
| 1239 | SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT); |
| 1240 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1241 | // FIXME: incomplete : if we're not at the end, find end of coin |
| 1242 | SkTSpan<OppCurve, TCurve>* oppLast; |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1243 | SkOPASSERT(last->fCoinEnd.isMatch()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1244 | oppLast = last->findOppT(last->fCoinEnd.perpT()); |
| 1245 | SkDEBUGCODE(coinEnd = last->fEndT); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1246 | #ifdef SK_DEBUG |
| 1247 | if (!this->globalState() || !this->globalState()->debugSkipAssert()) { |
| 1248 | oppEndT = oppMatched ? oppLast->fEndT : oppLast->fStartT; |
| 1249 | } |
| 1250 | #endif |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1251 | if (!oppMatched) { |
Ben Wagner | f08d1d0 | 2018-06-18 15:11:00 -0400 | [diff] [blame] | 1252 | using std::swap; |
| 1253 | swap(oppFirst, oppLast); |
| 1254 | swap(oppStartT, oppEndT); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1255 | } |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 1256 | SkOPASSERT(oppStartT < oppEndT); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1257 | SkASSERT(coinStart == first->fStartT); |
| 1258 | SkASSERT(coinEnd == last->fEndT); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1259 | SkOPASSERT(oppStartT == oppFirst->fStartT); |
| 1260 | SkOPASSERT(oppEndT == oppLast->fEndT); |
| 1261 | if (!oppFirst) { |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1262 | *result = nullptr; |
| 1263 | return true; |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1264 | } |
caryclark | 4294286 | 2016-08-19 07:01:33 -0700 | [diff] [blame] | 1265 | if (!oppLast) { |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1266 | *result = nullptr; |
| 1267 | return true; |
caryclark | 4294286 | 2016-08-19 07:01:33 -0700 | [diff] [blame] | 1268 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1269 | // reduce coincident runs to single entries |
| 1270 | this->validate(); |
| 1271 | sect2->validate(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1272 | bool deleteEmptySpans = this->updateBounded(first, last, oppFirst); |
| 1273 | deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1274 | this->removeSpanRange(first, last); |
| 1275 | sect2->removeSpanRange(oppFirst, oppLast); |
| 1276 | first->fEndT = last->fEndT; |
| 1277 | first->resetBounds(this->fCurve); |
| 1278 | first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], sect2->fCurve); |
| 1279 | first->fCoinEnd.setPerp(fCurve, first->fEndT, first->fPart[TCurve::kPointLast], sect2->fCurve); |
| 1280 | oppStartT = first->fCoinStart.perpT(); |
| 1281 | oppEndT = first->fCoinEnd.perpT(); |
| 1282 | if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) { |
| 1283 | if (!oppMatched) { |
Ben Wagner | f08d1d0 | 2018-06-18 15:11:00 -0400 | [diff] [blame] | 1284 | using std::swap; |
| 1285 | swap(oppStartT, oppEndT); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1286 | } |
| 1287 | oppFirst->fStartT = oppStartT; |
| 1288 | oppFirst->fEndT = oppEndT; |
| 1289 | oppFirst->resetBounds(sect2->fCurve); |
| 1290 | } |
| 1291 | this->validateBounded(); |
| 1292 | sect2->validateBounded(); |
| 1293 | last = first->fNext; |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 1294 | if (!this->removeCoincident(first, false)) { |
| 1295 | return false; |
| 1296 | } |
| 1297 | if (!sect2->removeCoincident(oppFirst, true)) { |
| 1298 | return false; |
| 1299 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1300 | if (deleteEmptySpans) { |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1301 | if (!this->deleteEmptySpans() || !sect2->deleteEmptySpans()) { |
| 1302 | *result = nullptr; |
| 1303 | return false; |
| 1304 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1305 | } |
| 1306 | this->validate(); |
| 1307 | sect2->validate(); |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1308 | *result = last && !last->fDeleted && fHead && sect2->fHead ? last : nullptr; |
| 1309 | return true; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1310 | } |
| 1311 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1312 | template<typename TCurve, typename OppCurve> |
| 1313 | SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::findCoincidentRun( |
| 1314 | SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>** lastPtr) { |
| 1315 | SkTSpan<TCurve, OppCurve>* work = first; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1316 | SkTSpan<TCurve, OppCurve>* lastCandidate = nullptr; |
| 1317 | first = nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1318 | // find the first fully coincident span |
| 1319 | do { |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1320 | if (work->fCoinStart.isMatch()) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1321 | #if DEBUG_T_SECT |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1322 | work->validatePerpT(work->fCoinStart.perpT()); |
| 1323 | work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt()); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1324 | #endif |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 1325 | SkOPASSERT(work->hasOppT(work->fCoinStart.perpT())); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1326 | if (!work->fCoinEnd.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1327 | break; |
| 1328 | } |
| 1329 | lastCandidate = work; |
| 1330 | if (!first) { |
| 1331 | first = work; |
| 1332 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1333 | } else if (first && work->fCollapsed) { |
| 1334 | *lastPtr = lastCandidate; |
| 1335 | return first; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1336 | } else { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1337 | lastCandidate = nullptr; |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1338 | SkOPASSERT(!first); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1339 | } |
| 1340 | if (work == *lastPtr) { |
| 1341 | return first; |
| 1342 | } |
| 1343 | work = work->fNext; |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 1344 | if (!work) { |
| 1345 | return nullptr; |
| 1346 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1347 | } while (true); |
| 1348 | if (lastCandidate) { |
| 1349 | *lastPtr = lastCandidate; |
| 1350 | } |
| 1351 | return first; |
| 1352 | } |
| 1353 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1354 | template<typename TCurve, typename OppCurve> |
| 1355 | int SkTSect<TCurve, OppCurve>::intersects(SkTSpan<TCurve, OppCurve>* span, |
| 1356 | SkTSect<OppCurve, TCurve>* opp, |
| 1357 | SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1358 | bool spanStart, oppStart; |
| 1359 | int hullResult = span->hullsIntersect(oppSpan, &spanStart, &oppStart); |
| 1360 | if (hullResult >= 0) { |
| 1361 | if (hullResult == 2) { // hulls have one point in common |
| 1362 | if (!span->fBounded || !span->fBounded->fNext) { |
| 1363 | SkASSERT(!span->fBounded || span->fBounded->fBounded == oppSpan); |
| 1364 | if (spanStart) { |
| 1365 | span->fEndT = span->fStartT; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1366 | } else { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1367 | span->fStartT = span->fEndT; |
| 1368 | } |
| 1369 | } else { |
| 1370 | hullResult = 1; |
| 1371 | } |
| 1372 | if (!oppSpan->fBounded || !oppSpan->fBounded->fNext) { |
| 1373 | SkASSERT(!oppSpan->fBounded || oppSpan->fBounded->fBounded == span); |
| 1374 | if (oppStart) { |
| 1375 | oppSpan->fEndT = oppSpan->fStartT; |
| 1376 | } else { |
| 1377 | oppSpan->fStartT = oppSpan->fEndT; |
| 1378 | } |
| 1379 | *oppResult = 2; |
| 1380 | } else { |
| 1381 | *oppResult = 1; |
| 1382 | } |
| 1383 | } else { |
| 1384 | *oppResult = 1; |
| 1385 | } |
| 1386 | return hullResult; |
| 1387 | } |
| 1388 | if (span->fIsLine && oppSpan->fIsLine) { |
| 1389 | SkIntersections i; |
| 1390 | int sects = this->linesIntersect(span, opp, oppSpan, &i); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1391 | if (sects == 2) { |
| 1392 | return *oppResult = 1; |
| 1393 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1394 | if (!sects) { |
| 1395 | return -1; |
| 1396 | } |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 1397 | this->removedEndCheck(span); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1398 | span->fStartT = span->fEndT = i[0][0]; |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 1399 | opp->removedEndCheck(oppSpan); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1400 | oppSpan->fStartT = oppSpan->fEndT = i[1][0]; |
| 1401 | return *oppResult = 2; |
| 1402 | } |
| 1403 | if (span->fIsLinear || oppSpan->fIsLinear) { |
| 1404 | return *oppResult = (int) span->linearsIntersect(oppSpan); |
| 1405 | } |
| 1406 | return *oppResult = 1; |
| 1407 | } |
| 1408 | |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 1409 | template<typename TCurve> |
| 1410 | static bool is_parallel(const SkDLine& thisLine, const TCurve& opp) { |
| 1411 | if (!opp.IsConic()) { |
| 1412 | return false; // FIXME : breaks a lot of stuff now |
| 1413 | } |
| 1414 | int finds = 0; |
| 1415 | SkDLine thisPerp; |
| 1416 | thisPerp.fPts[0].fX = thisLine.fPts[1].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY); |
| 1417 | thisPerp.fPts[0].fY = thisLine.fPts[1].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX); |
| 1418 | thisPerp.fPts[1] = thisLine.fPts[1]; |
| 1419 | SkIntersections perpRayI; |
| 1420 | perpRayI.intersectRay(opp, thisPerp); |
| 1421 | for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { |
| 1422 | finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[1]); |
| 1423 | } |
| 1424 | thisPerp.fPts[1].fX = thisLine.fPts[0].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY); |
| 1425 | thisPerp.fPts[1].fY = thisLine.fPts[0].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX); |
| 1426 | thisPerp.fPts[0] = thisLine.fPts[0]; |
| 1427 | perpRayI.intersectRay(opp, thisPerp); |
| 1428 | for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { |
| 1429 | finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[0]); |
| 1430 | } |
| 1431 | return finds >= 2; |
| 1432 | } |
| 1433 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1434 | // while the intersection points are sufficiently far apart: |
| 1435 | // construct the tangent lines from the intersections |
| 1436 | // find the point where the tangent line intersects the opposite curve |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1437 | template<typename TCurve, typename OppCurve> |
| 1438 | int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span, |
| 1439 | SkTSect<OppCurve, TCurve>* opp, |
| 1440 | SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) { |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 1441 | SkIntersections thisRayI SkDEBUGCODE((span->fDebugGlobalState)); |
| 1442 | SkIntersections oppRayI SkDEBUGCODE((span->fDebugGlobalState)); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1443 | SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1444 | SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast] }}; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1445 | int loopCount = 0; |
| 1446 | double bestDistSq = DBL_MAX; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1447 | if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { |
| 1448 | return 0; |
| 1449 | } |
| 1450 | if (!oppRayI.intersectRay(this->fCurve, oppLine)) { |
| 1451 | return 0; |
| 1452 | } |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1453 | // if the ends of each line intersect the opposite curve, the lines are coincident |
| 1454 | if (thisRayI.used() > 1) { |
| 1455 | int ptMatches = 0; |
| 1456 | for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) { |
| 1457 | for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) { |
| 1458 | ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPts[lIndex]); |
| 1459 | } |
| 1460 | } |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 1461 | if (ptMatches == 2 || is_parallel(thisLine, opp->fCurve)) { |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1462 | return 2; |
| 1463 | } |
| 1464 | } |
| 1465 | if (oppRayI.used() > 1) { |
| 1466 | int ptMatches = 0; |
| 1467 | for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) { |
Cary Clark | d80870f | 2017-10-17 11:57:26 -0400 | [diff] [blame] | 1468 | for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(oppLine.fPts); ++lIndex) { |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1469 | ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[lIndex]); |
| 1470 | } |
| 1471 | } |
caryclark | ed0935a | 2015-10-22 07:23:52 -0700 | [diff] [blame] | 1472 | if (ptMatches == 2|| is_parallel(oppLine, this->fCurve)) { |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 1473 | return 2; |
| 1474 | } |
| 1475 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1476 | do { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1477 | // pick the closest pair of points |
| 1478 | double closest = DBL_MAX; |
| 1479 | int closeIndex SK_INIT_TO_AVOID_WARNING; |
| 1480 | int oppCloseIndex SK_INIT_TO_AVOID_WARNING; |
| 1481 | for (int index = 0; index < oppRayI.used(); ++index) { |
| 1482 | if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT)) { |
| 1483 | continue; |
| 1484 | } |
| 1485 | for (int oIndex = 0; oIndex < thisRayI.used(); ++oIndex) { |
| 1486 | if (!roughly_between(oppSpan->fStartT, thisRayI[0][oIndex], oppSpan->fEndT)) { |
| 1487 | continue; |
| 1488 | } |
| 1489 | double distSq = thisRayI.pt(index).distanceSquared(oppRayI.pt(oIndex)); |
| 1490 | if (closest > distSq) { |
| 1491 | closest = distSq; |
| 1492 | closeIndex = index; |
| 1493 | oppCloseIndex = oIndex; |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1494 | } |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1495 | } |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1496 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1497 | if (closest == DBL_MAX) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1498 | break; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1499 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1500 | const SkDPoint& oppIPt = thisRayI.pt(oppCloseIndex); |
| 1501 | const SkDPoint& iPt = oppRayI.pt(closeIndex); |
| 1502 | if (between(span->fStartT, oppRayI[0][closeIndex], span->fEndT) |
| 1503 | && between(oppSpan->fStartT, thisRayI[0][oppCloseIndex], oppSpan->fEndT) |
| 1504 | && oppIPt.approximatelyEqual(iPt)) { |
| 1505 | i->merge(oppRayI, closeIndex, thisRayI, oppCloseIndex); |
| 1506 | return i->used(); |
| 1507 | } |
| 1508 | double distSq = oppIPt.distanceSquared(iPt); |
| 1509 | if (bestDistSq < distSq || ++loopCount > 5) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1510 | return 0; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1511 | } |
| 1512 | bestDistSq = distSq; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1513 | double oppStart = oppRayI[0][closeIndex]; |
| 1514 | thisLine[0] = fCurve.ptAtT(oppStart); |
| 1515 | thisLine[1] = thisLine[0] + fCurve.dxdyAtT(oppStart); |
| 1516 | if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { |
| 1517 | break; |
| 1518 | } |
| 1519 | double start = thisRayI[0][oppCloseIndex]; |
| 1520 | oppLine[0] = opp->fCurve.ptAtT(start); |
| 1521 | oppLine[1] = oppLine[0] + opp->fCurve.dxdyAtT(start); |
| 1522 | if (!oppRayI.intersectRay(this->fCurve, oppLine)) { |
| 1523 | break; |
| 1524 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1525 | } while (true); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1526 | // convergence may fail if the curves are nearly coincident |
| 1527 | SkTCoincident<OppCurve, TCurve> oCoinS, oCoinE; |
| 1528 | oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->fPart[0], fCurve); |
| 1529 | oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->fPart[OppCurve::kPointLast], fCurve); |
| 1530 | double tStart = oCoinS.perpT(); |
| 1531 | double tEnd = oCoinE.perpT(); |
| 1532 | bool swap = tStart > tEnd; |
| 1533 | if (swap) { |
Ben Wagner | f08d1d0 | 2018-06-18 15:11:00 -0400 | [diff] [blame] | 1534 | using std::swap; |
| 1535 | swap(tStart, tEnd); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1536 | } |
| 1537 | tStart = SkTMax(tStart, span->fStartT); |
| 1538 | tEnd = SkTMin(tEnd, span->fEndT); |
| 1539 | if (tStart > tEnd) { |
| 1540 | return 0; |
| 1541 | } |
| 1542 | SkDVector perpS, perpE; |
| 1543 | if (tStart == span->fStartT) { |
| 1544 | SkTCoincident<TCurve, OppCurve> coinS; |
| 1545 | coinS.setPerp(fCurve, span->fStartT, span->fPart[0], opp->fCurve); |
| 1546 | perpS = span->fPart[0] - coinS.perpPt(); |
| 1547 | } else if (swap) { |
| 1548 | perpS = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast]; |
| 1549 | } else { |
| 1550 | perpS = oCoinS.perpPt() - oppSpan->fPart[0]; |
| 1551 | } |
| 1552 | if (tEnd == span->fEndT) { |
| 1553 | SkTCoincident<TCurve, OppCurve> coinE; |
| 1554 | coinE.setPerp(fCurve, span->fEndT, span->fPart[TCurve::kPointLast], opp->fCurve); |
| 1555 | perpE = span->fPart[TCurve::kPointLast] - coinE.perpPt(); |
| 1556 | } else if (swap) { |
| 1557 | perpE = oCoinS.perpPt() - oppSpan->fPart[0]; |
| 1558 | } else { |
| 1559 | perpE = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast]; |
| 1560 | } |
| 1561 | if (perpS.dot(perpE) >= 0) { |
| 1562 | return 0; |
| 1563 | } |
| 1564 | SkTCoincident<TCurve, OppCurve> coinW; |
| 1565 | double workT = tStart; |
| 1566 | double tStep = tEnd - tStart; |
| 1567 | SkDPoint workPt; |
| 1568 | do { |
| 1569 | tStep *= 0.5; |
| 1570 | if (precisely_zero(tStep)) { |
| 1571 | return 0; |
| 1572 | } |
| 1573 | workT += tStep; |
| 1574 | workPt = fCurve.ptAtT(workT); |
| 1575 | coinW.setPerp(fCurve, workT, workPt, opp->fCurve); |
caryclark | 27c015d | 2016-09-23 05:47:20 -0700 | [diff] [blame] | 1576 | double perpT = coinW.perpT(); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1577 | if (coinW.isMatch() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) { |
caryclark | b669300 | 2015-12-16 12:28:35 -0800 | [diff] [blame] | 1578 | continue; |
| 1579 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1580 | SkDVector perpW = workPt - coinW.perpPt(); |
| 1581 | if ((perpS.dot(perpW) >= 0) == (tStep < 0)) { |
| 1582 | tStep = -tStep; |
| 1583 | } |
caryclark | b669300 | 2015-12-16 12:28:35 -0800 | [diff] [blame] | 1584 | if (workPt.approximatelyEqual(coinW.perpPt())) { |
| 1585 | break; |
| 1586 | } |
| 1587 | } while (true); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1588 | double oppTTest = coinW.perpT(); |
| 1589 | if (!opp->fHead->contains(oppTTest)) { |
| 1590 | return 0; |
| 1591 | } |
| 1592 | i->setMax(1); |
| 1593 | i->insert(workT, oppTTest, workPt); |
| 1594 | return 1; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1595 | } |
| 1596 | |
| 1597 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1598 | template<typename TCurve, typename OppCurve> |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1599 | bool SkTSect<TCurve, OppCurve>::markSpanGone(SkTSpan<TCurve, OppCurve>* span) { |
| 1600 | if (--fActiveCount < 0) { |
| 1601 | return false; |
| 1602 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1603 | span->fNext = fDeleted; |
| 1604 | fDeleted = span; |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 1605 | SkOPASSERT(!span->fDeleted); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1606 | span->fDeleted = true; |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1607 | return true; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1608 | } |
| 1609 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1610 | template<typename TCurve, typename OppCurve> |
| 1611 | bool SkTSect<TCurve, OppCurve>::matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, |
| 1612 | double t2) const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1613 | SkDVector dxdy = this->fCurve.dxdyAtT(t); |
| 1614 | SkDVector dxdy2 = sect2->fCurve.dxdyAtT(t2); |
| 1615 | return dxdy.dot(dxdy2) >= 0; |
| 1616 | } |
| 1617 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1618 | template<typename TCurve, typename OppCurve> |
| 1619 | void SkTSect<TCurve, OppCurve>::matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, |
| 1620 | double t2, bool* calcMatched, bool* oppMatched) const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1621 | if (*calcMatched) { |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 1622 | SkASSERT(*oppMatched == this->matchedDirection(t, sect2, t2)); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1623 | } else { |
| 1624 | *oppMatched = this->matchedDirection(t, sect2, t2); |
| 1625 | *calcMatched = true; |
| 1626 | } |
| 1627 | } |
| 1628 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1629 | template<typename TCurve, typename OppCurve> |
| 1630 | void SkTSect<TCurve, OppCurve>::mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1631 | double smallLimit = 0; |
| 1632 | do { |
| 1633 | // find the smallest unprocessed span |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1634 | SkTSpan<TCurve, OppCurve>* smaller = nullptr; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1635 | SkTSpan<TCurve, OppCurve>* test = fCoincident; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1636 | do { |
caryclark | 221a4bb | 2016-10-07 11:15:15 -0700 | [diff] [blame] | 1637 | if (!test) { |
| 1638 | return; |
| 1639 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1640 | if (test->fStartT < smallLimit) { |
| 1641 | continue; |
| 1642 | } |
| 1643 | if (smaller && smaller->fEndT < test->fStartT) { |
| 1644 | continue; |
| 1645 | } |
| 1646 | smaller = test; |
| 1647 | } while ((test = test->fNext)); |
| 1648 | if (!smaller) { |
| 1649 | return; |
| 1650 | } |
| 1651 | smallLimit = smaller->fEndT; |
| 1652 | // find next larger span |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1653 | SkTSpan<TCurve, OppCurve>* prior = nullptr; |
| 1654 | SkTSpan<TCurve, OppCurve>* larger = nullptr; |
| 1655 | SkTSpan<TCurve, OppCurve>* largerPrior = nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1656 | test = fCoincident; |
| 1657 | do { |
| 1658 | if (test->fStartT < smaller->fEndT) { |
| 1659 | continue; |
| 1660 | } |
caryclark | 221a4bb | 2016-10-07 11:15:15 -0700 | [diff] [blame] | 1661 | SkOPASSERT(test->fStartT != smaller->fEndT); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1662 | if (larger && larger->fStartT < test->fStartT) { |
| 1663 | continue; |
| 1664 | } |
| 1665 | largerPrior = prior; |
| 1666 | larger = test; |
| 1667 | } while ((prior = test), (test = test->fNext)); |
| 1668 | if (!larger) { |
| 1669 | continue; |
| 1670 | } |
| 1671 | // check middle t value to see if it is coincident as well |
| 1672 | double midT = (smaller->fEndT + larger->fStartT) / 2; |
| 1673 | SkDPoint midPt = fCurve.ptAtT(midT); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1674 | SkTCoincident<TCurve, OppCurve> coin; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1675 | coin.setPerp(fCurve, midT, midPt, sect2->fCurve); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1676 | if (coin.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1677 | smaller->fEndT = larger->fEndT; |
| 1678 | smaller->fCoinEnd = larger->fCoinEnd; |
| 1679 | if (largerPrior) { |
| 1680 | largerPrior->fNext = larger->fNext; |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1681 | largerPrior->validate(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1682 | } else { |
| 1683 | fCoincident = larger->fNext; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1684 | } |
| 1685 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1686 | } while (true); |
| 1687 | } |
| 1688 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1689 | template<typename TCurve, typename OppCurve> |
| 1690 | SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::prev( |
| 1691 | SkTSpan<TCurve, OppCurve>* span) const { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1692 | SkTSpan<TCurve, OppCurve>* result = nullptr; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1693 | SkTSpan<TCurve, OppCurve>* test = fHead; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1694 | while (span != test) { |
| 1695 | result = test; |
| 1696 | test = test->fNext; |
| 1697 | SkASSERT(test); |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1698 | } |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 1699 | return result; |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1700 | } |
| 1701 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1702 | template<typename TCurve, typename OppCurve> |
| 1703 | void SkTSect<TCurve, OppCurve>::recoverCollapsed() { |
| 1704 | SkTSpan<TCurve, OppCurve>* deleted = fDeleted; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1705 | while (deleted) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1706 | SkTSpan<TCurve, OppCurve>* delNext = deleted->fNext; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1707 | if (deleted->fCollapsed) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1708 | SkTSpan<TCurve, OppCurve>** spanPtr = &fHead; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1709 | while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) { |
| 1710 | spanPtr = &(*spanPtr)->fNext; |
| 1711 | } |
| 1712 | deleted->fNext = *spanPtr; |
| 1713 | *spanPtr = deleted; |
| 1714 | } |
| 1715 | deleted = delNext; |
| 1716 | } |
| 1717 | } |
| 1718 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1719 | template<typename TCurve, typename OppCurve> |
| 1720 | void SkTSect<TCurve, OppCurve>::removeAllBut(const SkTSpan<OppCurve, TCurve>* keep, |
| 1721 | SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp) { |
| 1722 | const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1723 | while (testBounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1724 | SkTSpan<OppCurve, TCurve>* bounded = testBounded->fBounded; |
| 1725 | const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1726 | // may have been deleted when opp did 'remove all but' |
| 1727 | if (bounded != keep && !bounded->fDeleted) { |
| 1728 | SkAssertResult(SkDEBUGCODE(!) span->removeBounded(bounded)); |
| 1729 | if (bounded->removeBounded(span)) { |
| 1730 | opp->removeSpan(bounded); |
| 1731 | } |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1732 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1733 | testBounded = next; |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1734 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1735 | SkASSERT(!span->fDeleted); |
| 1736 | SkASSERT(span->findOppSpan(keep)); |
| 1737 | SkASSERT(keep->findOppSpan(span)); |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1738 | } |
| 1739 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1740 | template<typename TCurve, typename OppCurve> |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 1741 | bool SkTSect<TCurve, OppCurve>::removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1742 | SkTSpan<TCurve, OppCurve>* test = fHead; |
| 1743 | SkTSpan<TCurve, OppCurve>* next; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1744 | do { |
| 1745 | next = test->fNext; |
| 1746 | if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) { |
| 1747 | continue; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1748 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1749 | SkDVector startV = test->fCoinStart.perpPt() - test->fPart[0]; |
| 1750 | SkDVector endV = test->fCoinEnd.perpPt() - test->fPart[TCurve::kPointLast]; |
| 1751 | #if DEBUG_T_SECT |
| 1752 | SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUNCTION__, |
| 1753 | startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV)); |
| 1754 | #endif |
| 1755 | if (startV.dot(endV) <= 0) { |
| 1756 | continue; |
| 1757 | } |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 1758 | if (!this->removeSpans(test, opp)) { |
| 1759 | return false; |
| 1760 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1761 | } while ((test = next)); |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 1762 | return true; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1763 | } |
| 1764 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1765 | template<typename TCurve, typename OppCurve> |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 1766 | bool SkTSect<TCurve, OppCurve>::removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween) { |
| 1767 | if (!this->unlinkSpan(span)) { |
| 1768 | return false; |
| 1769 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1770 | if (isBetween || between(0, span->fCoinStart.perpT(), 1)) { |
| 1771 | --fActiveCount; |
| 1772 | span->fNext = fCoincident; |
| 1773 | fCoincident = span; |
| 1774 | } else { |
| 1775 | this->markSpanGone(span); |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1776 | } |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 1777 | return true; |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1778 | } |
| 1779 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1780 | template<typename TCurve, typename OppCurve> |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 1781 | void SkTSect<TCurve, OppCurve>::removedEndCheck(SkTSpan<TCurve, OppCurve>* span) { |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 1782 | if (!span->fStartT) { |
| 1783 | fRemovedStartT = true; |
| 1784 | } |
| 1785 | if (1 == span->fEndT) { |
| 1786 | fRemovedEndT = true; |
| 1787 | } |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 1788 | } |
| 1789 | |
| 1790 | template<typename TCurve, typename OppCurve> |
| 1791 | bool SkTSect<TCurve, OppCurve>::removeSpan(SkTSpan<TCurve, OppCurve>* span) {\ |
| 1792 | this->removedEndCheck(span); |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 1793 | if (!this->unlinkSpan(span)) { |
| 1794 | return false; |
| 1795 | } |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 1796 | return this->markSpanGone(span); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1797 | } |
| 1798 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1799 | template<typename TCurve, typename OppCurve> |
| 1800 | void SkTSect<TCurve, OppCurve>::removeSpanRange(SkTSpan<TCurve, OppCurve>* first, |
| 1801 | SkTSpan<TCurve, OppCurve>* last) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1802 | if (first == last) { |
| 1803 | return; |
| 1804 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1805 | SkTSpan<TCurve, OppCurve>* span = first; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1806 | SkASSERT(span); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1807 | SkTSpan<TCurve, OppCurve>* final = last->fNext; |
| 1808 | SkTSpan<TCurve, OppCurve>* next = span->fNext; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1809 | while ((span = next) && span != final) { |
| 1810 | next = span->fNext; |
| 1811 | this->markSpanGone(span); |
| 1812 | } |
| 1813 | if (final) { |
| 1814 | final->fPrev = first; |
| 1815 | } |
| 1816 | first->fNext = final; |
Cary Clark | b8421ed | 2018-03-14 15:55:02 -0400 | [diff] [blame] | 1817 | // world may not be ready for validation here |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1818 | first->validate(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1819 | } |
| 1820 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1821 | template<typename TCurve, typename OppCurve> |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 1822 | bool SkTSect<TCurve, OppCurve>::removeSpans(SkTSpan<TCurve, OppCurve>* span, |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1823 | SkTSect<OppCurve, TCurve>* opp) { |
| 1824 | SkTSpanBounded<OppCurve, TCurve>* bounded = span->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1825 | while (bounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1826 | SkTSpan<OppCurve, TCurve>* spanBounded = bounded->fBounded; |
| 1827 | SkTSpanBounded<OppCurve, TCurve>* next = bounded->fNext; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1828 | if (span->removeBounded(spanBounded)) { // shuffles last into position 0 |
| 1829 | this->removeSpan(span); |
| 1830 | } |
| 1831 | if (spanBounded->removeBounded(span)) { |
| 1832 | opp->removeSpan(spanBounded); |
| 1833 | } |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 1834 | if (span->fDeleted && opp->hasBounded(span)) { |
| 1835 | return false; |
| 1836 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1837 | bounded = next; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1838 | } |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 1839 | return true; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1840 | } |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1841 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1842 | template<typename TCurve, typename OppCurve> |
| 1843 | SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::spanAtT(double t, |
| 1844 | SkTSpan<TCurve, OppCurve>** priorSpan) { |
| 1845 | SkTSpan<TCurve, OppCurve>* test = fHead; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1846 | SkTSpan<TCurve, OppCurve>* prev = nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1847 | while (test && test->fEndT < t) { |
| 1848 | prev = test; |
| 1849 | test = test->fNext; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1850 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1851 | *priorSpan = prev; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1852 | return test && test->fStartT <= t ? test : nullptr; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1853 | } |
| 1854 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1855 | template<typename TCurve, typename OppCurve> |
| 1856 | SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::tail() { |
| 1857 | SkTSpan<TCurve, OppCurve>* result = fHead; |
| 1858 | SkTSpan<TCurve, OppCurve>* next = fHead; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1859 | while ((next = next->fNext)) { |
| 1860 | if (next->fEndT > result->fEndT) { |
| 1861 | result = next; |
| 1862 | } |
| 1863 | } |
| 1864 | return result; |
| 1865 | } |
| 1866 | |
| 1867 | /* Each span has a range of opposite spans it intersects. After the span is split in two, |
| 1868 | adjust the range to its new size */ |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1869 | template<typename TCurve, typename OppCurve> |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 1870 | bool SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span, |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1871 | SkTSect<OppCurve, TCurve>* opp) { |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 1872 | FAIL_IF(!span->initBounds(fCurve)); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1873 | const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1874 | while (testBounded) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1875 | SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded; |
| 1876 | const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1877 | int oppSects, sects = this->intersects(span, opp, test, &oppSects); |
| 1878 | if (sects >= 1) { |
| 1879 | if (oppSects == 2) { |
| 1880 | test->initBounds(opp->fCurve); |
| 1881 | opp->removeAllBut(span, test, this); |
| 1882 | } |
| 1883 | if (sects == 2) { |
| 1884 | span->initBounds(fCurve); |
| 1885 | this->removeAllBut(test, span, opp); |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 1886 | return true; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1887 | } |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1888 | } else { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1889 | if (span->removeBounded(test)) { |
| 1890 | this->removeSpan(span); |
| 1891 | } |
| 1892 | if (test->removeBounded(span)) { |
| 1893 | opp->removeSpan(test); |
| 1894 | } |
| 1895 | } |
| 1896 | testBounded = next; |
| 1897 | } |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 1898 | return true; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1899 | } |
| 1900 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1901 | template<typename TCurve, typename OppCurve> |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 1902 | bool SkTSect<TCurve, OppCurve>::unlinkSpan(SkTSpan<TCurve, OppCurve>* span) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1903 | SkTSpan<TCurve, OppCurve>* prev = span->fPrev; |
| 1904 | SkTSpan<TCurve, OppCurve>* next = span->fNext; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1905 | if (prev) { |
| 1906 | prev->fNext = next; |
| 1907 | if (next) { |
| 1908 | next->fPrev = prev; |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 1909 | if (next->fStartT > next->fEndT) { |
| 1910 | return false; |
| 1911 | } |
Cary Clark | b8421ed | 2018-03-14 15:55:02 -0400 | [diff] [blame] | 1912 | // world may not be ready for validate here |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1913 | next->validate(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1914 | } |
| 1915 | } else { |
| 1916 | fHead = next; |
| 1917 | if (next) { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1918 | next->fPrev = nullptr; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1919 | } |
| 1920 | } |
Cary Clark | 38702ab | 2017-09-05 18:11:55 -0400 | [diff] [blame] | 1921 | return true; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 1922 | } |
| 1923 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1924 | template<typename TCurve, typename OppCurve> |
| 1925 | bool SkTSect<TCurve, OppCurve>::updateBounded(SkTSpan<TCurve, OppCurve>* first, |
| 1926 | SkTSpan<TCurve, OppCurve>* last, SkTSpan<OppCurve, TCurve>* oppFirst) { |
| 1927 | SkTSpan<TCurve, OppCurve>* test = first; |
| 1928 | const SkTSpan<TCurve, OppCurve>* final = last->next(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1929 | bool deleteSpan = false; |
| 1930 | do { |
| 1931 | deleteSpan |= test->removeAllBounded(); |
caryclark | e25a4f6 | 2016-07-26 09:26:29 -0700 | [diff] [blame] | 1932 | } while ((test = test->fNext) != final && test); |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1933 | first->fBounded = nullptr; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1934 | first->addBounded(oppFirst, &fHeap); |
| 1935 | // cannot call validate until remove span range is called |
| 1936 | return deleteSpan; |
| 1937 | } |
| 1938 | |
| 1939 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1940 | template<typename TCurve, typename OppCurve> |
| 1941 | void SkTSect<TCurve, OppCurve>::validate() const { |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1942 | #if DEBUG_VALIDATE |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1943 | int count = 0; |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1944 | double last = 0; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1945 | if (fHead) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1946 | const SkTSpan<TCurve, OppCurve>* span = fHead; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1947 | SkASSERT(!span->fPrev); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1948 | const SkTSpan<TCurve, OppCurve>* next; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1949 | do { |
| 1950 | span->validate(); |
| 1951 | SkASSERT(span->fStartT >= last); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1952 | last = span->fEndT; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1953 | ++count; |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1954 | next = span->fNext; |
| 1955 | SkASSERT(next != span); |
| 1956 | } while ((span = next) != nullptr); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1957 | } |
| 1958 | SkASSERT(count == fActiveCount); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1959 | #endif |
| 1960 | #if DEBUG_T_SECT |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1961 | SkASSERT(fActiveCount <= fDebugAllocatedCount); |
| 1962 | int deletedCount = 0; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1963 | const SkTSpan<TCurve, OppCurve>* deleted = fDeleted; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1964 | while (deleted) { |
| 1965 | ++deletedCount; |
| 1966 | deleted = deleted->fNext; |
| 1967 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1968 | const SkTSpan<TCurve, OppCurve>* coincident = fCoincident; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1969 | while (coincident) { |
| 1970 | ++deletedCount; |
| 1971 | coincident = coincident->fNext; |
| 1972 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1973 | SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount); |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1974 | #endif |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1975 | } |
| 1976 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1977 | template<typename TCurve, typename OppCurve> |
| 1978 | void SkTSect<TCurve, OppCurve>::validateBounded() const { |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 1979 | #if DEBUG_VALIDATE |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1980 | if (!fHead) { |
| 1981 | return; |
| 1982 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1983 | const SkTSpan<TCurve, OppCurve>* span = fHead; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1984 | do { |
| 1985 | span->validateBounded(); |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1986 | } while ((span = span->fNext) != nullptr); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1987 | #endif |
| 1988 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1989 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1990 | template<typename TCurve, typename OppCurve> |
| 1991 | int SkTSect<TCurve, OppCurve>::EndsEqual(const SkTSect<TCurve, OppCurve>* sect1, |
| 1992 | const SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 1993 | int zeroOneSet = 0; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1994 | if (sect1->fCurve[0] == sect2->fCurve[0]) { |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1995 | zeroOneSet |= kZeroS1Set | kZeroS2Set; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 1996 | intersections->insert(0, 0, sect1->fCurve[0]); |
| 1997 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 1998 | if (sect1->fCurve[0] == sect2->fCurve[OppCurve::kPointLast]) { |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 1999 | zeroOneSet |= kZeroS1Set | kOneS2Set; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2000 | intersections->insert(0, 1, sect1->fCurve[0]); |
| 2001 | } |
| 2002 | if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[0]) { |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 2003 | zeroOneSet |= kOneS1Set | kZeroS2Set; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2004 | intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]); |
| 2005 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2006 | if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[OppCurve::kPointLast]) { |
caryclark | ccec0f9 | 2015-03-24 07:28:17 -0700 | [diff] [blame] | 2007 | zeroOneSet |= kOneS1Set | kOneS2Set; |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 2008 | intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2009 | } |
| 2010 | // check for zero |
| 2011 | if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set)) |
| 2012 | && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) { |
| 2013 | zeroOneSet |= kZeroS1Set | kZeroS2Set; |
| 2014 | intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]); |
| 2015 | } |
| 2016 | if (!(zeroOneSet & (kZeroS1Set | kOneS2Set)) |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2017 | && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[OppCurve::kPointLast])) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2018 | zeroOneSet |= kZeroS1Set | kOneS2Set; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2019 | intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[OppCurve::kPointLast]); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2020 | } |
| 2021 | // check for one |
| 2022 | if (!(zeroOneSet & (kOneS1Set | kZeroS2Set)) |
| 2023 | && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0])) { |
| 2024 | zeroOneSet |= kOneS1Set | kZeroS2Set; |
| 2025 | intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], sect2->fCurve[0]); |
| 2026 | } |
| 2027 | if (!(zeroOneSet & (kOneS1Set | kOneS2Set)) |
| 2028 | && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[ |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2029 | OppCurve::kPointLast])) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2030 | zeroOneSet |= kOneS1Set | kOneS2Set; |
| 2031 | intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast], |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2032 | sect2->fCurve[OppCurve::kPointLast]); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2033 | } |
| 2034 | return zeroOneSet; |
| 2035 | } |
| 2036 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2037 | template<typename TCurve, typename OppCurve> |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2038 | struct SkClosestRecord { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2039 | bool operator<(const SkClosestRecord& rh) const { |
| 2040 | return fClosest < rh.fClosest; |
| 2041 | } |
| 2042 | |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2043 | void addIntersection(SkIntersections* intersections) const { |
| 2044 | double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT(); |
| 2045 | double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT(); |
| 2046 | intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]); |
| 2047 | } |
| 2048 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2049 | void findEnd(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2, |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2050 | int c1Index, int c2Index) { |
| 2051 | const TCurve& c1 = span1->part(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2052 | const OppCurve& c2 = span2->part(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2053 | if (!c1[c1Index].approximatelyEqual(c2[c2Index])) { |
| 2054 | return; |
| 2055 | } |
| 2056 | double dist = c1[c1Index].distanceSquared(c2[c2Index]); |
| 2057 | if (fClosest < dist) { |
| 2058 | return; |
| 2059 | } |
| 2060 | fC1Span = span1; |
| 2061 | fC2Span = span2; |
| 2062 | fC1StartT = span1->startT(); |
| 2063 | fC1EndT = span1->endT(); |
| 2064 | fC2StartT = span2->startT(); |
| 2065 | fC2EndT = span2->endT(); |
| 2066 | fC1Index = c1Index; |
| 2067 | fC2Index = c2Index; |
| 2068 | fClosest = dist; |
| 2069 | } |
| 2070 | |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 2071 | bool matesWith(const SkClosestRecord& mate SkDEBUGPARAMS(SkIntersections* i)) const { |
Cary Clark | 6711638 | 2017-01-03 16:25:18 -0500 | [diff] [blame] | 2072 | SkOPOBJASSERT(i, fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT() |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2073 | || mate.fC1Span->endT() <= fC1Span->startT()); |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 2074 | SkOPOBJASSERT(i, fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->startT() |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2075 | || mate.fC2Span->endT() <= fC2Span->startT()); |
| 2076 | return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->startT() |
| 2077 | || fC1Span->startT() == mate.fC1Span->endT() |
| 2078 | || fC2Span == mate.fC2Span |
| 2079 | || fC2Span->endT() == mate.fC2Span->startT() |
| 2080 | || fC2Span->startT() == mate.fC2Span->endT(); |
| 2081 | } |
| 2082 | |
| 2083 | void merge(const SkClosestRecord& mate) { |
| 2084 | fC1Span = mate.fC1Span; |
| 2085 | fC2Span = mate.fC2Span; |
| 2086 | fClosest = mate.fClosest; |
| 2087 | fC1Index = mate.fC1Index; |
| 2088 | fC2Index = mate.fC2Index; |
| 2089 | } |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 2090 | |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2091 | void reset() { |
| 2092 | fClosest = FLT_MAX; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 2093 | SkDEBUGCODE(fC1Span = nullptr); |
| 2094 | SkDEBUGCODE(fC2Span = nullptr); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2095 | SkDEBUGCODE(fC1Index = fC2Index = -1); |
| 2096 | } |
| 2097 | |
| 2098 | void update(const SkClosestRecord& mate) { |
| 2099 | fC1StartT = SkTMin(fC1StartT, mate.fC1StartT); |
| 2100 | fC1EndT = SkTMax(fC1EndT, mate.fC1EndT); |
| 2101 | fC2StartT = SkTMin(fC2StartT, mate.fC2StartT); |
| 2102 | fC2EndT = SkTMax(fC2EndT, mate.fC2EndT); |
| 2103 | } |
| 2104 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2105 | const SkTSpan<TCurve, OppCurve>* fC1Span; |
| 2106 | const SkTSpan<OppCurve, TCurve>* fC2Span; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2107 | double fC1StartT; |
| 2108 | double fC1EndT; |
| 2109 | double fC2StartT; |
| 2110 | double fC2EndT; |
| 2111 | double fClosest; |
| 2112 | int fC1Index; |
| 2113 | int fC2Index; |
| 2114 | }; |
| 2115 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2116 | template<typename TCurve, typename OppCurve> |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2117 | struct SkClosestSect { |
| 2118 | SkClosestSect() |
| 2119 | : fUsed(0) { |
| 2120 | fClosest.push_back().reset(); |
| 2121 | } |
| 2122 | |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 2123 | bool find(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2 |
| 2124 | SkDEBUGPARAMS(SkIntersections* i)) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2125 | SkClosestRecord<TCurve, OppCurve>* record = &fClosest[fUsed]; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2126 | record->findEnd(span1, span2, 0, 0); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2127 | record->findEnd(span1, span2, 0, OppCurve::kPointLast); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2128 | record->findEnd(span1, span2, TCurve::kPointLast, 0); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2129 | record->findEnd(span1, span2, TCurve::kPointLast, OppCurve::kPointLast); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2130 | if (record->fClosest == FLT_MAX) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2131 | return false; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2132 | } |
| 2133 | for (int index = 0; index < fUsed; ++index) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2134 | SkClosestRecord<TCurve, OppCurve>* test = &fClosest[index]; |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 2135 | if (test->matesWith(*record SkDEBUGPARAMS(i))) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2136 | if (test->fClosest > record->fClosest) { |
| 2137 | test->merge(*record); |
| 2138 | } |
| 2139 | test->update(*record); |
| 2140 | record->reset(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2141 | return false; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2142 | } |
| 2143 | } |
| 2144 | ++fUsed; |
| 2145 | fClosest.push_back().reset(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2146 | return true; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2147 | } |
| 2148 | |
| 2149 | void finish(SkIntersections* intersections) const { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2150 | SkSTArray<TCurve::kMaxIntersections * 3, |
| 2151 | const SkClosestRecord<TCurve, OppCurve>*, true> closestPtrs; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2152 | for (int index = 0; index < fUsed; ++index) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2153 | closestPtrs.push_back(&fClosest[index]); |
| 2154 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2155 | SkTQSort<const SkClosestRecord<TCurve, OppCurve> >(closestPtrs.begin(), closestPtrs.end() |
| 2156 | - 1); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2157 | for (int index = 0; index < fUsed; ++index) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2158 | const SkClosestRecord<TCurve, OppCurve>* test = closestPtrs[index]; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2159 | test->addIntersection(intersections); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2160 | } |
| 2161 | } |
| 2162 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2163 | // this is oversized so that an extra records can merge into final one |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2164 | SkSTArray<TCurve::kMaxIntersections * 2, SkClosestRecord<TCurve, OppCurve>, true> fClosest; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2165 | int fUsed; |
| 2166 | }; |
| 2167 | |
| 2168 | // returns true if the rect is too small to consider |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2169 | template<typename TCurve, typename OppCurve> |
| 2170 | void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, |
| 2171 | SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2172 | #if DEBUG_T_SECT_DUMP > 1 |
| 2173 | gDumpTSectNum = 0; |
| 2174 | #endif |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2175 | SkDEBUGCODE(sect1->fOppSect = sect2); |
| 2176 | SkDEBUGCODE(sect2->fOppSect = sect1); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2177 | intersections->reset(); |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2178 | intersections->setMax(TCurve::kMaxIntersections + 4); // give extra for slop |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2179 | SkTSpan<TCurve, OppCurve>* span1 = sect1->fHead; |
| 2180 | SkTSpan<OppCurve, TCurve>* span2 = sect2->fHead; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2181 | int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect); |
| 2182 | // SkASSERT(between(0, sect, 2)); |
| 2183 | if (!sect) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2184 | return; |
| 2185 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2186 | if (sect == 2 && oppSect == 2) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2187 | (void) EndsEqual(sect1, sect2, intersections); |
| 2188 | return; |
| 2189 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2190 | span1->addBounded(span2, §1->fHeap); |
| 2191 | span2->addBounded(span1, §2->fHeap); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 2192 | const int kMaxCoinLoopCount = 8; |
| 2193 | int coinLoopCount = kMaxCoinLoopCount; |
| 2194 | double start1s SK_INIT_TO_AVOID_WARNING; |
| 2195 | double start1e SK_INIT_TO_AVOID_WARNING; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2196 | do { |
| 2197 | // find the largest bounds |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2198 | SkTSpan<TCurve, OppCurve>* largest1 = sect1->boundsMax(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2199 | if (!largest1) { |
| 2200 | break; |
| 2201 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2202 | SkTSpan<OppCurve, TCurve>* largest2 = sect2->boundsMax(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2203 | // split it |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2204 | if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax |
| 2205 | || (!largest1->fCollapsed && largest2->fCollapsed)))) { |
| 2206 | if (largest1->fCollapsed) { |
| 2207 | break; |
| 2208 | } |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 2209 | sect1->resetRemovedEnds(); |
| 2210 | sect2->resetRemovedEnds(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2211 | // trim parts that don't intersect the opposite |
| 2212 | SkTSpan<TCurve, OppCurve>* half1 = sect1->addOne(); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 2213 | SkDEBUGCODE(half1->debugSetGlobalState(sect1->globalState())); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2214 | if (!half1->split(largest1, §1->fHeap)) { |
| 2215 | break; |
| 2216 | } |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2217 | if (!sect1->trim(largest1, sect2)) { |
| 2218 | SkOPOBJASSERT(intersections, 0); |
| 2219 | return; |
| 2220 | } |
| 2221 | if (!sect1->trim(half1, sect2)) { |
| 2222 | SkOPOBJASSERT(intersections, 0); |
| 2223 | return; |
| 2224 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2225 | } else { |
| 2226 | if (largest2->fCollapsed) { |
| 2227 | break; |
| 2228 | } |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 2229 | sect1->resetRemovedEnds(); |
| 2230 | sect2->resetRemovedEnds(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2231 | // trim parts that don't intersect the opposite |
| 2232 | SkTSpan<OppCurve, TCurve>* half2 = sect2->addOne(); |
caryclark | 643ede6 | 2016-08-08 14:27:45 -0700 | [diff] [blame] | 2233 | SkDEBUGCODE(half2->debugSetGlobalState(sect2->globalState())); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2234 | if (!half2->split(largest2, §2->fHeap)) { |
| 2235 | break; |
| 2236 | } |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2237 | if (!sect2->trim(largest2, sect1)) { |
| 2238 | SkOPOBJASSERT(intersections, 0); |
| 2239 | return; |
| 2240 | } |
| 2241 | if (!sect2->trim(half2, sect1)) { |
| 2242 | SkOPOBJASSERT(intersections, 0); |
| 2243 | return; |
| 2244 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2245 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2246 | sect1->validate(); |
| 2247 | sect2->validate(); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 2248 | #if DEBUG_T_SECT_LOOP_COUNT |
| 2249 | intersections->debugBumpLoopCount(SkIntersections::kIterations_DebugLoop); |
| 2250 | #endif |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2251 | // if there are 9 or more continuous spans on both sects, suspect coincidence |
| 2252 | if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT |
| 2253 | && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 2254 | if (coinLoopCount == kMaxCoinLoopCount) { |
| 2255 | start1s = sect1->fHead->fStartT; |
| 2256 | start1e = sect1->tail()->fEndT; |
| 2257 | } |
caryclark | ef7cee4 | 2016-09-06 09:05:54 -0700 | [diff] [blame] | 2258 | if (!sect1->coincidentCheck(sect2)) { |
| 2259 | return; |
| 2260 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2261 | sect1->validate(); |
| 2262 | sect2->validate(); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 2263 | #if DEBUG_T_SECT_LOOP_COUNT |
| 2264 | intersections->debugBumpLoopCount(SkIntersections::kCoinCheck_DebugLoop); |
| 2265 | #endif |
caryclark | ef784fb | 2015-10-30 12:03:06 -0700 | [diff] [blame] | 2266 | if (!--coinLoopCount && sect1->fHead && sect2->fHead) { |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 2267 | /* All known working cases resolve in two tries. Sadly, cubicConicTests[0] |
| 2268 | gets stuck in a loop. It adds an extension to allow a coincident end |
| 2269 | perpendicular to track its intersection in the opposite curve. However, |
| 2270 | the bounding box of the extension does not intersect the original curve, |
caryclark | 55888e4 | 2016-07-18 10:01:36 -0700 | [diff] [blame] | 2271 | so the extension is discarded, only to be added again the next time around. */ |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 2272 | sect1->coincidentForce(sect2, start1s, start1e); |
| 2273 | sect1->validate(); |
| 2274 | sect2->validate(); |
| 2275 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2276 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2277 | if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT |
| 2278 | && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { |
Cary Clark | 59ed482 | 2016-12-08 16:17:56 -0500 | [diff] [blame] | 2279 | if (!sect1->fHead) { |
| 2280 | return; |
| 2281 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2282 | sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail()); |
Cary Clark | 59ed482 | 2016-12-08 16:17:56 -0500 | [diff] [blame] | 2283 | if (!sect2->fHead) { |
| 2284 | return; |
| 2285 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2286 | sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail()); |
Cary Clark | 0949bee | 2018-03-19 09:42:00 -0400 | [diff] [blame] | 2287 | if (!sect1->removeByPerpendicular(sect2)) { |
| 2288 | return; |
| 2289 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2290 | sect1->validate(); |
| 2291 | sect2->validate(); |
caryclark | 26ad22a | 2015-10-16 09:03:38 -0700 | [diff] [blame] | 2292 | #if DEBUG_T_SECT_LOOP_COUNT |
| 2293 | intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop); |
| 2294 | #endif |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2295 | if (sect1->collapsed() > TCurve::kMaxIntersections) { |
| 2296 | break; |
| 2297 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2298 | } |
| 2299 | #if DEBUG_T_SECT_DUMP |
| 2300 | sect1->dumpBoth(sect2); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2301 | #endif |
| 2302 | if (!sect1->fHead || !sect2->fHead) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2303 | break; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2304 | } |
| 2305 | } while (true); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2306 | SkTSpan<TCurve, OppCurve>* coincident = sect1->fCoincident; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2307 | if (coincident) { |
| 2308 | // if there is more than one coincident span, check loosely to see if they should be joined |
| 2309 | if (coincident->fNext) { |
| 2310 | sect1->mergeCoincidence(sect2); |
| 2311 | coincident = sect1->fCoincident; |
| 2312 | } |
| 2313 | SkASSERT(sect2->fCoincident); // courtesy check : coincidence only looks at sect 1 |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2314 | do { |
caryclark | 221a4bb | 2016-10-07 11:15:15 -0700 | [diff] [blame] | 2315 | if (!coincident) { |
| 2316 | return; |
| 2317 | } |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2318 | if (!coincident->fCoinStart.isMatch()) { |
caryclark | ef784fb | 2015-10-30 12:03:06 -0700 | [diff] [blame] | 2319 | continue; |
| 2320 | } |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2321 | if (!coincident->fCoinEnd.isMatch()) { |
caryclark | ef784fb | 2015-10-30 12:03:06 -0700 | [diff] [blame] | 2322 | continue; |
| 2323 | } |
Cary Clark | 6711638 | 2017-01-03 16:25:18 -0500 | [diff] [blame] | 2324 | double perpT = coincident->fCoinStart.perpT(); |
| 2325 | if (perpT < 0) { |
| 2326 | return; |
| 2327 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2328 | int index = intersections->insertCoincident(coincident->fStartT, |
Cary Clark | 6711638 | 2017-01-03 16:25:18 -0500 | [diff] [blame] | 2329 | perpT, coincident->fPart[0]); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2330 | if ((intersections->insertCoincident(coincident->fEndT, |
| 2331 | coincident->fCoinEnd.perpT(), |
| 2332 | coincident->fPart[TCurve::kPointLast]) < 0) && index >= 0) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2333 | intersections->clearCoincidence(index); |
| 2334 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2335 | } while ((coincident = coincident->fNext)); |
| 2336 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2337 | int zeroOneSet = EndsEqual(sect1, sect2, intersections); |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 2338 | // if (!sect1->fHead || !sect2->fHead) { |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2339 | // if the final iteration contains an end (0 or 1), |
| 2340 | if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) { |
| 2341 | SkTCoincident<TCurve, OppCurve> perp; // intersect perpendicular with opposite curve |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2342 | perp.setPerp(sect1->fCurve, 0, sect1->fCurve[0], sect2->fCurve); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2343 | if (perp.isMatch()) { |
| 2344 | intersections->insert(0, perp.perpT(), perp.perpPt()); |
| 2345 | } |
| 2346 | } |
| 2347 | if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) { |
| 2348 | SkTCoincident<TCurve, OppCurve> perp; |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2349 | perp.setPerp(sect1->fCurve, 1, sect1->fCurve[TCurve::kPointLast], sect2->fCurve); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2350 | if (perp.isMatch()) { |
| 2351 | intersections->insert(1, perp.perpT(), perp.perpPt()); |
| 2352 | } |
| 2353 | } |
| 2354 | if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) { |
| 2355 | SkTCoincident<OppCurve, TCurve> perp; |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2356 | perp.setPerp(sect2->fCurve, 0, sect2->fCurve[0], sect1->fCurve); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2357 | if (perp.isMatch()) { |
| 2358 | intersections->insert(perp.perpT(), 0, perp.perpPt()); |
| 2359 | } |
| 2360 | } |
| 2361 | if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) { |
| 2362 | SkTCoincident<OppCurve, TCurve> perp; |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2363 | perp.setPerp(sect2->fCurve, 1, sect2->fCurve[OppCurve::kPointLast], sect1->fCurve); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2364 | if (perp.isMatch()) { |
| 2365 | intersections->insert(perp.perpT(), 1, perp.perpPt()); |
| 2366 | } |
| 2367 | } |
caryclark | 34efb70 | 2016-10-24 08:19:06 -0700 | [diff] [blame] | 2368 | // } |
| 2369 | if (!sect1->fHead || !sect2->fHead) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2370 | return; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2371 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2372 | sect1->recoverCollapsed(); |
| 2373 | sect2->recoverCollapsed(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2374 | SkTSpan<TCurve, OppCurve>* result1 = sect1->fHead; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2375 | // check heads and tails for zero and ones and insert them if we haven't already done so |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2376 | const SkTSpan<TCurve, OppCurve>* head1 = result1; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2377 | if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStartT)) { |
| 2378 | const SkDPoint& start1 = sect1->fCurve[0]; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2379 | if (head1->isBounded()) { |
| 2380 | double t = head1->closestBoundedT(start1); |
| 2381 | if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) { |
| 2382 | intersections->insert(0, t, start1); |
| 2383 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2384 | } |
| 2385 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2386 | const SkTSpan<OppCurve, TCurve>* head2 = sect2->fHead; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2387 | if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStartT)) { |
| 2388 | const SkDPoint& start2 = sect2->fCurve[0]; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2389 | if (head2->isBounded()) { |
| 2390 | double t = head2->closestBoundedT(start2); |
| 2391 | if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) { |
| 2392 | intersections->insert(t, 0, start2); |
| 2393 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2394 | } |
| 2395 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2396 | const SkTSpan<TCurve, OppCurve>* tail1 = sect1->tail(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2397 | if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT)) { |
| 2398 | const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast]; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2399 | if (tail1->isBounded()) { |
| 2400 | double t = tail1->closestBoundedT(end1); |
| 2401 | if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) { |
| 2402 | intersections->insert(1, t, end1); |
| 2403 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2404 | } |
| 2405 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2406 | const SkTSpan<OppCurve, TCurve>* tail2 = sect2->tail(); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2407 | if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT)) { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2408 | const SkDPoint& end2 = sect2->fCurve[OppCurve::kPointLast]; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2409 | if (tail2->isBounded()) { |
| 2410 | double t = tail2->closestBoundedT(end2); |
| 2411 | if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) { |
| 2412 | intersections->insert(t, 1, end2); |
| 2413 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2414 | } |
| 2415 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2416 | SkClosestSect<TCurve, OppCurve> closest; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2417 | do { |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2418 | while (result1 && result1->fCoinStart.isMatch() && result1->fCoinEnd.isMatch()) { |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2419 | result1 = result1->fNext; |
| 2420 | } |
| 2421 | if (!result1) { |
| 2422 | break; |
| 2423 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2424 | SkTSpan<OppCurve, TCurve>* result2 = sect2->fHead; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2425 | bool found = false; |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2426 | while (result2) { |
caryclark | cdeff81 | 2016-07-22 03:34:19 -0700 | [diff] [blame] | 2427 | found |= closest.find(result1, result2 SkDEBUGPARAMS(intersections)); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2428 | result2 = result2->fNext; |
| 2429 | } |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2430 | } while ((result1 = result1->fNext)); |
| 2431 | closest.finish(intersections); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2432 | // if there is more than one intersection and it isn't already coincident, check |
| 2433 | int last = intersections->used() - 1; |
| 2434 | for (int index = 0; index < last; ) { |
| 2435 | if (intersections->isCoincident(index) && intersections->isCoincident(index + 1)) { |
| 2436 | ++index; |
| 2437 | continue; |
| 2438 | } |
| 2439 | double midT = ((*intersections)[0][index] + (*intersections)[0][index + 1]) / 2; |
| 2440 | SkDPoint midPt = sect1->fCurve.ptAtT(midT); |
| 2441 | // intersect perpendicular with opposite curve |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 2442 | SkTCoincident<TCurve, OppCurve> perp; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2443 | perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve); |
caryclark | 6c3b9cd | 2016-09-26 05:36:58 -0700 | [diff] [blame] | 2444 | if (!perp.isMatch()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 2445 | ++index; |
| 2446 | continue; |
| 2447 | } |
| 2448 | if (intersections->isCoincident(index)) { |
| 2449 | intersections->removeOne(index); |
| 2450 | --last; |
| 2451 | } else if (intersections->isCoincident(index + 1)) { |
| 2452 | intersections->removeOne(index + 1); |
| 2453 | --last; |
| 2454 | } else { |
| 2455 | intersections->setCoincident(index++); |
| 2456 | } |
| 2457 | intersections->setCoincident(index); |
| 2458 | } |
caryclark | a35ab3e | 2016-10-20 08:32:18 -0700 | [diff] [blame] | 2459 | SkOPOBJASSERT(intersections, intersections->used() <= TCurve::kMaxIntersections); |
caryclark | 45fa447 | 2015-01-16 07:04:10 -0800 | [diff] [blame] | 2460 | } |
deanm | 12670eb | 2016-04-26 14:09:01 -0700 | [diff] [blame] | 2461 | |
| 2462 | #endif |