OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkChunkAlloc.h" | 8 #include "SkChunkAlloc.h" |
| 9 #include "SkPathOpsBounds.h" |
9 #include "SkPathOpsRect.h" | 10 #include "SkPathOpsRect.h" |
10 #include "SkPathOpsQuad.h" | 11 #include "SkPathOpsQuad.h" |
11 #include "SkIntersections.h" | 12 #include "SkIntersections.h" |
12 #include "SkTArray.h" | 13 #include "SkTSort.h" |
13 | 14 |
14 /* TCurve is either SkDQuadratic or SkDCubic */ | 15 /* TCurve is either SkDQuadratic or SkDCubic */ |
15 template<typename TCurve> | 16 template<typename TCurve> |
16 class SkTCoincident { | 17 class SkTCoincident { |
17 public: | 18 public: |
| 19 SkTCoincident() |
| 20 : fCoincident(false) { |
| 21 } |
| 22 |
| 23 void clear() { |
| 24 fPerpT = -1; |
| 25 fCoincident = false; |
| 26 } |
| 27 |
18 bool isCoincident() const { | 28 bool isCoincident() const { |
19 return fCoincident; | 29 return fCoincident; |
20 } | 30 } |
21 | 31 |
22 void init() { | 32 void init() { |
23 fCoincident = false; | 33 fCoincident = false; |
24 SkDEBUGCODE(fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN); | 34 SkDEBUGCODE(fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN); |
25 SkDEBUGCODE(fPerpT = SK_ScalarNaN); | 35 SkDEBUGCODE(fPerpT = SK_ScalarNaN); |
26 } | 36 } |
27 | 37 |
(...skipping 19 matching lines...) Expand all Loading... |
47 double fPerpT; // perpendicular intersection on opposite curve | 57 double fPerpT; // perpendicular intersection on opposite curve |
48 bool fCoincident; | 58 bool fCoincident; |
49 }; | 59 }; |
50 | 60 |
51 template<typename TCurve> class SkTSect; | 61 template<typename TCurve> class SkTSect; |
52 | 62 |
53 /* Curve is either TCurve or SkDCubic */ | 63 /* Curve is either TCurve or SkDCubic */ |
54 template<typename TCurve> | 64 template<typename TCurve> |
55 class SkTSpan { | 65 class SkTSpan { |
56 public: | 66 public: |
57 void init(const TCurve& ); | 67 void addBounded(SkTSpan* ); |
58 void initBounds(const TCurve& ); | 68 double closestBoundedT(const SkDPoint& pt) const; |
| 69 bool contains(double t) const; |
59 | 70 |
60 double closestBoundedT(const SkDPoint& pt) const; | 71 const SkTSect<TCurve>* debugOpp() const; |
61 | 72 const SkTSpan* debugSpan(int ) const; |
62 bool contains(double t) const { | 73 const SkTSpan* debugT(double t) const; |
63 return !! const_cast<SkTSpan*>(this)->innerFind(t); | 74 #ifdef SK_DEBUG |
64 } | 75 bool debugIsBefore(const SkTSpan* span) const; |
65 | 76 #endif |
66 bool contains(const SkTSpan* span) const; | 77 void dump() const; |
| 78 void dumpBounds(int id) const; |
67 | 79 |
68 double endT() const { | 80 double endT() const { |
69 return fEndT; | 81 return fEndT; |
70 } | 82 } |
71 | 83 |
72 SkTSpan* find(double t) { | 84 SkTSpan* findOppSpan(const SkTSpan* opp) const; |
73 SkTSpan* result = innerFind(t); | 85 |
| 86 SkTSpan* findOppT(double t) const { |
| 87 SkTSpan* result = oppT(t); |
74 SkASSERT(result); | 88 SkASSERT(result); |
75 return result; | 89 return result; |
76 } | 90 } |
77 | 91 |
78 bool intersects(const SkTSpan* span, bool* check); | 92 bool hasOppT(double t) const { |
| 93 return SkToBool(oppT(t)); |
| 94 } |
| 95 |
| 96 int hullsIntersect(SkTSpan* span, bool* start, bool* oppStart); |
| 97 void init(const TCurve& ); |
| 98 void initBounds(const TCurve& ); |
| 99 |
| 100 bool isBounded() const { |
| 101 return fBounded.count() > 0; |
| 102 } |
| 103 |
| 104 bool linearsIntersect(SkTSpan* span); |
| 105 double linearT(const SkDPoint& ) const; |
| 106 |
| 107 void markCoincident() { |
| 108 fCoinStart.markCoincident(); |
| 109 fCoinEnd.markCoincident(); |
| 110 } |
79 | 111 |
80 const SkTSpan* next() const { | 112 const SkTSpan* next() const { |
81 return fNext; | 113 return fNext; |
82 } | 114 } |
83 | 115 |
| 116 bool onlyEndPointsInCommon(const SkTSpan* opp, bool* start, bool* oppStart,
bool* ptsInCommon); |
| 117 |
84 const TCurve& part() const { | 118 const TCurve& part() const { |
85 return fPart; | 119 return fPart; |
86 } | 120 } |
87 | 121 |
| 122 bool removeAllBounded(); |
| 123 bool removeBounded(const SkTSpan* opp); |
| 124 |
88 void reset() { | 125 void reset() { |
89 fBounded.reset(); | 126 fBounded.reset(); |
90 } | 127 } |
91 | 128 |
| 129 void resetBounds(const TCurve& curve) { |
| 130 fIsLinear = fIsLine = false; |
| 131 initBounds(curve); |
| 132 } |
| 133 |
92 bool split(SkTSpan* work) { | 134 bool split(SkTSpan* work) { |
93 return splitAt(work, (work->fStartT + work->fEndT) * 0.5); | 135 return splitAt(work, (work->fStartT + work->fEndT) * 0.5); |
94 } | 136 } |
95 | 137 |
96 bool splitAt(SkTSpan* work, double t); | 138 bool splitAt(SkTSpan* work, double t); |
97 | 139 |
98 double startT() const { | 140 double startT() const { |
99 return fStartT; | 141 return fStartT; |
100 } | 142 } |
101 | 143 |
102 bool tightBoundsIntersects(const SkTSpan* span) const; | 144 private: |
103 | 145 |
104 // implementation is for testing only | 146 // implementation is for testing only |
105 void dump() const { | 147 int debugID() const { |
106 dump(NULL); | 148 return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); |
107 } | 149 } |
108 | 150 |
109 private: | 151 void dumpID() const; |
110 SkTSpan* innerFind(double t); | |
111 bool linearIntersects(const TCurve& ) const; | |
112 | 152 |
113 // implementation is for testing only | 153 int hullCheck(const SkTSpan* opp, bool* start, bool* oppStart); |
114 #if DEBUG_T_SECT | 154 int linearIntersects(const TCurve& ) const; |
115 int debugID(const SkTSect<TCurve>* ) const { return fDebugID; } | 155 SkTSpan* oppT(double t) const; |
116 #else | |
117 int debugID(const SkTSect<TCurve>* ) const; | |
118 #endif | |
119 void dump(const SkTSect<TCurve>* ) const; | |
120 void dumpID(const SkTSect<TCurve>* ) const; | |
121 | 156 |
122 #if DEBUG_T_SECT | |
123 void validate() const; | 157 void validate() const; |
124 #endif | 158 void validateBounded() const; |
| 159 void validatePerpT(double oppT) const; |
| 160 void validatePerpPt(double t, const SkDPoint& ) const; |
125 | 161 |
126 TCurve fPart; | 162 TCurve fPart; |
127 SkTCoincident<TCurve> fCoinStart; | 163 SkTCoincident<TCurve> fCoinStart; |
128 SkTCoincident<TCurve> fCoinEnd; | 164 SkTCoincident<TCurve> fCoinEnd; |
129 SkSTArray<4, SkTSpan*, true> fBounded; | 165 SkSTArray<4, SkTSpan*, true> fBounded; |
130 SkTSpan* fPrev; | 166 SkTSpan* fPrev; |
131 SkTSpan* fNext; | 167 SkTSpan* fNext; |
132 SkDRect fBounds; | 168 SkDRect fBounds; |
133 double fStartT; | 169 double fStartT; |
134 double fEndT; | 170 double fEndT; |
135 double fBoundsMax; | 171 double fBoundsMax; |
136 bool fCollapsed; | 172 bool fCollapsed; |
137 bool fHasPerp; | 173 bool fHasPerp; |
138 bool fIsLinear; | 174 bool fIsLinear; |
139 #if DEBUG_T_SECT | 175 bool fIsLine; |
140 int fDebugID; | 176 bool fDeleted; |
141 bool fDebugDeleted; | 177 PATH_OPS_DEBUG_CODE(SkTSect<TCurve>* fDebugSect); |
142 #endif | 178 PATH_OPS_DEBUG_T_SECT_CODE(int fID); |
143 friend class SkTSect<TCurve>; | 179 friend class SkTSect<TCurve>; |
144 }; | 180 }; |
145 | 181 |
146 template<typename TCurve> | 182 template<typename TCurve> |
147 class SkTSect { | 183 class SkTSect { |
148 public: | 184 public: |
149 SkTSect(const TCurve& c PATH_OPS_DEBUG_PARAMS(int id)); | 185 SkTSect(const TCurve& c PATH_OPS_DEBUG_T_SECT_PARAMS(int id)); |
150 static void BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersections* in
tersections); | 186 static void BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersections* in
tersections); |
151 | 187 |
152 // for testing only | 188 // for testing only |
| 189 bool debugHasBounded(const SkTSpan<TCurve>* ) const; |
| 190 |
| 191 const SkTSect* debugOpp() const { |
| 192 return PATH_OPS_DEBUG_RELEASE(fOppSect, NULL); |
| 193 } |
| 194 |
| 195 const SkTSpan<TCurve>* debugSpan(int id) const; |
| 196 const SkTSpan<TCurve>* debugT(double t) const; |
153 void dump() const; | 197 void dump() const; |
154 void dumpBoth(const SkTSect& opp) const; | 198 void dumpBoth(SkTSect* ) const; |
155 void dumpBoth(const SkTSect* opp) const; | 199 void dumpBounds(int id) const; |
| 200 void dumpCoin() const; |
| 201 void dumpCoinCurves() const; |
156 void dumpCurves() const; | 202 void dumpCurves() const; |
157 | 203 |
158 private: | 204 private: |
159 enum { | 205 enum { |
160 kZeroS1Set = 1, | 206 kZeroS1Set = 1, |
161 kOneS1Set = 2, | 207 kOneS1Set = 2, |
162 kZeroS2Set = 4, | 208 kZeroS2Set = 4, |
163 kOneS2Set = 8 | 209 kOneS2Set = 8 |
164 }; | 210 }; |
165 | 211 |
| 212 SkTSpan<TCurve>* addFollowing(SkTSpan<TCurve>* prior); |
| 213 void addForPerp(SkTSpan<TCurve>* span, double t); |
166 SkTSpan<TCurve>* addOne(); | 214 SkTSpan<TCurve>* addOne(); |
167 bool binarySearchCoin(const SkTSect& , double tStart, double tStep, double*
t, double* oppT); | 215 |
| 216 SkTSpan<TCurve>* addSplitAt(SkTSpan<TCurve>* span, double t) { |
| 217 SkTSpan<TCurve>* result = this->addOne(); |
| 218 result->splitAt(span, t); |
| 219 result->initBounds(fCurve); |
| 220 span->initBounds(fCurve); |
| 221 return result; |
| 222 } |
| 223 |
| 224 bool binarySearchCoin(SkTSect* , double tStart, double tStep, double* t, dou
ble* oppT); |
168 SkTSpan<TCurve>* boundsMax() const; | 225 SkTSpan<TCurve>* boundsMax() const; |
169 void coincidentCheck(SkTSect* sect2); | 226 void coincidentCheck(SkTSect* sect2); |
| 227 bool coincidentHasT(double t); |
| 228 void computePerpendiculars(SkTSect* sect2, SkTSpan<TCurve>* first, SkTSpan<T
Curve>* last); |
| 229 int countConsecutiveSpans(SkTSpan<TCurve>* first, SkTSpan<TCurve>** last) co
nst; |
| 230 |
| 231 int debugID() const { |
| 232 return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); |
| 233 } |
| 234 |
| 235 void deleteEmptySpans(); |
| 236 void dumpCommon(const SkTSpan<TCurve>* ) const; |
| 237 void dumpCommonCurves(const SkTSpan<TCurve>* ) const; |
170 static int EndsEqual(const SkTSect* sect1, const SkTSect* sect2, SkIntersect
ions* ); | 238 static int EndsEqual(const SkTSect* sect1, const SkTSect* sect2, SkIntersect
ions* ); |
171 bool intersects(SkTSpan<TCurve>* span, const SkTSect* opp, | 239 SkTSpan<TCurve>* extractCoincident(SkTSect* sect2, SkTSpan<TCurve>* first, |
172 const SkTSpan<TCurve>* oppSpan) const; | 240 SkTSpan<TCurve>* last); |
173 void onCurveCheck(SkTSect* sect2, SkTSpan<TCurve>* first, SkTSpan<TCurve>* l
ast); | 241 SkTSpan<TCurve>* findCoincidentRun(SkTSpan<TCurve>* first, SkTSpan<TCurve>**
lastPtr, |
| 242 const SkTSect* sect2); |
| 243 int intersects(SkTSpan<TCurve>* span, const SkTSect* opp, |
| 244 SkTSpan<TCurve>* oppSpan, int* oppResult) const; |
| 245 int linesIntersect(const SkTSpan<TCurve>* span, const SkTSect* opp, |
| 246 const SkTSpan<TCurve>* oppSpan, SkIntersections* ) const; |
| 247 void markSpanGone(SkTSpan<TCurve>* span); |
| 248 bool matchedDirection(double t, const SkTSect* sect2, double t2) const; |
| 249 void matchedDirCheck(double t, const SkTSect* sect2, double t2, |
| 250 bool* calcMatched, bool* oppMatched) const; |
| 251 void mergeCoincidence(SkTSect* sect2); |
| 252 SkTSpan<TCurve>* prev(SkTSpan<TCurve>* ) const; |
| 253 void removeByPerpendicular(SkTSect* opp); |
174 void recoverCollapsed(); | 254 void recoverCollapsed(); |
| 255 void removeCoincident(SkTSpan<TCurve>* span, bool isBetween); |
| 256 void removeAllBut(const SkTSpan<TCurve>* keep, SkTSpan<TCurve>* span, SkTSec
t* opp); |
175 void removeSpan(SkTSpan<TCurve>* span); | 257 void removeSpan(SkTSpan<TCurve>* span); |
176 void removeOne(const SkTSpan<TCurve>* test, SkTSpan<TCurve>* span); | 258 void removeSpanRange(SkTSpan<TCurve>* first, SkTSpan<TCurve>* last); |
177 void removeSpans(SkTSpan<TCurve>* span, SkTSect* opp); | 259 void removeSpans(SkTSpan<TCurve>* span, SkTSect* opp); |
178 void setPerp(const TCurve& opp, SkTSpan<TCurve>* first, SkTSpan<TCurve>* las
t); | 260 SkTSpan<TCurve>* spanAtT(double t, SkTSpan<TCurve>** priorSpan); |
179 const SkTSpan<TCurve>* tail() const; | 261 SkTSpan<TCurve>* tail(); |
180 void trim(SkTSpan<TCurve>* span, SkTSect* opp); | 262 void trim(SkTSpan<TCurve>* span, SkTSect* opp); |
| 263 void unlinkSpan(SkTSpan<TCurve>* span); |
| 264 bool updateBounded(SkTSpan<TCurve>* first, SkTSpan<TCurve>* last, SkTSpan<TC
urve>* oppFirst); |
| 265 void validate() const; |
| 266 void validateBounded() const; |
181 | 267 |
182 #if DEBUG_T_SECT | |
183 int debugID() const { return fDebugID; } | |
184 void validate() const; | |
185 #else | |
186 int debugID() const { return 0; } | |
187 #endif | |
188 const TCurve& fCurve; | 268 const TCurve& fCurve; |
189 SkChunkAlloc fHeap; | 269 SkChunkAlloc fHeap; |
190 SkTSpan<TCurve>* fHead; | 270 SkTSpan<TCurve>* fHead; |
| 271 SkTSpan<TCurve>* fCoincident; |
191 SkTSpan<TCurve>* fDeleted; | 272 SkTSpan<TCurve>* fDeleted; |
192 int fActiveCount; | 273 int fActiveCount; |
| 274 PATH_OPS_DEBUG_CODE(SkTSect* fOppSect); |
| 275 PATH_OPS_DEBUG_T_SECT_CODE(int fID); |
| 276 PATH_OPS_DEBUG_T_SECT_CODE(int fDebugCount); |
193 #if DEBUG_T_SECT | 277 #if DEBUG_T_SECT |
194 int fDebugID; | |
195 int fDebugCount; | |
196 int fDebugAllocatedCount; | 278 int fDebugAllocatedCount; |
197 #endif | 279 #endif |
198 friend class SkTSpan<TCurve>; // only used by debug id | 280 friend class SkTSpan<TCurve>; // only used by debug id |
199 }; | 281 }; |
200 | 282 |
201 #define COINCIDENT_SPAN_COUNT 9 | 283 #define COINCIDENT_SPAN_COUNT 9 |
202 | 284 |
203 template<typename TCurve> | 285 template<typename TCurve> |
204 void SkTCoincident<TCurve>::setPerp(const TCurve& c1, double t, | 286 void SkTCoincident<TCurve>::setPerp(const TCurve& c1, double t, |
205 const SkDPoint& cPt, const TCurve& c2) { | 287 const SkDPoint& cPt, const TCurve& c2) { |
206 SkDVector dxdy = c1.dxdyAtT(t); | 288 SkDVector dxdy = c1.dxdyAtT(t); |
207 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; | 289 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; |
208 SkIntersections i; | 290 SkIntersections i; |
209 int used = i.intersectRay(c2, perp); | 291 int used = i.intersectRay(c2, perp); |
210 // only keep closest | 292 // only keep closest |
211 if (used == 0) { | 293 if (used == 0 || used == 3) { |
212 fPerpT = -1; | 294 this->clear(); |
213 return; | 295 return; |
214 } | 296 } |
215 fPerpT = i[0][0]; | 297 fPerpT = i[0][0]; |
216 fPerpPt = i.pt(0); | 298 fPerpPt = i.pt(0); |
217 SkASSERT(used <= 2); | 299 SkASSERT(used <= 2); |
218 if (used == 2) { | 300 if (used == 2) { |
219 double distSq = (fPerpPt - cPt).lengthSquared(); | 301 double distSq = (fPerpPt - cPt).lengthSquared(); |
220 double dist2Sq = (i.pt(1) - cPt).lengthSquared(); | 302 double dist2Sq = (i.pt(1) - cPt).lengthSquared(); |
221 if (dist2Sq < distSq) { | 303 if (dist2Sq < distSq) { |
222 fPerpT = i[0][1]; | 304 fPerpT = i[0][1]; |
223 fPerpPt = i.pt(1); | 305 fPerpPt = i.pt(1); |
224 } | 306 } |
225 } | 307 } |
| 308 #if DEBUG_T_SECT |
| 309 SkDebugf("%s cPt=(%1.9g,%1.9g) %s fPerpPt=(%1.9g,%1.9g)\n", __FUNCTION__, cP
t.fX, cPt.fY, |
| 310 cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpPt.fX, fPerpPt.f
Y); |
| 311 #endif |
226 fCoincident = cPt.approximatelyEqual(fPerpPt); | 312 fCoincident = cPt.approximatelyEqual(fPerpPt); |
227 #if DEBUG_T_SECT | 313 #if DEBUG_T_SECT |
228 if (fCoincident) { | 314 if (fCoincident) { |
229 SkDebugf(""); // allow setting breakpoint | 315 SkDebugf(""); // allow setting breakpoint |
230 } | 316 } |
231 #endif | 317 #endif |
232 } | 318 } |
233 | 319 |
234 template<typename TCurve> | 320 template<typename TCurve> |
235 void SkTSpan<TCurve>::init(const TCurve& c) { | 321 void SkTSpan<TCurve>::addBounded(SkTSpan* span) { |
236 fPrev = fNext = NULL; | 322 if (this->findOppSpan(span)) { |
237 fIsLinear = false; | 323 return; |
238 fStartT = 0; | 324 } |
239 fEndT = 1; | 325 fBounded.push_back() = span; |
240 initBounds(c); | |
241 } | 326 } |
242 | 327 |
243 template<typename TCurve> | 328 template<typename TCurve> |
244 void SkTSpan<TCurve>::initBounds(const TCurve& c) { | 329 SkTSpan<TCurve>* SkTSect<TCurve>::addFollowing(SkTSpan<TCurve>* prior) { |
245 fPart = c.subDivide(fStartT, fEndT); | 330 SkTSpan<TCurve>* result = this->addOne(); |
246 fBounds.setBounds(fPart); | 331 result->fStartT = prior ? prior->fEndT : 0; |
247 fCoinStart.init(); | 332 SkTSpan<TCurve>* next = prior ? prior->fNext : fHead; |
248 fCoinEnd.init(); | 333 result->fEndT = next ? next->fStartT : 1; |
249 fBoundsMax = SkTMax(fBounds.width(), fBounds.height()); | 334 result->fPrev = prior; |
250 fCollapsed = fPart.collapsed(); | 335 result->fNext = next; |
251 fHasPerp = false; | 336 if (prior) { |
252 #if DEBUG_T_SECT | 337 prior->fNext = result; |
253 fDebugDeleted = false; | 338 } else { |
254 if (fCollapsed) { | 339 fHead = result; |
255 SkDebugf(""); // for convenient breakpoints | |
256 } | 340 } |
257 #endif | 341 if (next) { |
| 342 next->fPrev = result; |
| 343 } |
| 344 result->resetBounds(fCurve); |
| 345 return result; |
258 } | 346 } |
259 | 347 |
260 template<typename TCurve> | 348 template<typename TCurve> |
| 349 void SkTSect<TCurve>::addForPerp(SkTSpan<TCurve>* span, double t) { |
| 350 if (!span->hasOppT(t)) { |
| 351 SkTSpan<TCurve>* priorSpan; |
| 352 SkTSpan<TCurve>* opp = this->spanAtT(t, &priorSpan); |
| 353 if (!opp) { |
| 354 opp = this->addFollowing(priorSpan); |
| 355 #if DEBUG_PERP |
| 356 SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan
->debugID(), t, |
| 357 opp->debugID()); |
| 358 #endif |
| 359 } |
| 360 #if DEBUG_PERP |
| 361 opp->dump(); SkDebugf("\n"); |
| 362 SkDebugf("%s fBounded.push_back span=%d opp=%d\n", __FUNCTION__, priorSp
an->debugID(), |
| 363 opp->debugID()); |
| 364 #endif |
| 365 opp->fBounded.push_back(span); |
| 366 span->fBounded.push_back(opp); |
| 367 } |
| 368 this->validate(); |
| 369 span->validatePerpT(t); |
| 370 } |
| 371 |
| 372 template<typename TCurve> |
261 double SkTSpan<TCurve>::closestBoundedT(const SkDPoint& pt) const { | 373 double SkTSpan<TCurve>::closestBoundedT(const SkDPoint& pt) const { |
262 int count = fBounded.count(); | 374 int count = fBounded.count(); |
263 double result = -1; | 375 double result = -1; |
264 double closest = FLT_MAX; | 376 double closest = FLT_MAX; |
265 for (int index = 0; index < count; ++index) { | 377 for (int index = 0; index < count; ++index) { |
266 const SkTSpan* test = fBounded[index]; | 378 const SkTSpan* test = fBounded[index]; |
267 double startDist = test->fPart[0].distanceSquared(pt); | 379 double startDist = test->fPart[0].distanceSquared(pt); |
268 if (closest > startDist) { | 380 if (closest > startDist) { |
269 closest = startDist; | 381 closest = startDist; |
270 result = test->fStartT; | 382 result = test->fStartT; |
271 } | 383 } |
272 double endDist = test->fPart[TCurve::kPointLast].distanceSquared(pt); | 384 double endDist = test->fPart[TCurve::kPointLast].distanceSquared(pt); |
273 if (closest > endDist) { | 385 if (closest > endDist) { |
274 closest = endDist; | 386 closest = endDist; |
275 result = test->fEndT; | 387 result = test->fEndT; |
276 } | 388 } |
277 } | 389 } |
278 SkASSERT(between(0, result, 1)); | 390 SkASSERT(between(0, result, 1)); |
279 return result; | 391 return result; |
280 } | 392 } |
281 | 393 |
| 394 #ifdef SK_DEBUG |
282 template<typename TCurve> | 395 template<typename TCurve> |
283 bool SkTSpan<TCurve>::contains(const SkTSpan* span) const { | 396 bool SkTSpan<TCurve>::debugIsBefore(const SkTSpan* span) const { |
284 int count = fBounded.count(); | 397 const SkTSpan* work = this; |
285 for (int index = 0; index < count; ++index) { | 398 do { |
286 const SkTSpan* test = fBounded[index]; | 399 if (span == work) { |
287 if (span == test) { | |
288 return true; | 400 return true; |
289 } | 401 } |
290 } | 402 } while ((work = work->fNext)); |
| 403 return false; |
| 404 } |
| 405 #endif |
| 406 |
| 407 template<typename TCurve> |
| 408 bool SkTSpan<TCurve>::contains(double t) const { |
| 409 const SkTSpan* work = this; |
| 410 do { |
| 411 if (between(work->fStartT, t, work->fEndT)) { |
| 412 return true; |
| 413 } |
| 414 } while ((work = work->fNext)); |
291 return false; | 415 return false; |
292 } | 416 } |
293 | 417 |
294 template<typename TCurve> | 418 template<typename TCurve> |
295 SkTSpan<TCurve>* SkTSpan<TCurve>::innerFind(double t) { | 419 const SkTSect<TCurve>* SkTSpan<TCurve>::debugOpp() const { |
296 SkTSpan* work = this; | 420 return PATH_OPS_DEBUG_RELEASE(fDebugSect->debugOpp(), NULL); |
297 do { | 421 } |
298 if (between(work->fStartT, t, work->fEndT)) { | 422 |
299 return work; | 423 template<typename TCurve> |
| 424 SkTSpan<TCurve>* SkTSpan<TCurve>::findOppSpan(const SkTSpan* opp) const { |
| 425 int count = fBounded.count(); |
| 426 for (int index = 0; index < count; ++index) { |
| 427 SkTSpan* test = fBounded[index]; |
| 428 if (opp == test) { |
| 429 return test; |
300 } | 430 } |
301 } while ((work = work->fNext)); | 431 } |
302 return NULL; | 432 return NULL; |
303 } | 433 } |
304 | 434 |
| 435 // returns 0 if no hull intersection |
| 436 // 1 if hulls intersect |
| 437 // 2 if hulls only share a common endpoint |
| 438 // -1 if linear and further checking is required |
| 439 template<typename TCurve> |
| 440 int SkTSpan<TCurve>::hullCheck(const SkTSpan* opp, bool* start, bool* oppStart)
{ |
| 441 if (fIsLinear) { |
| 442 return -1; |
| 443 } |
| 444 bool ptsInCommon; |
| 445 if (onlyEndPointsInCommon(opp, start, oppStart, &ptsInCommon)) { |
| 446 SkASSERT(ptsInCommon); |
| 447 return 2; |
| 448 } |
| 449 bool linear; |
| 450 if (fPart.hullIntersects(opp->fPart, &linear)) { |
| 451 if (!linear) { // check set true if linear |
| 452 return 1; |
| 453 } |
| 454 fIsLinear = true; |
| 455 fIsLine = fPart.controlsInside(); |
| 456 return ptsInCommon ? 2 : -1; |
| 457 } else { // hull is not linear; check set true if intersected at the end po
ints |
| 458 return ((int) ptsInCommon) << 1; // 0 or 2 |
| 459 } |
| 460 return 0; |
| 461 } |
| 462 |
305 // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear, | 463 // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear, |
306 // use line intersection to guess a better split than 0.5 | 464 // use line intersection to guess a better split than 0.5 |
307 // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all futu
re splits are linear | 465 // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all futu
re splits are linear |
308 template<typename TCurve> | 466 template<typename TCurve> |
309 bool SkTSpan<TCurve>::intersects(const SkTSpan* span, bool* check) { | 467 int SkTSpan<TCurve>::hullsIntersect(SkTSpan* opp, bool* start, bool* oppStart) { |
310 if (!fBounds.intersects(span->fBounds)) { | 468 if (!fBounds.intersects(opp->fBounds)) { |
311 *check = false; // no need to check to see if the bounds have end point
s in common | 469 return 0; |
312 return false; | |
313 } | 470 } |
314 if (!fIsLinear && fPart.hullIntersects(span->fPart, check)) { | 471 int hullSect = this->hullCheck(opp, start, oppStart); |
315 if (!*check) { | 472 if (hullSect >= 0) { |
316 return true; | 473 return hullSect; |
317 } | |
318 fIsLinear = true; | |
319 } | 474 } |
320 if (fIsLinear) { | 475 hullSect = opp->hullCheck(this, oppStart, start); |
321 *check = false; | 476 if (hullSect >= 0) { |
322 return linearIntersects(span->fPart); | 477 return hullSect; |
323 } | 478 } |
324 return *check; | 479 return -1; |
325 } | 480 } |
326 | 481 |
327 template<typename TCurve> | 482 template<typename TCurve> |
328 bool SkTSpan<TCurve>::linearIntersects(const TCurve& q2) const { | 483 void SkTSpan<TCurve>::init(const TCurve& c) { |
| 484 fPrev = fNext = NULL; |
| 485 fStartT = 0; |
| 486 fEndT = 1; |
| 487 resetBounds(c); |
| 488 } |
| 489 |
| 490 template<typename TCurve> |
| 491 void SkTSpan<TCurve>::initBounds(const TCurve& c) { |
| 492 fPart = c.subDivide(fStartT, fEndT); |
| 493 fBounds.setBounds(fPart); |
| 494 fCoinStart.init(); |
| 495 fCoinEnd.init(); |
| 496 fBoundsMax = SkTMax(fBounds.width(), fBounds.height()); |
| 497 fCollapsed = fPart.collapsed(); |
| 498 fHasPerp = false; |
| 499 fDeleted = false; |
| 500 #if DEBUG_T_SECT |
| 501 if (fCollapsed) { |
| 502 SkDebugf(""); // for convenient breakpoints |
| 503 } |
| 504 #endif |
| 505 } |
| 506 |
| 507 template<typename TCurve> |
| 508 bool SkTSpan<TCurve>::linearsIntersect(SkTSpan* span) { |
| 509 int result = this->linearIntersects(span->fPart); |
| 510 if (result <= 1) { |
| 511 return SkToBool(result); |
| 512 } |
| 513 SkASSERT(span->fIsLinear); |
| 514 result = span->linearIntersects(this->fPart); |
| 515 // SkASSERT(result <= 1); |
| 516 return SkToBool(result); |
| 517 } |
| 518 |
| 519 template<typename TCurve> |
| 520 double SkTSpan<TCurve>::linearT(const SkDPoint& pt) const { |
| 521 SkDVector len = fPart[TCurve::kPointLast] - fPart[0]; |
| 522 return fabs(len.fX) > fabs(len.fY) |
| 523 ? (pt.fX - fPart[0].fX) / len.fX |
| 524 : (pt.fY - fPart[0].fY) / len.fY; |
| 525 } |
| 526 |
| 527 template<typename TCurve> |
| 528 int SkTSpan<TCurve>::linearIntersects(const TCurve& q2) const { |
329 // looks like q1 is near-linear | 529 // looks like q1 is near-linear |
330 int start = 0, end = TCurve::kPointCount - 1; // the outside points are usu
ally the extremes | 530 int start = 0, end = TCurve::kPointLast; // the outside points are usually
the extremes |
331 if (!fPart.controlsInside()) { | 531 if (!fPart.controlsInside()) { |
332 double dist = 0; // if there's any question, compute distance to find b
est outsiders | 532 double dist = 0; // if there's any question, compute distance to find b
est outsiders |
333 for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) { | 533 for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) { |
334 for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) { | 534 for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) { |
335 double test = (fPart[outer] - fPart[inner]).lengthSquared(); | 535 double test = (fPart[outer] - fPart[inner]).lengthSquared(); |
336 if (dist > test) { | 536 if (dist > test) { |
337 continue; | 537 continue; |
338 } | 538 } |
339 dist = test; | 539 dist = test; |
340 start = outer; | 540 start = outer; |
341 end = inner; | 541 end = inner; |
342 } | 542 } |
343 } | 543 } |
344 } | 544 } |
345 // see if q2 is on one side of the line formed by the extreme points | 545 // see if q2 is on one side of the line formed by the extreme points |
346 double origX = fPart[start].fX; | 546 double origX = fPart[start].fX; |
347 double origY = fPart[start].fY; | 547 double origY = fPart[start].fY; |
348 double adj = fPart[end].fX - origX; | 548 double adj = fPart[end].fX - origX; |
349 double opp = fPart[end].fY - origY; | 549 double opp = fPart[end].fY - origY; |
350 double sign; | 550 double maxPart = SkTMax(fabs(adj), fabs(opp)); |
| 551 double sign = 0; // initialization to shut up warning in release build |
351 for (int n = 0; n < TCurve::kPointCount; ++n) { | 552 for (int n = 0; n < TCurve::kPointCount; ++n) { |
| 553 double dx = q2[n].fY - origY; |
| 554 double dy = q2[n].fX - origX; |
| 555 double maxVal = SkTMax(maxPart, SkTMax(fabs(dx), fabs(dy))); |
352 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; | 556 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; |
353 if (precisely_zero(test)) { | 557 if (precisely_zero_when_compared_to(test, maxVal)) { |
354 return true; | 558 return 1; |
| 559 } |
| 560 if (approximately_zero_when_compared_to(test, maxVal)) { |
| 561 return 3; |
355 } | 562 } |
356 if (n == 0) { | 563 if (n == 0) { |
357 sign = test; | 564 sign = test; |
358 continue; | 565 continue; |
359 } | 566 } |
360 if (test * sign < 0) { | 567 if (test * sign < 0) { |
361 return true; | 568 return 1; |
362 } | 569 } |
363 } | 570 } |
| 571 return 0; |
| 572 } |
| 573 |
| 574 template<typename TCurve> |
| 575 bool SkTSpan<TCurve>::onlyEndPointsInCommon(const SkTSpan* opp, bool* start, boo
l* oppStart, |
| 576 bool* ptsInCommon) { |
| 577 if (opp->fPart[0] == fPart[0]) { |
| 578 *start = *oppStart = true; |
| 579 } else if (opp->fPart[0] == fPart[TCurve::kPointLast]) { |
| 580 *start = false; |
| 581 *oppStart = true; |
| 582 } else if (opp->fPart[TCurve::kPointLast] == fPart[0]) { |
| 583 *start = true; |
| 584 *oppStart = false; |
| 585 } else if (opp->fPart[TCurve::kPointLast] == fPart[TCurve::kPointLast]) { |
| 586 *start = *oppStart = false; |
| 587 } else { |
| 588 *ptsInCommon = false; |
| 589 return false; |
| 590 } |
| 591 *ptsInCommon = true; |
| 592 const SkDPoint* o1Pts[TCurve::kPointCount - 1], * o2Pts[TCurve::kPointCount
- 1]; |
| 593 int baseIndex = *start ? 0 : TCurve::kPointLast; |
| 594 fPart.otherPts(baseIndex, o1Pts); |
| 595 opp->fPart.otherPts(*oppStart ? 0 : TCurve::kPointLast, o2Pts); |
| 596 const SkDPoint& base = fPart[baseIndex]; |
| 597 for (int o1 = 0; o1 < (int) SK_ARRAY_COUNT(o1Pts); ++o1) { |
| 598 SkDVector v1 = *o1Pts[o1] - base; |
| 599 for (int o2 = 0; o2 < (int) SK_ARRAY_COUNT(o2Pts); ++o2) { |
| 600 SkDVector v2 = *o2Pts[o2] - base; |
| 601 if (v2.dot(v1) >= 0) { |
| 602 return false; |
| 603 } |
| 604 } |
| 605 } |
| 606 return true; |
| 607 } |
| 608 |
| 609 template<typename TCurve> |
| 610 SkTSpan<TCurve>* SkTSpan<TCurve>::oppT(double t) const { |
| 611 int count = fBounded.count(); |
| 612 for (int index = 0; index < count; ++index) { |
| 613 SkTSpan* test = fBounded[index]; |
| 614 if (between(test->fStartT, t, test->fEndT)) { |
| 615 return test; |
| 616 } |
| 617 } |
| 618 return NULL; |
| 619 } |
| 620 |
| 621 template<typename TCurve> |
| 622 bool SkTSpan<TCurve>::removeAllBounded() { |
| 623 bool deleteSpan = false; |
| 624 int count = fBounded.count(); |
| 625 for (int index = 0; index < count; ++index) { |
| 626 SkTSpan* opp = fBounded[index]; |
| 627 deleteSpan |= opp->removeBounded(this); |
| 628 } |
| 629 return deleteSpan; |
| 630 } |
| 631 |
| 632 template<typename TCurve> |
| 633 bool SkTSpan<TCurve>::removeBounded(const SkTSpan* opp) { |
| 634 int count = fBounded.count(); |
| 635 if (fHasPerp) { |
| 636 bool foundStart = false; |
| 637 bool foundEnd = false; |
| 638 for (int index = 0; index < count; ++index) { |
| 639 const SkTSpan* test = fBounded[index]; |
| 640 if (opp == test) { |
| 641 continue; |
| 642 } |
| 643 foundStart |= between(test->fStartT, fCoinStart.perpT(), test->fEndT
); |
| 644 foundEnd |= between(test->fStartT, fCoinEnd.perpT(), test->fEndT); |
| 645 } |
| 646 if (!foundStart || !foundEnd) { |
| 647 fHasPerp = false; |
| 648 fCoinStart.init(); |
| 649 fCoinEnd.init(); |
| 650 } |
| 651 } |
| 652 for (int index = 0; index < count; ++index) { |
| 653 if (opp == fBounded[index]) { |
| 654 fBounded.removeShuffle(index); |
| 655 SkASSERT((count == 1) == (fBounded.count() == 0)); |
| 656 return count == 1; |
| 657 } |
| 658 } |
| 659 SkASSERT(0); |
364 return false; | 660 return false; |
365 } | 661 } |
366 | 662 |
367 template<typename TCurve> | 663 template<typename TCurve> |
368 bool SkTSpan<TCurve>::splitAt(SkTSpan* work, double t) { | 664 bool SkTSpan<TCurve>::splitAt(SkTSpan* work, double t) { |
369 fStartT = t; | 665 fStartT = t; |
370 fEndT = work->fEndT; | 666 fEndT = work->fEndT; |
371 if (fStartT == fEndT) { | 667 if (fStartT == fEndT) { |
372 fCollapsed = true; | 668 fCollapsed = true; |
373 return false; | 669 return false; |
374 } | 670 } |
375 work->fEndT = t; | 671 work->fEndT = t; |
376 if (work->fStartT == work->fEndT) { | 672 if (work->fStartT == work->fEndT) { |
377 work->fCollapsed = true; | 673 work->fCollapsed = true; |
378 return false; | 674 return false; |
379 } | 675 } |
380 fPrev = work; | 676 fPrev = work; |
381 fNext = work->fNext; | 677 fNext = work->fNext; |
382 fIsLinear = work->fIsLinear; | 678 fIsLinear = work->fIsLinear; |
| 679 fIsLine = work->fIsLine; |
| 680 |
383 work->fNext = this; | 681 work->fNext = this; |
384 if (fNext) { | 682 if (fNext) { |
385 fNext->fPrev = this; | 683 fNext->fPrev = this; |
386 } | 684 } |
387 fBounded = work->fBounded; | 685 fBounded = work->fBounded; |
388 int count = fBounded.count(); | 686 int count = fBounded.count(); |
389 for (int index = 0; index < count; ++index) { | 687 for (int index = 0; index < count; ++index) { |
390 fBounded[index]->fBounded.push_back() = this; | 688 fBounded[index]->fBounded.push_back() = this; |
391 } | 689 } |
392 return true; | 690 return true; |
393 } | 691 } |
394 | 692 |
395 template<typename TCurve> | 693 template<typename TCurve> |
396 bool SkTSpan<TCurve>::tightBoundsIntersects(const SkTSpan* span) const { | 694 void SkTSpan<TCurve>::validate() const { |
397 // skew all to an axis | |
398 SkDVector v2_0 = fPart[TCurve::kPointLast] - fPart[0]; | |
399 bool skewToXAxis = fabs(v2_0.fX) > fabs(v2_0.fY); | |
400 double ratio = skewToXAxis ? v2_0.fY / v2_0.fX : v2_0.fX / v2_0.fY; | |
401 TCurve r1 = fPart; | |
402 if (skewToXAxis) { | |
403 r1[1].fY -= (fPart[1].fX - r1[0].fX) * ratio; | |
404 if (TCurve::IsCubic()) { | |
405 r1[2].fY -= (fPart[2].fX - r1[0].fX) * ratio; | |
406 r1[3].fY = r1[0].fY; | |
407 } else { | |
408 r1[2].fY = r1[0].fY; | |
409 } | |
410 } else { | |
411 r1[1].fX -= (fPart[1].fY - r1[0].fY) * ratio; | |
412 if (TCurve::IsCubic()) { | |
413 r1[2].fX -= (fPart[2].fY - r1[0].fY) * ratio; | |
414 r1[3].fX = r1[0].fX; | |
415 } else { | |
416 r1[2].fX = r1[0].fX; | |
417 } | |
418 } | |
419 // compute the tight skewed bounds | |
420 SkDRect bounds; | |
421 bounds.setBounds(r1); | |
422 // see if opposite ends are within range of tight skewed bounds | |
423 TCurve r2 = span->fPart; | |
424 for (int i = 0; i < TCurve::kPointCount; i += 2) { | |
425 if (skewToXAxis) { | |
426 r2[i].fY -= (r2[i].fX - r1[0].fX) * ratio; | |
427 if (between(bounds.fTop, r2[i].fY, bounds.fBottom)) { | |
428 return true; | |
429 } | |
430 } else { | |
431 r2[i].fX -= (r2[i].fY - r1[0].fY) * ratio; | |
432 if (between(bounds.fLeft, r2[i].fX, bounds.fRight)) { | |
433 return true; | |
434 } | |
435 } | |
436 } | |
437 // see if opposite ends are on either side of tight skewed bounds | |
438 if ((skewToXAxis ? (r2[0].fY - r1[0].fY) * (r2[TCurve::kPointLast].fY - r1[0
].fY) | |
439 : (r2[0].fX - r1[0].fX) * (r2[TCurve::kPointLast].fX - r
1[0].fX)) < 0) { | |
440 return true; | |
441 } | |
442 // compute opposite tight skewed bounds | |
443 if (skewToXAxis) { | |
444 r2[1].fY -= (r2[1].fX - r1[0].fX) * ratio; | |
445 if (TCurve::IsCubic()) { | |
446 r2[2].fY -= (r2[2].fX - r1[0].fX) * ratio; | |
447 } | |
448 } else { | |
449 r2[1].fX -= (r2[1].fY - r1[0].fY) * ratio; | |
450 if (TCurve::IsCubic()) { | |
451 r2[2].fX -= (r2[2].fY - r1[0].fY) * ratio; | |
452 } | |
453 } | |
454 SkDRect sBounds; | |
455 sBounds.setBounds(r2); | |
456 // see if tight bounds overlap | |
457 if (skewToXAxis) { | |
458 return bounds.fTop <= sBounds.fBottom && sBounds.fTop <= bounds.fBottom;
| |
459 } else { | |
460 return bounds.fLeft <= sBounds.fRight && sBounds.fLeft <= bounds.fRight;
| |
461 } | |
462 } | |
463 | |
464 #if DEBUG_T_SECT | 695 #if DEBUG_T_SECT |
465 template<typename TCurve> | |
466 void SkTSpan<TCurve>::validate() const { | |
467 SkASSERT(fNext == NULL || fNext != fPrev); | 696 SkASSERT(fNext == NULL || fNext != fPrev); |
468 SkASSERT(fNext == NULL || this == fNext->fPrev); | 697 SkASSERT(fNext == NULL || this == fNext->fPrev); |
469 SkASSERT(fBounds.width() || fBounds.height()); | 698 SkASSERT(fPrev == NULL || this == fPrev->fNext); |
| 699 SkASSERT(fBounds.width() || fBounds.height() || fCollapsed); |
470 SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height())); | 700 SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height())); |
471 SkASSERT(0 <= fStartT); | 701 SkASSERT(0 <= fStartT); |
472 SkASSERT(fEndT <= 1); | 702 SkASSERT(fEndT <= 1); |
473 SkASSERT(fStartT < fEndT); | 703 SkASSERT(fStartT <= fEndT); |
474 SkASSERT(fBounded.count() > 0); | 704 SkASSERT(fBounded.count() > 0); |
| 705 this->validateBounded(); |
| 706 if (fHasPerp) { |
| 707 if (fCoinStart.isCoincident()) { |
| 708 validatePerpT(fCoinStart.perpT()); |
| 709 validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt()); |
| 710 } |
| 711 if (fCoinEnd.isCoincident()) { |
| 712 validatePerpT(fCoinEnd.perpT()); |
| 713 validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt()); |
| 714 } |
| 715 } |
| 716 #endif |
| 717 } |
| 718 |
| 719 template<typename TCurve> |
| 720 void SkTSpan<TCurve>::validateBounded() const { |
| 721 #if DEBUG_VALIDATE |
475 for (int index = 0; index < fBounded.count(); ++index) { | 722 for (int index = 0; index < fBounded.count(); ++index) { |
476 const SkTSpan* overlap = fBounded[index]; | 723 const SkTSpan* overlap = fBounded[index]; |
477 SkASSERT(((fDebugID ^ overlap->fDebugID) & 1) == 1); | 724 SkASSERT(!overlap->fDeleted); |
478 SkASSERT(overlap->contains(this)); | 725 SkASSERT(((this->debugID() ^ overlap->debugID()) & 1) == 1); |
| 726 SkASSERT(overlap->findOppSpan(this)); |
479 } | 727 } |
| 728 #endif |
480 } | 729 } |
481 #endif | |
482 | 730 |
483 template<typename TCurve> | 731 template<typename TCurve> |
484 SkTSect<TCurve>::SkTSect(const TCurve& c PATH_OPS_DEBUG_PARAMS(int id)) | 732 void SkTSpan<TCurve>::validatePerpT(double oppT) const { |
| 733 #if DEBUG_VALIDATE |
| 734 for (int index = 0; index < fBounded.count(); ++index) { |
| 735 const SkTSpan* overlap = fBounded[index]; |
| 736 if (between(overlap->fStartT, oppT, overlap->fEndT)) { |
| 737 return; |
| 738 } |
| 739 } |
| 740 SkASSERT(0); |
| 741 #endif |
| 742 } |
| 743 |
| 744 template<typename TCurve> |
| 745 void SkTSpan<TCurve>::validatePerpPt(double t, const SkDPoint& pt) const { |
| 746 #if DEBUG_T_SECT |
| 747 PATH_OPS_DEBUG_CODE(SkASSERT(fDebugSect->fOppSect->fCurve.ptAtT(t) == pt)); |
| 748 #endif |
| 749 } |
| 750 |
| 751 |
| 752 template<typename TCurve> |
| 753 SkTSect<TCurve>::SkTSect(const TCurve& c PATH_OPS_DEBUG_T_SECT_PARAMS(int id)) |
485 : fCurve(c) | 754 : fCurve(c) |
486 , fHeap(sizeof(SkTSpan<TCurve>) * 4) | 755 , fHeap(sizeof(SkTSpan<TCurve>) * 4) |
| 756 , fCoincident(NULL) |
487 , fDeleted(NULL) | 757 , fDeleted(NULL) |
488 , fActiveCount(0) | 758 , fActiveCount(0) |
489 PATH_OPS_DEBUG_PARAMS(fDebugID(id)) | 759 PATH_OPS_DEBUG_T_SECT_PARAMS(fID(id)) |
490 PATH_OPS_DEBUG_PARAMS(fDebugCount(0)) | 760 PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0)) |
491 PATH_OPS_DEBUG_PARAMS(fDebugAllocatedCount(0)) | 761 PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0)) |
492 { | 762 { |
493 fHead = addOne(); | 763 fHead = addOne(); |
494 fHead->init(c); | 764 fHead->init(c); |
495 } | 765 } |
496 | 766 |
497 template<typename TCurve> | 767 template<typename TCurve> |
498 SkTSpan<TCurve>* SkTSect<TCurve>::addOne() { | 768 SkTSpan<TCurve>* SkTSect<TCurve>::addOne() { |
499 SkTSpan<TCurve>* result; | 769 SkTSpan<TCurve>* result; |
500 if (fDeleted) { | 770 if (fDeleted) { |
501 result = fDeleted; | 771 result = fDeleted; |
502 result->reset(); | 772 result->reset(); |
503 fDeleted = result->fNext; | 773 fDeleted = result->fNext; |
504 } else { | 774 } else { |
505 result = SkNEW_PLACEMENT(fHeap.allocThrow(sizeof(SkTSpan<TCurve>)), SkTS
pan<TCurve>); | 775 result = SkNEW_PLACEMENT(fHeap.allocThrow(sizeof(SkTSpan<TCurve>)), SkTS
pan<TCurve>); |
506 #if DEBUG_T_SECT | 776 #if DEBUG_T_SECT |
507 ++fDebugAllocatedCount; | 777 ++fDebugAllocatedCount; |
508 #endif | 778 #endif |
509 } | 779 } |
510 ++fActiveCount; | 780 ++fActiveCount; |
511 #if DEBUG_T_SECT | 781 PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID); |
512 result->fDebugID = fDebugCount++ * 2 + fDebugID; | 782 PATH_OPS_DEBUG_CODE(result->fDebugSect = this); |
513 #endif | |
514 return result; | 783 return result; |
515 } | 784 } |
516 | 785 |
517 template<typename TCurve> | 786 template<typename TCurve> |
518 bool SkTSect<TCurve>::binarySearchCoin(const SkTSect& sect2, double tStart, doub
le tStep, | 787 bool SkTSect<TCurve>::binarySearchCoin(SkTSect* sect2, double tStart, double tSt
ep, |
519 double* resultT, double* oppT) { | 788 double* resultT, double* oppT) { |
520 SkTSpan<TCurve> work; | 789 SkTSpan<TCurve> work; |
521 double result = work.fStartT = work.fEndT = tStart; | 790 double result = work.fStartT = work.fEndT = tStart; |
| 791 PATH_OPS_DEBUG_CODE(work.fDebugSect = this); |
522 SkDPoint last = fCurve.ptAtT(tStart); | 792 SkDPoint last = fCurve.ptAtT(tStart); |
523 SkDPoint oppPt; | 793 SkDPoint oppPt; |
524 bool flip = false; | 794 bool flip = false; |
525 SkDEBUGCODE(bool down = tStep < 0); | 795 SkDEBUGCODE(bool down = tStep < 0); |
526 const TCurve& opp = sect2.fCurve; | 796 const TCurve& opp = sect2->fCurve; |
527 do { | 797 do { |
528 tStep *= 0.5; | 798 tStep *= 0.5; |
529 work.fStartT += tStep; | 799 work.fStartT += tStep; |
530 if (flip) { | 800 if (flip) { |
531 tStep = -tStep; | 801 tStep = -tStep; |
532 flip = false; | 802 flip = false; |
533 } | 803 } |
534 work.initBounds(fCurve); | 804 work.initBounds(fCurve); |
535 if (work.fCollapsed) { | 805 if (work.fCollapsed) { |
536 return false; | 806 return false; |
537 } | 807 } |
538 if (last.approximatelyEqual(work.fPart[0])) { | 808 if (last.approximatelyEqual(work.fPart[0])) { |
539 break; | 809 break; |
540 } | 810 } |
541 last = work.fPart[0]; | 811 last = work.fPart[0]; |
542 work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp); | 812 work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp); |
543 if (work.fCoinStart.isCoincident()) { | 813 if (work.fCoinStart.isCoincident()) { |
| 814 #if DEBUG_T_SECT |
| 815 work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt(
)); |
| 816 #endif |
544 double oppTTest = work.fCoinStart.perpT(); | 817 double oppTTest = work.fCoinStart.perpT(); |
545 if (sect2.fHead->contains(oppTTest)) { | 818 if (sect2->fHead->contains(oppTTest)) { |
546 *oppT = oppTTest; | 819 *oppT = oppTTest; |
547 oppPt = work.fCoinStart.perpPt(); | 820 oppPt = work.fCoinStart.perpPt(); |
548 SkASSERT(down ? result > work.fStartT : result < work.fStartT); | 821 SkASSERT(down ? result > work.fStartT : result < work.fStartT); |
549 result = work.fStartT; | 822 result = work.fStartT; |
550 continue; | 823 continue; |
551 } | 824 } |
552 } | 825 } |
553 tStep = -tStep; | 826 tStep = -tStep; |
554 flip = true; | 827 flip = true; |
555 } while (true); | 828 } while (true); |
(...skipping 11 matching lines...) Expand all Loading... |
567 return true; | 840 return true; |
568 } | 841 } |
569 | 842 |
570 // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in
quad span | 843 // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in
quad span |
571 // so that each quad sect has a pointer to the largest, and can updat
e it as spans | 844 // so that each quad sect has a pointer to the largest, and can updat
e it as spans |
572 // are split | 845 // are split |
573 template<typename TCurve> | 846 template<typename TCurve> |
574 SkTSpan<TCurve>* SkTSect<TCurve>::boundsMax() const { | 847 SkTSpan<TCurve>* SkTSect<TCurve>::boundsMax() const { |
575 SkTSpan<TCurve>* test = fHead; | 848 SkTSpan<TCurve>* test = fHead; |
576 SkTSpan<TCurve>* largest = fHead; | 849 SkTSpan<TCurve>* largest = fHead; |
577 bool largestCoin = largest->fCoinStart.isCoincident() && largest->fCoinEnd.i
sCoincident(); | 850 bool lCollapsed = largest->fCollapsed; |
578 while ((test = test->fNext)) { | 851 while ((test = test->fNext)) { |
579 bool testCoin = test->fCoinStart.isCoincident() || test->fCoinEnd.isCoin
cident(); | 852 bool tCollapsed = test->fCollapsed; |
580 if ((largestCoin && !testCoin) || (largestCoin == testCoin | 853 if ((lCollapsed && !tCollapsed) || (lCollapsed == tCollapsed && |
581 && (largest->fBoundsMax < test->fBoundsMax | 854 largest->fBoundsMax < test->fBoundsMax)) { |
582 || (largest->fCollapsed && !test->fCollapsed)))) { | |
583 largest = test; | 855 largest = test; |
584 largestCoin = testCoin; | 856 } |
585 } | 857 } |
586 } | 858 return largest; |
587 return largestCoin ? NULL : largest; | |
588 } | 859 } |
589 | 860 |
590 template<typename TCurve> | 861 template<typename TCurve> |
591 void SkTSect<TCurve>::coincidentCheck(SkTSect* sect2) { | 862 void SkTSect<TCurve>::coincidentCheck(SkTSect* sect2) { |
592 SkTSpan<TCurve>* first = fHead; | 863 SkTSpan<TCurve>* first = fHead; |
593 SkTSpan<TCurve>* next; | 864 SkTSpan<TCurve>* last, * next; |
594 do { | 865 do { |
595 int consecutive = 1; | 866 int consecutive = this->countConsecutiveSpans(first, &last); |
596 SkTSpan<TCurve>* last = first; | 867 next = last->fNext; |
597 do { | |
598 next = last->fNext; | |
599 if (!next) { | |
600 break; | |
601 } | |
602 if (next->fStartT > last->fEndT) { | |
603 break; | |
604 } | |
605 ++consecutive; | |
606 last = next; | |
607 } while (true); | |
608 if (consecutive < COINCIDENT_SPAN_COUNT) { | 868 if (consecutive < COINCIDENT_SPAN_COUNT) { |
609 continue; | 869 continue; |
610 } | 870 } |
611 setPerp(sect2->fCurve, first, last); | 871 this->validate(); |
| 872 sect2->validate(); |
| 873 this->computePerpendiculars(sect2, first, last); |
| 874 this->validate(); |
| 875 sect2->validate(); |
612 // check to see if a range of points are on the curve | 876 // check to see if a range of points are on the curve |
613 onCurveCheck(sect2, first, last); | 877 SkTSpan<TCurve>* coinStart = first; |
614 SkTSpan<TCurve>* removalCandidate = NULL; | 878 do { |
615 if (!first->fCoinStart.isCoincident()) { | 879 coinStart = this->extractCoincident(sect2, coinStart, last); |
616 SkTSpan<TCurve>* firstCoin = first->fNext; | 880 } while (coinStart && !last->fDeleted); |
617 removalCandidate = first; | |
618 first = firstCoin; | |
619 } | |
620 if (!first->fCoinStart.isCoincident()) { | |
621 continue; | |
622 } | |
623 if (removalCandidate) { | |
624 removeSpans(removalCandidate, sect2); | |
625 } | |
626 if (!last->fCoinStart.isCoincident()) { | |
627 continue; | |
628 } | |
629 if (!last->fCoinEnd.isCoincident()) { | |
630 if (--consecutive < COINCIDENT_SPAN_COUNT) { | |
631 continue; | |
632 } | |
633 last = last->fPrev; | |
634 SkASSERT(last->fCoinStart.isCoincident()); | |
635 SkASSERT(last->fCoinEnd.isCoincident()); | |
636 } | |
637 SkASSERT(between(0, first->fCoinStart.perpT(), 1) || first->fCoinStart.p
erpT() == -1); | |
638 if (first->fCoinStart.perpT() < 0) { | |
639 first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], s
ect2->fCurve); | |
640 } | |
641 SkASSERT(between(0, last->fCoinEnd.perpT(), 1) || last->fCoinEnd.perpT()
== -1); | |
642 if (last->fCoinEnd.perpT() < 0) { | |
643 last->fCoinEnd.setPerp(fCurve, last->fEndT, last->fPart[TCurve::kPoi
ntLast], | |
644 sect2->fCurve); | |
645 } | |
646 SkTSpan<TCurve>* removeMe = first->fNext; | |
647 while (removeMe != last) { | |
648 SkTSpan<TCurve>* removeNext = removeMe->fNext; | |
649 removeSpans(removeMe, sect2); | |
650 removeMe = removeNext; | |
651 } | |
652 } while ((first = next)); | 881 } while ((first = next)); |
653 } | 882 } |
654 | 883 |
655 template<typename TCurve> | 884 template<typename TCurve> |
656 bool SkTSect<TCurve>::intersects(SkTSpan<TCurve>* span, const SkTSect* opp, | 885 bool SkTSect<TCurve>::coincidentHasT(double t) { |
657 const SkTSpan<TCurve>* oppSpan) const { | 886 SkTSpan<TCurve>* test = fCoincident; |
658 bool check; // we ignore whether the end points are in common or not | 887 while (test) { |
659 if (!span->intersects(oppSpan, &check)) { | 888 if (between(test->fStartT, t, test->fEndT)) { |
660 return false; | 889 return true; |
661 } | 890 } |
662 if (fActiveCount < COINCIDENT_SPAN_COUNT || opp->fActiveCount < COINCIDENT_S
PAN_COUNT) { | 891 test = test->fNext; |
663 return true; | 892 } |
664 } | 893 return false; |
665 return span->tightBoundsIntersects(oppSpan); | 894 } |
666 } | 895 |
667 | 896 template<typename TCurve> |
668 template<typename TCurve> | 897 void SkTSect<TCurve>::computePerpendiculars(SkTSect* sect2, SkTSpan<TCurve>* fir
st, |
669 void SkTSect<TCurve>::onCurveCheck(SkTSect* sect2, SkTSpan<TCurve>* first, SkTSp
an<TCurve>* last) { | 898 SkTSpan<TCurve>* last) { |
670 SkTSpan<TCurve>* work = first; | 899 const TCurve& opp = sect2->fCurve; |
671 first = NULL; | 900 SkTSpan<TCurve>* work = first; |
672 do { | 901 SkTSpan<TCurve>* prior = NULL; |
673 if (work->fCoinStart.isCoincident()) { | 902 do { |
674 if (!first) { | 903 if (!work->fHasPerp && !work->fCollapsed) { |
675 first = work; | 904 if (prior) { |
676 } | 905 work->fCoinStart = prior->fCoinEnd; |
677 } else if (first) { | 906 } else { |
678 break; | 907 work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0],
opp); |
| 908 } |
| 909 if (work->fCoinStart.isCoincident()) { |
| 910 double perpT = work->fCoinStart.perpT(); |
| 911 if (sect2->coincidentHasT(perpT)) { |
| 912 work->fCoinStart.clear(); |
| 913 } else { |
| 914 sect2->addForPerp(work, perpT); |
| 915 } |
| 916 } |
| 917 work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPoi
ntLast], opp); |
| 918 if (work->fCoinEnd.isCoincident()) { |
| 919 double perpT = work->fCoinEnd.perpT(); |
| 920 if (sect2->coincidentHasT(perpT)) { |
| 921 work->fCoinEnd.clear(); |
| 922 } else { |
| 923 sect2->addForPerp(work, perpT); |
| 924 } |
| 925 } |
| 926 work->fHasPerp = true; |
679 } | 927 } |
680 if (work == last) { | 928 if (work == last) { |
681 break; | 929 break; |
682 } | 930 } |
| 931 prior = work; |
683 work = work->fNext; | 932 work = work->fNext; |
684 SkASSERT(work); | 933 SkASSERT(work); |
685 } while (true); | 934 } while (true); |
| 935 } |
| 936 |
| 937 template<typename TCurve> |
| 938 int SkTSect<TCurve>::countConsecutiveSpans(SkTSpan<TCurve>* first, |
| 939 SkTSpan<TCurve>** lastPtr) const { |
| 940 int consecutive = 1; |
| 941 SkTSpan<TCurve>* last = first; |
| 942 do { |
| 943 SkTSpan<TCurve>* next = last->fNext; |
| 944 if (!next) { |
| 945 break; |
| 946 } |
| 947 if (next->fStartT > last->fEndT) { |
| 948 break; |
| 949 } |
| 950 ++consecutive; |
| 951 last = next; |
| 952 } while (true); |
| 953 *lastPtr = last; |
| 954 return consecutive; |
| 955 } |
| 956 |
| 957 template<typename TCurve> |
| 958 bool SkTSect<TCurve>::debugHasBounded(const SkTSpan<TCurve>* span) const { |
| 959 const SkTSpan<TCurve>* test = fHead; |
| 960 if (!test) { |
| 961 return false; |
| 962 } |
| 963 do { |
| 964 if (test->findOppSpan(span)) { |
| 965 return true; |
| 966 } |
| 967 } while ((test = test->next())); |
| 968 return false; |
| 969 } |
| 970 |
| 971 template<typename TCurve> |
| 972 void SkTSect<TCurve>::deleteEmptySpans() { |
| 973 SkTSpan<TCurve>* test; |
| 974 SkTSpan<TCurve>* next = fHead; |
| 975 while ((test = next)) { |
| 976 next = test->fNext; |
| 977 if (test->fBounded.count() == 0) { |
| 978 this->removeSpan(test); |
| 979 } |
| 980 } |
| 981 } |
| 982 |
| 983 template<typename TCurve> |
| 984 SkTSpan<TCurve>* SkTSect<TCurve>::extractCoincident(SkTSect* sect2, SkTSpan<TCur
ve>* first, |
| 985 SkTSpan<TCurve>* last) { |
| 986 first = findCoincidentRun(first, &last, sect2); |
686 if (!first) { | 987 if (!first) { |
687 return; | 988 return NULL; |
688 } | 989 } |
689 // march outwards to find limit of coincidence from here to previous and nex
t spans | 990 // march outwards to find limit of coincidence from here to previous and nex
t spans |
690 double startT = first->fStartT; | 991 double startT = first->fStartT; |
691 double oppT; | 992 double oppStartT; |
| 993 double oppEndT SK_INIT_TO_AVOID_WARNING; |
692 SkTSpan<TCurve>* prev = first->fPrev; | 994 SkTSpan<TCurve>* prev = first->fPrev; |
693 if (prev) { | 995 SkASSERT(first->fCoinStart.isCoincident()); |
694 double coinStart; | 996 SkTSpan<TCurve>* oppFirst = first->findOppT(first->fCoinStart.perpT()); |
695 if (binarySearchCoin(*sect2, startT, prev->fStartT - startT, &coinStart,
&oppT)) { | 997 SkASSERT(last->fCoinEnd.isCoincident()); |
696 if (coinStart < startT) { | 998 bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT(); |
697 SkASSERT(prev->fStartT < coinStart && coinStart < prev->fEndT); | 999 double coinStart; |
698 SkTSpan<TCurve>* oppStart = sect2->fHead->find(oppT); | 1000 SkDEBUGCODE(double coinEnd); |
699 if (oppStart->fStartT < oppT && oppT < oppStart->fEndT) { | 1001 if (prev && prev->fEndT == startT |
700 // split prev at coinStart if needed | 1002 && this->binarySearchCoin(sect2, startT, prev->fStartT - startT, &co
inStart, |
701 SkTSpan<TCurve>* half2 = addOne(); | 1003 &oppStartT) |
702 half2->splitAt(prev, coinStart); | 1004 && prev->fStartT < coinStart && coinStart < startT) { |
703 half2->initBounds(fCurve); | 1005 oppFirst = prev->findOppT(oppStartT); // find opp start before splittin
g prev |
704 prev->initBounds(fCurve); | 1006 SkASSERT(oppFirst); |
705 prev->fCoinEnd.markCoincident(); | 1007 first = this->addSplitAt(prev, coinStart); |
706 half2->fCoinStart.markCoincident(); | 1008 first->markCoincident(); |
707 half2->fCoinEnd.markCoincident(); | 1009 prev->fCoinEnd.markCoincident(); |
708 // find span containing opposite t, and split that too | 1010 if (oppFirst->fStartT < oppStartT && oppStartT < oppFirst->fEndT) { |
709 SkTSpan<TCurve>* oppHalf = sect2->addOne(); | 1011 SkTSpan<TCurve>* oppHalf = sect2->addSplitAt(oppFirst, oppStartT); |
710 oppHalf->splitAt(oppStart, oppT); | 1012 if (oppMatched) { |
711 oppHalf->initBounds(sect2->fCurve); | 1013 oppFirst->fCoinEnd.markCoincident(); |
712 oppStart->initBounds(sect2->fCurve); | 1014 oppHalf->markCoincident(); |
| 1015 oppFirst = oppHalf; |
| 1016 } else { |
| 1017 oppFirst->markCoincident(); |
| 1018 oppHalf->fCoinStart.markCoincident(); |
| 1019 } |
| 1020 } |
| 1021 } else { |
| 1022 SkDEBUGCODE(coinStart = first->fStartT); |
| 1023 SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT
); |
| 1024 } |
| 1025 SkTSpan<TCurve>* oppLast; |
| 1026 SkASSERT(last->fCoinEnd.isCoincident()); |
| 1027 oppLast = last->findOppT(last->fCoinEnd.perpT()); |
| 1028 SkDEBUGCODE(coinEnd = last->fEndT); |
| 1029 SkDEBUGCODE(oppEndT = oppMatched ? oppLast->fEndT : oppLast->fStartT); |
| 1030 if (!oppMatched) { |
| 1031 SkTSwap(oppFirst, oppLast); |
| 1032 SkTSwap(oppStartT, oppEndT); |
| 1033 } |
| 1034 SkASSERT(oppStartT < oppEndT); |
| 1035 SkASSERT(coinStart == first->fStartT); |
| 1036 SkASSERT(coinEnd == last->fEndT); |
| 1037 SkASSERT(oppStartT == oppFirst->fStartT); |
| 1038 SkASSERT(oppEndT == oppLast->fEndT); |
| 1039 // reduce coincident runs to single entries |
| 1040 this->validate(); |
| 1041 sect2->validate(); |
| 1042 bool deleteThisSpan = this->updateBounded(first, last, oppFirst); |
| 1043 bool deleteSect2Span = sect2->updateBounded(oppFirst, oppLast, first); |
| 1044 this->removeSpanRange(first, last); |
| 1045 sect2->removeSpanRange(oppFirst, oppLast); |
| 1046 first->fEndT = last->fEndT; |
| 1047 first->resetBounds(this->fCurve); |
| 1048 first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], sect2->fC
urve); |
| 1049 first->fCoinEnd.setPerp(fCurve, first->fEndT, first->fPart[TCurve::kPointLas
t], sect2->fCurve); |
| 1050 oppStartT = first->fCoinStart.perpT(); |
| 1051 oppEndT = first->fCoinEnd.perpT(); |
| 1052 if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) { |
| 1053 if (!oppMatched) { |
| 1054 SkTSwap(oppStartT, oppEndT); |
| 1055 } |
| 1056 oppFirst->fStartT = oppStartT; |
| 1057 oppFirst->fEndT = oppEndT; |
| 1058 oppFirst->resetBounds(sect2->fCurve); |
| 1059 } |
| 1060 this->validateBounded(); |
| 1061 sect2->validateBounded(); |
| 1062 last = first->fNext; |
| 1063 this->removeCoincident(first, false); |
| 1064 sect2->removeCoincident(oppFirst, true); |
| 1065 if (deleteThisSpan) { |
| 1066 this->deleteEmptySpans(); |
| 1067 } |
| 1068 if (deleteSect2Span) { |
| 1069 sect2->deleteEmptySpans(); |
| 1070 } |
| 1071 this->validate(); |
| 1072 sect2->validate(); |
| 1073 return last && !last->fDeleted ? last : NULL; |
| 1074 } |
| 1075 |
| 1076 template<typename TCurve> |
| 1077 SkTSpan<TCurve>* SkTSect<TCurve>::findCoincidentRun(SkTSpan<TCurve>* first, |
| 1078 SkTSpan<TCurve>** lastPtr, const SkTSect* sect2) { |
| 1079 SkTSpan<TCurve>* work = first; |
| 1080 SkTSpan<TCurve>* lastCandidate = NULL; |
| 1081 first = NULL; |
| 1082 // find the first fully coincident span |
| 1083 do { |
| 1084 if (work->fCoinStart.isCoincident()) { |
| 1085 work->validatePerpT(work->fCoinStart.perpT()); |
| 1086 work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perp
Pt()); |
| 1087 SkASSERT(work->hasOppT(work->fCoinStart.perpT())); |
| 1088 if (!work->fCoinEnd.isCoincident()) { |
| 1089 break; |
| 1090 } |
| 1091 lastCandidate = work; |
| 1092 if (!first) { |
| 1093 first = work; |
| 1094 } |
| 1095 } else { |
| 1096 lastCandidate = NULL; |
| 1097 SkASSERT(!first); |
| 1098 } |
| 1099 if (work == *lastPtr) { |
| 1100 return first; |
| 1101 } |
| 1102 work = work->fNext; |
| 1103 SkASSERT(work); |
| 1104 } while (true); |
| 1105 if (lastCandidate) { |
| 1106 *lastPtr = lastCandidate; |
| 1107 } |
| 1108 return first; |
| 1109 } |
| 1110 |
| 1111 template<typename TCurve> |
| 1112 int SkTSect<TCurve>::intersects(SkTSpan<TCurve>* span, const SkTSect* opp, |
| 1113 SkTSpan<TCurve>* oppSpan, int* oppResult) const { |
| 1114 bool spanStart, oppStart; |
| 1115 int hullResult = span->hullsIntersect(oppSpan, &spanStart, &oppStart); |
| 1116 if (hullResult >= 0) { |
| 1117 if (hullResult == 2) { // hulls have one point in common |
| 1118 if (span->fBounded.count() <= 1) { |
| 1119 SkASSERT(span->fBounded.count() == 0 || span->fBounded[0] == opp
Span); |
| 1120 if (spanStart) { |
| 1121 span->fEndT = span->fStartT; |
713 } else { | 1122 } else { |
714 SkASSERT(oppStart->fStartT == oppT || oppT == oppStart->fEnd
T); | 1123 span->fStartT = span->fEndT; |
715 first->fStartT = coinStart; | 1124 } |
716 prev->fEndT = coinStart; | 1125 } else { |
717 first->initBounds(fCurve); | 1126 hullResult = 1; |
718 prev->initBounds(fCurve); | 1127 } |
719 first->fCoinStart.markCoincident(); | 1128 if (oppSpan->fBounded.count() <= 1) { |
720 first->fCoinEnd.markCoincident(); | 1129 SkASSERT(span->fBounded.count() == 0 || oppSpan->fBounded[0] ==
span); |
721 } | 1130 if (oppStart) { |
722 } | 1131 oppSpan->fEndT = oppSpan->fStartT; |
723 } | |
724 } | |
725 if (!work->fCoinEnd.isCoincident()) { | |
726 if (work->fEndT == 1) { | |
727 SkDebugf("!"); | |
728 } | |
729 // SkASSERT(work->fEndT < 1); | |
730 startT = work->fStartT; | |
731 double coinEnd; | |
732 if (binarySearchCoin(*sect2, startT, work->fEndT - startT, &coinEnd, &op
pT)) { | |
733 if (coinEnd > startT) { | |
734 SkTSpan<TCurve>* oppStart = sect2->fHead->find(oppT); | |
735 if (oppStart->fStartT < oppT && oppT < oppStart->fEndT) { | |
736 SkASSERT(coinEnd < work->fEndT); | |
737 // split prev at coinEnd if needed | |
738 SkTSpan<TCurve>* half2 = addOne(); | |
739 half2->splitAt(work, coinEnd); | |
740 half2->initBounds(fCurve); | |
741 work->initBounds(fCurve); | |
742 work->fCoinStart.markCoincident(); | |
743 work->fCoinEnd.markCoincident(); | |
744 half2->fCoinStart.markCoincident(); | |
745 SkTSpan<TCurve>* oppHalf = sect2->addOne(); | |
746 oppHalf->splitAt(oppStart, oppT); | |
747 oppHalf->initBounds(sect2->fCurve); | |
748 oppStart->initBounds(sect2->fCurve); | |
749 } else { | 1132 } else { |
750 SkASSERT(oppStart->fStartT == oppT || oppT == oppStart->fEnd
T); | 1133 oppSpan->fStartT = oppSpan->fEndT; |
751 SkTSpan<TCurve>* next = work->fNext; | 1134 } |
752 bool hasNext = next && work->fEndT == next->fStartT; | 1135 *oppResult = 2; |
753 work->fEndT = coinEnd; | 1136 } else { |
754 work->initBounds(fCurve); | 1137 *oppResult = 1; |
755 work->fCoinStart.markCoincident(); | 1138 } |
756 work->fCoinEnd.markCoincident(); | 1139 } else { |
757 if (hasNext) { | 1140 *oppResult = 1; |
758 next->fStartT = coinEnd; | 1141 } |
759 next->initBounds(fCurve); | 1142 return hullResult; |
760 } | 1143 } |
761 } | 1144 if (span->fIsLine && oppSpan->fIsLine) { |
762 } | 1145 SkIntersections i; |
763 } | 1146 int sects = this->linesIntersect(span, opp, oppSpan, &i); |
764 } | 1147 if (!sects) { |
765 } | 1148 return -1; |
766 | 1149 } |
767 template<typename TCurve> | 1150 span->fStartT = span->fEndT = i[0][0]; |
| 1151 oppSpan->fStartT = oppSpan->fEndT = i[1][0]; |
| 1152 return *oppResult = 2; |
| 1153 } |
| 1154 if (span->fIsLinear || oppSpan->fIsLinear) { |
| 1155 return *oppResult = (int) span->linearsIntersect(oppSpan); |
| 1156 } |
| 1157 return *oppResult = 1; |
| 1158 } |
| 1159 |
| 1160 // while the intersection points are sufficiently far apart: |
| 1161 // construct the tangent lines from the intersections |
| 1162 // find the point where the tangent line intersects the opposite curve |
| 1163 template<typename TCurve> |
| 1164 int SkTSect<TCurve>::linesIntersect(const SkTSpan<TCurve>* span, const SkTSect*
opp, |
| 1165 const SkTSpan<TCurve>* oppSpan, SkIntersections* i) const { |
| 1166 SkIntersections thisRayI, oppRayI; |
| 1167 SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; |
| 1168 SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[TCurve::kPointLast] }
}; |
| 1169 int loopCount = 0; |
| 1170 double bestDistSq = DBL_MAX; |
| 1171 do { |
| 1172 if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { |
| 1173 return 0; |
| 1174 } |
| 1175 if (!oppRayI.intersectRay(this->fCurve, oppLine)) { |
| 1176 return 0; |
| 1177 } |
| 1178 // pick the closest pair of points |
| 1179 double closest = DBL_MAX; |
| 1180 int closeIndex SK_INIT_TO_AVOID_WARNING; |
| 1181 int oppCloseIndex SK_INIT_TO_AVOID_WARNING; |
| 1182 for (int index = 0; index < oppRayI.used(); ++index) { |
| 1183 if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT))
{ |
| 1184 continue; |
| 1185 } |
| 1186 for (int oIndex = 0; oIndex < thisRayI.used(); ++oIndex) { |
| 1187 if (!roughly_between(oppSpan->fStartT, thisRayI[0][oIndex], oppS
pan->fEndT)) { |
| 1188 continue; |
| 1189 } |
| 1190 double distSq = thisRayI.pt(index).distanceSquared(oppRayI.pt(oI
ndex)); |
| 1191 if (closest > distSq) { |
| 1192 closest = distSq; |
| 1193 closeIndex = index; |
| 1194 oppCloseIndex = oIndex; |
| 1195 } |
| 1196 } |
| 1197 } |
| 1198 if (closest == DBL_MAX) { |
| 1199 return 0; |
| 1200 } |
| 1201 const SkDPoint& oppIPt = thisRayI.pt(oppCloseIndex); |
| 1202 const SkDPoint& iPt = oppRayI.pt(closeIndex); |
| 1203 if (between(span->fStartT, oppRayI[0][closeIndex], span->fEndT) |
| 1204 && between(oppSpan->fStartT, thisRayI[0][oppCloseIndex], oppSpan
->fEndT) |
| 1205 && oppIPt.approximatelyEqual(iPt)) { |
| 1206 i->merge(oppRayI, closeIndex, thisRayI, oppCloseIndex); |
| 1207 return i->used(); |
| 1208 } |
| 1209 double distSq = oppIPt.distanceSquared(iPt); |
| 1210 if (bestDistSq < distSq || ++loopCount > 5) { |
| 1211 break; |
| 1212 } |
| 1213 bestDistSq = distSq; |
| 1214 thisLine[0] = fCurve.ptAtT(oppRayI[0][closeIndex]); |
| 1215 thisLine[1] = thisLine[0] + fCurve.dxdyAtT(oppRayI[0][closeIndex]); |
| 1216 oppLine[0] = opp->fCurve.ptAtT(thisRayI[0][oppCloseIndex]); |
| 1217 oppLine[1] = oppLine[0] + opp->fCurve.dxdyAtT(thisRayI[0][oppCloseIndex]
); |
| 1218 } while (true); |
| 1219 return false; |
| 1220 } |
| 1221 |
| 1222 |
| 1223 template<typename TCurve> |
| 1224 void SkTSect<TCurve>::markSpanGone(SkTSpan<TCurve>* span) { |
| 1225 --fActiveCount; |
| 1226 span->fNext = fDeleted; |
| 1227 fDeleted = span; |
| 1228 SkASSERT(!span->fDeleted); |
| 1229 span->fDeleted = true; |
| 1230 } |
| 1231 |
| 1232 template<typename TCurve> |
| 1233 bool SkTSect<TCurve>::matchedDirection(double t, const SkTSect* sect2, double t2
) const { |
| 1234 SkDVector dxdy = this->fCurve.dxdyAtT(t); |
| 1235 SkDVector dxdy2 = sect2->fCurve.dxdyAtT(t2); |
| 1236 return dxdy.dot(dxdy2) >= 0; |
| 1237 } |
| 1238 |
| 1239 template<typename TCurve> |
| 1240 void SkTSect<TCurve>::matchedDirCheck(double t, const SkTSect* sect2, double t2, |
| 1241 bool* calcMatched, bool* oppMatched) const { |
| 1242 if (*calcMatched) { |
| 1243 SkASSERT(*oppMatched == this->matchedDirection(t, sect2, t2)); |
| 1244 } else { |
| 1245 *oppMatched = this->matchedDirection(t, sect2, t2); |
| 1246 *calcMatched = true; |
| 1247 } |
| 1248 } |
| 1249 |
| 1250 template<typename TCurve> |
| 1251 void SkTSect<TCurve>::mergeCoincidence(SkTSect* sect2) { |
| 1252 double smallLimit = 0; |
| 1253 do { |
| 1254 // find the smallest unprocessed span |
| 1255 SkTSpan<TCurve>* smaller = NULL; |
| 1256 SkTSpan<TCurve>* test = fCoincident; |
| 1257 do { |
| 1258 if (test->fStartT < smallLimit) { |
| 1259 continue; |
| 1260 } |
| 1261 if (smaller && smaller->fEndT < test->fStartT) { |
| 1262 continue; |
| 1263 } |
| 1264 smaller = test; |
| 1265 } while ((test = test->fNext)); |
| 1266 if (!smaller) { |
| 1267 return; |
| 1268 } |
| 1269 smallLimit = smaller->fEndT; |
| 1270 // find next larger span |
| 1271 SkTSpan<TCurve>* prior = NULL; |
| 1272 SkTSpan<TCurve>* larger = NULL; |
| 1273 SkTSpan<TCurve>* largerPrior = NULL; |
| 1274 test = fCoincident; |
| 1275 do { |
| 1276 if (test->fStartT < smaller->fEndT) { |
| 1277 continue; |
| 1278 } |
| 1279 SkASSERT(test->fStartT != smaller->fEndT); |
| 1280 if (larger && larger->fStartT < test->fStartT) { |
| 1281 continue; |
| 1282 } |
| 1283 largerPrior = prior; |
| 1284 larger = test; |
| 1285 } while ((prior = test), (test = test->fNext)); |
| 1286 if (!larger) { |
| 1287 continue; |
| 1288 } |
| 1289 // check middle t value to see if it is coincident as well |
| 1290 double midT = (smaller->fEndT + larger->fStartT) / 2; |
| 1291 SkDPoint midPt = fCurve.ptAtT(midT); |
| 1292 SkTCoincident<TCurve> coin; |
| 1293 coin.setPerp(fCurve, midT, midPt, sect2->fCurve); |
| 1294 if (coin.isCoincident()) { |
| 1295 smaller->fEndT = larger->fEndT; |
| 1296 smaller->fCoinEnd = larger->fCoinEnd; |
| 1297 if (largerPrior) { |
| 1298 largerPrior->fNext = larger->fNext; |
| 1299 } else { |
| 1300 fCoincident = larger->fNext; |
| 1301 } |
| 1302 } |
| 1303 } while (true); |
| 1304 } |
| 1305 |
| 1306 template<typename TCurve> |
| 1307 SkTSpan<TCurve>* SkTSect<TCurve>::prev(SkTSpan<TCurve>* span) const { |
| 1308 SkTSpan<TCurve>* result = NULL; |
| 1309 SkTSpan<TCurve>* test = fHead; |
| 1310 while (span != test) { |
| 1311 result = test; |
| 1312 test = test->fNext; |
| 1313 SkASSERT(test); |
| 1314 } |
| 1315 return result; |
| 1316 } |
| 1317 |
| 1318 template<typename TCurve> |
768 void SkTSect<TCurve>::recoverCollapsed() { | 1319 void SkTSect<TCurve>::recoverCollapsed() { |
769 SkTSpan<TCurve>* deleted = fDeleted; | 1320 SkTSpan<TCurve>* deleted = fDeleted; |
770 while (deleted) { | 1321 while (deleted) { |
771 SkTSpan<TCurve>* delNext = deleted->fNext; | 1322 SkTSpan<TCurve>* delNext = deleted->fNext; |
772 if (deleted->fCollapsed) { | 1323 if (deleted->fCollapsed) { |
773 SkTSpan<TCurve>** spanPtr = &fHead; | 1324 SkTSpan<TCurve>** spanPtr = &fHead; |
774 while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) { | 1325 while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) { |
775 spanPtr = &(*spanPtr)->fNext; | 1326 spanPtr = &(*spanPtr)->fNext; |
776 } | 1327 } |
777 deleted->fNext = *spanPtr; | 1328 deleted->fNext = *spanPtr; |
778 *spanPtr = deleted; | 1329 *spanPtr = deleted; |
779 } | 1330 } |
780 deleted = delNext; | 1331 deleted = delNext; |
781 } | 1332 } |
782 } | 1333 } |
783 | 1334 |
784 template<typename TCurve> | 1335 template<typename TCurve> |
| 1336 void SkTSect<TCurve>::removeAllBut(const SkTSpan<TCurve>* keep, SkTSpan<TCurve>*
span, |
| 1337 SkTSect* opp) { |
| 1338 int count = span->fBounded.count(); |
| 1339 for (int index = 0; index < count; ++index) { |
| 1340 SkTSpan<TCurve>* bounded = span->fBounded[0]; |
| 1341 if (bounded == keep) { |
| 1342 continue; |
| 1343 } |
| 1344 if (bounded->fDeleted) { // may have been deleted when opp did 'remove
all but' |
| 1345 continue; |
| 1346 } |
| 1347 SkAssertResult(SkDEBUGCODE(!) span->removeBounded(bounded)); |
| 1348 if (bounded->removeBounded(span)) { |
| 1349 opp->removeSpan(bounded); |
| 1350 } |
| 1351 } |
| 1352 SkASSERT(!span->fDeleted); |
| 1353 SkASSERT(span->findOppSpan(keep)); |
| 1354 SkASSERT(keep->findOppSpan(span)); |
| 1355 } |
| 1356 |
| 1357 template<typename TCurve> |
| 1358 void SkTSect<TCurve>::removeByPerpendicular(SkTSect<TCurve>* opp) { |
| 1359 SkTSpan<TCurve>* test = fHead; |
| 1360 SkTSpan<TCurve>* next; |
| 1361 do { |
| 1362 next = test->fNext; |
| 1363 if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) { |
| 1364 continue; |
| 1365 } |
| 1366 SkDVector startV = test->fCoinStart.perpPt() - test->fPart[0]; |
| 1367 SkDVector endV = test->fCoinEnd.perpPt() - test->fPart[TCurve::kPointLas
t]; |
| 1368 #if DEBUG_T_SECT |
| 1369 SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUN
CTION__, |
| 1370 startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV)); |
| 1371 #endif |
| 1372 if (startV.dot(endV) <= 0) { |
| 1373 continue; |
| 1374 } |
| 1375 this->removeSpans(test, opp); |
| 1376 } while ((test = next)); |
| 1377 } |
| 1378 |
| 1379 template<typename TCurve> |
| 1380 void SkTSect<TCurve>::removeCoincident(SkTSpan<TCurve>* span, bool isBetween) { |
| 1381 this->unlinkSpan(span); |
| 1382 if (isBetween || between(0, span->fCoinStart.perpT(), 1)) { |
| 1383 --fActiveCount; |
| 1384 span->fNext = fCoincident; |
| 1385 fCoincident = span; |
| 1386 } else { |
| 1387 this->markSpanGone(span); |
| 1388 } |
| 1389 } |
| 1390 |
| 1391 template<typename TCurve> |
785 void SkTSect<TCurve>::removeSpan(SkTSpan<TCurve>* span) { | 1392 void SkTSect<TCurve>::removeSpan(SkTSpan<TCurve>* span) { |
786 SkTSpan<TCurve>* prev = span->fPrev; | 1393 this->unlinkSpan(span); |
787 SkTSpan<TCurve>* next = span->fNext; | 1394 this->markSpanGone(span); |
788 if (prev) { | |
789 prev->fNext = next; | |
790 if (next) { | |
791 next->fPrev = prev; | |
792 } | |
793 } else { | |
794 fHead = next; | |
795 if (next) { | |
796 next->fPrev = NULL; | |
797 } | |
798 } | |
799 --fActiveCount; | |
800 span->fNext = fDeleted; | |
801 fDeleted = span; | |
802 #if DEBUG_T_SECT | |
803 SkASSERT(!span->fDebugDeleted); | |
804 span->fDebugDeleted = true; | |
805 #endif | |
806 } | 1395 } |
807 | 1396 |
808 template<typename TCurve> | 1397 template<typename TCurve> |
809 void SkTSect<TCurve>::removeOne(const SkTSpan<TCurve>* test, SkTSpan<TCurve>* sp
an) { | 1398 void SkTSect<TCurve>::removeSpanRange(SkTSpan<TCurve>* first, SkTSpan<TCurve>* l
ast) { |
810 int last = span->fBounded.count() - 1; | 1399 if (first == last) { |
811 for (int index = 0; index <= last; ++index) { | 1400 return; |
812 if (span->fBounded[index] == test) { | |
813 span->fBounded.removeShuffle(index); | |
814 if (!last) { | |
815 removeSpan(span); | |
816 } | |
817 return; | |
818 } | |
819 } | 1401 } |
| 1402 SkTSpan<TCurve>* span = first; |
| 1403 SkASSERT(span); |
| 1404 SkTSpan<TCurve>* final = last->fNext; |
| 1405 SkTSpan<TCurve>* next = span->fNext; |
| 1406 while ((span = next) && span != final) { |
| 1407 next = span->fNext; |
| 1408 this->markSpanGone(span); |
| 1409 } |
| 1410 if (final) { |
| 1411 final->fPrev = first; |
| 1412 } |
| 1413 first->fNext = final; |
820 } | 1414 } |
821 | 1415 |
822 template<typename TCurve> | 1416 template<typename TCurve> |
823 void SkTSect<TCurve>::removeSpans(SkTSpan<TCurve>* span, SkTSect<TCurve>* opp) { | 1417 void SkTSect<TCurve>::removeSpans(SkTSpan<TCurve>* span, SkTSect<TCurve>* opp) { |
824 int count = span->fBounded.count(); | 1418 int count = span->fBounded.count(); |
825 for (int index = 0; index < count; ++index) { | 1419 for (int index = 0; index < count; ++index) { |
826 SkTSpan<TCurve>* bounded = span->fBounded[0]; | 1420 SkTSpan<TCurve>* bounded = span->fBounded[0]; |
827 removeOne(bounded, span); // shuffles last into position 0 | 1421 if (span->removeBounded(bounded)) { // shuffles last into position 0 |
828 opp->removeOne(span, bounded); | 1422 this->removeSpan(span); |
| 1423 } |
| 1424 if (bounded->removeBounded(span)) { |
| 1425 opp->removeSpan(bounded); |
| 1426 } |
| 1427 SkASSERT(!span->fDeleted || !opp->debugHasBounded(span)); |
| 1428 |
829 } | 1429 } |
830 } | 1430 } |
831 | 1431 |
832 template<typename TCurve> | 1432 template<typename TCurve> |
833 void SkTSect<TCurve>::setPerp(const TCurve& opp, SkTSpan<TCurve>* first, SkTSpan
<TCurve>* last) { | 1433 SkTSpan<TCurve>* SkTSect<TCurve>::spanAtT(double t, SkTSpan<TCurve>** priorSpan)
{ |
834 SkTSpan<TCurve>* work = first; | 1434 SkTSpan<TCurve>* test = fHead; |
835 if (!work->fHasPerp) { | 1435 SkTSpan<TCurve>* prev = NULL; |
836 work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp); | 1436 while (test && test->fEndT < t) { |
| 1437 prev = test; |
| 1438 test = test->fNext; |
837 } | 1439 } |
838 do { | 1440 *priorSpan = prev; |
839 if (!work->fHasPerp) { | 1441 return test && test->fStartT <= t ? test : NULL; |
840 work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPoi
ntLast], opp); | |
841 work->fHasPerp = true; | |
842 } | |
843 if (work == last) { | |
844 break; | |
845 } | |
846 SkTSpan<TCurve>* last = work; | |
847 work = work->fNext; | |
848 SkASSERT(work); | |
849 if (!work->fHasPerp) { | |
850 work->fCoinStart = last->fCoinEnd; | |
851 } | |
852 } while (true); | |
853 } | 1442 } |
854 | 1443 |
855 template<typename TCurve> | 1444 template<typename TCurve> |
856 const SkTSpan<TCurve>* SkTSect<TCurve>::tail() const { | 1445 SkTSpan<TCurve>* SkTSect<TCurve>::tail() { |
857 const SkTSpan<TCurve>* result = fHead; | 1446 SkTSpan<TCurve>* result = fHead; |
858 const SkTSpan<TCurve>* next = fHead; | 1447 SkTSpan<TCurve>* next = fHead; |
859 while ((next = next->fNext)) { | 1448 while ((next = next->fNext)) { |
860 if (next->fEndT > result->fEndT) { | 1449 if (next->fEndT > result->fEndT) { |
861 result = next; | 1450 result = next; |
862 } | 1451 } |
863 } | 1452 } |
864 return result; | 1453 return result; |
865 } | 1454 } |
866 | 1455 |
867 /* Each span has a range of opposite spans it intersects. After the span is spli
t in two, | 1456 /* Each span has a range of opposite spans it intersects. After the span is spli
t in two, |
868 adjust the range to its new size */ | 1457 adjust the range to its new size */ |
869 template<typename TCurve> | 1458 template<typename TCurve> |
870 void SkTSect<TCurve>::trim(SkTSpan<TCurve>* span, SkTSect* opp) { | 1459 void SkTSect<TCurve>::trim(SkTSpan<TCurve>* span, SkTSect* opp) { |
871 span->initBounds(fCurve); | 1460 span->initBounds(fCurve); |
872 int count = span->fBounded.count(); | 1461 for (int index = 0; index < span->fBounded.count(); ) { |
873 for (int index = 0; index < count; ) { | |
874 SkTSpan<TCurve>* test = span->fBounded[index]; | 1462 SkTSpan<TCurve>* test = span->fBounded[index]; |
875 bool sects = intersects(span, opp, test); | 1463 int oppSects, sects = this->intersects(span, opp, test, &oppSects); |
876 if (sects) { | 1464 if (sects >= 1) { |
| 1465 if (sects == 2) { |
| 1466 span->initBounds(fCurve); |
| 1467 this->removeAllBut(test, span, opp); |
| 1468 } |
| 1469 if (oppSects == 2) { |
| 1470 test->initBounds(opp->fCurve); |
| 1471 opp->removeAllBut(span, test, this); |
| 1472 } |
877 ++index; | 1473 ++index; |
878 } else { | 1474 } else { |
879 removeOne(test, span); | 1475 if (span->removeBounded(test)) { |
880 opp->removeOne(span, test); | 1476 this->removeSpan(span); |
881 --count; | 1477 } |
| 1478 if (test->removeBounded(span)) { |
| 1479 opp->removeSpan(test); |
| 1480 } |
882 } | 1481 } |
883 } | 1482 } |
884 } | 1483 } |
885 | 1484 |
886 #if DEBUG_T_SECT | 1485 template<typename TCurve> |
| 1486 void SkTSect<TCurve>::unlinkSpan(SkTSpan<TCurve>* span) { |
| 1487 SkTSpan<TCurve>* prev = span->fPrev; |
| 1488 SkTSpan<TCurve>* next = span->fNext; |
| 1489 if (prev) { |
| 1490 prev->fNext = next; |
| 1491 if (next) { |
| 1492 next->fPrev = prev; |
| 1493 } |
| 1494 } else { |
| 1495 fHead = next; |
| 1496 if (next) { |
| 1497 next->fPrev = NULL; |
| 1498 } |
| 1499 } |
| 1500 } |
| 1501 |
| 1502 template<typename TCurve> |
| 1503 bool SkTSect<TCurve>::updateBounded(SkTSpan<TCurve>* first, SkTSpan<TCurve>* las
t, |
| 1504 SkTSpan<TCurve>* oppFirst) { |
| 1505 SkTSpan<TCurve>* test = first; |
| 1506 const SkTSpan<TCurve>* final = last->next(); |
| 1507 bool deleteSpan = false; |
| 1508 do { |
| 1509 deleteSpan |= test->removeAllBounded(); |
| 1510 } while ((test = test->fNext) != final); |
| 1511 first->fBounded.resize_back(1); |
| 1512 first->fBounded[0] = oppFirst; |
| 1513 // cannot call validate until remove span range is called |
| 1514 return deleteSpan; |
| 1515 } |
| 1516 |
| 1517 |
887 template<typename TCurve> | 1518 template<typename TCurve> |
888 void SkTSect<TCurve>::validate() const { | 1519 void SkTSect<TCurve>::validate() const { |
| 1520 #if DEBUG_T_SECT |
889 int count = 0; | 1521 int count = 0; |
890 if (fHead) { | 1522 if (fHead) { |
891 const SkTSpan<TCurve>* span = fHead; | 1523 const SkTSpan<TCurve>* span = fHead; |
892 SkASSERT(!span->fPrev); | 1524 SkASSERT(!span->fPrev); |
893 double last = 0; | 1525 SkDEBUGCODE(double last = 0); |
894 do { | 1526 do { |
895 span->validate(); | 1527 span->validate(); |
896 SkASSERT(span->fStartT >= last); | 1528 SkASSERT(span->fStartT >= last); |
897 last = span->fEndT; | 1529 SkDEBUGCODE(last = span->fEndT); |
898 ++count; | 1530 ++count; |
899 } while ((span = span->fNext) != NULL); | 1531 } while ((span = span->fNext) != NULL); |
900 } | 1532 } |
901 SkASSERT(count == fActiveCount); | 1533 SkASSERT(count == fActiveCount); |
902 SkASSERT(fActiveCount <= fDebugAllocatedCount); | 1534 SkASSERT(fActiveCount <= fDebugAllocatedCount); |
903 int deletedCount = 0; | 1535 int deletedCount = 0; |
904 const SkTSpan<TCurve>* deleted = fDeleted; | 1536 const SkTSpan<TCurve>* deleted = fDeleted; |
905 while (deleted) { | 1537 while (deleted) { |
906 ++deletedCount; | 1538 ++deletedCount; |
907 deleted = deleted->fNext; | 1539 deleted = deleted->fNext; |
908 } | 1540 } |
| 1541 const SkTSpan<TCurve>* coincident = fCoincident; |
| 1542 while (coincident) { |
| 1543 ++deletedCount; |
| 1544 coincident = coincident->fNext; |
| 1545 } |
909 SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount); | 1546 SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount); |
| 1547 #endif |
910 } | 1548 } |
| 1549 |
| 1550 template<typename TCurve> |
| 1551 void SkTSect<TCurve>::validateBounded() const { |
| 1552 #if DEBUG_T_SECT |
| 1553 if (!fHead) { |
| 1554 return; |
| 1555 } |
| 1556 const SkTSpan<TCurve>* span = fHead; |
| 1557 do { |
| 1558 span->validateBounded(); |
| 1559 } while ((span = span->fNext) != NULL); |
911 #endif | 1560 #endif |
| 1561 } |
912 | 1562 |
913 template<typename TCurve> | 1563 template<typename TCurve> |
914 int SkTSect<TCurve>::EndsEqual(const SkTSect* sect1, const SkTSect* sect2, | 1564 int SkTSect<TCurve>::EndsEqual(const SkTSect* sect1, const SkTSect* sect2, |
915 SkIntersections* intersections) { | 1565 SkIntersections* intersections) { |
916 int zeroOneSet = 0; | 1566 int zeroOneSet = 0; |
| 1567 if (sect1->fCurve[0] == sect2->fCurve[0]) { |
| 1568 zeroOneSet |= kZeroS1Set | kZeroS2Set; |
| 1569 intersections->insert(0, 0, sect1->fCurve[0]); |
| 1570 } |
| 1571 if (sect1->fCurve[0] == sect2->fCurve[TCurve::kPointLast]) { |
| 1572 zeroOneSet |= kZeroS1Set | kOneS2Set; |
| 1573 intersections->insert(0, 1, sect1->fCurve[0]); |
| 1574 } |
| 1575 if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[0]) { |
| 1576 zeroOneSet |= kOneS1Set | kZeroS2Set; |
| 1577 intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]); |
| 1578 } |
| 1579 if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[TCurve::kPointLast])
{ |
| 1580 zeroOneSet |= kOneS1Set | kOneS2Set; |
| 1581 intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]); |
| 1582 } |
917 // check for zero | 1583 // check for zero |
918 if (sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) { | 1584 if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set)) |
| 1585 && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) { |
919 zeroOneSet |= kZeroS1Set | kZeroS2Set; | 1586 zeroOneSet |= kZeroS1Set | kZeroS2Set; |
920 if (sect1->fCurve[0] != sect2->fCurve[0]) { | 1587 intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]); |
921 intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]); | 1588 } |
922 } else { | 1589 if (!(zeroOneSet & (kZeroS1Set | kOneS2Set)) |
923 intersections->insert(0, 0, sect1->fCurve[0]); | 1590 && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[TCurve::kPointL
ast])) { |
924 } | |
925 } | |
926 if (sect1->fCurve[0].approximatelyEqual(sect2->fCurve[TCurve::kPointLast]))
{ | |
927 zeroOneSet |= kZeroS1Set | kOneS2Set; | 1591 zeroOneSet |= kZeroS1Set | kOneS2Set; |
928 if (sect1->fCurve[0] != sect2->fCurve[TCurve::kPointLast]) { | 1592 intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[TCurve::
kPointLast]); |
929 intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[TCur
ve::kPointLast]); | 1593 } |
930 } else { | |
931 intersections->insert(0, 1, sect1->fCurve[0]); | |
932 } | |
933 } | |
934 // check for one | 1594 // check for one |
935 if (sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0]))
{ | 1595 if (!(zeroOneSet & (kOneS1Set | kZeroS2Set)) |
| 1596 && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurv
e[0])) { |
936 zeroOneSet |= kOneS1Set | kZeroS2Set; | 1597 zeroOneSet |= kOneS1Set | kZeroS2Set; |
937 if (sect1->fCurve[TCurve::kPointLast] != sect2->fCurve[0]) { | 1598 intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], sect2
->fCurve[0]); |
938 intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], s
ect2->fCurve[0]); | 1599 } |
939 } else { | 1600 if (!(zeroOneSet & (kOneS1Set | kOneS2Set)) |
940 intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]); | 1601 && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurv
e[ |
941 } | 1602 TCurve::kPointLast])) { |
942 } | |
943 if (sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[TCurv
e::kPointLast])) { | |
944 zeroOneSet |= kOneS1Set | kOneS2Set; | 1603 zeroOneSet |= kOneS1Set | kOneS2Set; |
945 if (sect1->fCurve[TCurve::kPointLast] != sect2->fCurve[TCurve::kPointLas
t]) { | 1604 intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast], |
946 intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast], | 1605 sect2->fCurve[TCurve::kPointLast]); |
947 sect2->fCurve[TCurve::kPointLast]); | |
948 } else { | |
949 intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]); | |
950 } | |
951 } | 1606 } |
952 return zeroOneSet; | 1607 return zeroOneSet; |
953 } | 1608 } |
954 | 1609 |
955 template<typename TCurve> | 1610 template<typename TCurve> |
956 struct SkClosestRecord { | 1611 struct SkClosestRecord { |
| 1612 bool operator<(const SkClosestRecord& rh) const { |
| 1613 return fClosest < rh.fClosest; |
| 1614 } |
| 1615 |
957 void addIntersection(SkIntersections* intersections) const { | 1616 void addIntersection(SkIntersections* intersections) const { |
958 double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT(); | 1617 double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT(); |
959 double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT(); | 1618 double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT(); |
960 intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]); | 1619 intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]); |
961 } | 1620 } |
962 | 1621 |
963 void findEnd(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2, | 1622 void findEnd(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2, |
964 int c1Index, int c2Index) { | 1623 int c1Index, int c2Index) { |
965 const TCurve& c1 = span1->part(); | 1624 const TCurve& c1 = span1->part(); |
966 const TCurve& c2 = span2->part(); | 1625 const TCurve& c2 = span2->part(); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 int fC2Index; | 1685 int fC2Index; |
1027 }; | 1686 }; |
1028 | 1687 |
1029 template<typename TCurve> | 1688 template<typename TCurve> |
1030 struct SkClosestSect { | 1689 struct SkClosestSect { |
1031 SkClosestSect() | 1690 SkClosestSect() |
1032 : fUsed(0) { | 1691 : fUsed(0) { |
1033 fClosest.push_back().reset(); | 1692 fClosest.push_back().reset(); |
1034 } | 1693 } |
1035 | 1694 |
1036 void find(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2) { | 1695 bool find(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2) { |
1037 SkClosestRecord<TCurve>* record = &fClosest[fUsed]; | 1696 SkClosestRecord<TCurve>* record = &fClosest[fUsed]; |
1038 record->findEnd(span1, span2, 0, 0); | 1697 record->findEnd(span1, span2, 0, 0); |
1039 record->findEnd(span1, span2, 0, TCurve::kPointLast); | 1698 record->findEnd(span1, span2, 0, TCurve::kPointLast); |
1040 record->findEnd(span1, span2, TCurve::kPointLast, 0); | 1699 record->findEnd(span1, span2, TCurve::kPointLast, 0); |
1041 record->findEnd(span1, span2, TCurve::kPointLast, TCurve::kPointLast); | 1700 record->findEnd(span1, span2, TCurve::kPointLast, TCurve::kPointLast); |
1042 if (record->fClosest == FLT_MAX) { | 1701 if (record->fClosest == FLT_MAX) { |
1043 return; | 1702 return false; |
1044 } | 1703 } |
1045 for (int index = 0; index < fUsed; ++index) { | 1704 for (int index = 0; index < fUsed; ++index) { |
1046 SkClosestRecord<TCurve>* test = &fClosest[index]; | 1705 SkClosestRecord<TCurve>* test = &fClosest[index]; |
1047 if (test->matesWith(*record)) { | 1706 if (test->matesWith(*record)) { |
1048 if (test->fClosest > record->fClosest) { | 1707 if (test->fClosest > record->fClosest) { |
1049 test->merge(*record); | 1708 test->merge(*record); |
1050 } | 1709 } |
1051 test->update(*record); | 1710 test->update(*record); |
1052 record->reset(); | 1711 record->reset(); |
1053 return; | 1712 return false; |
1054 } | 1713 } |
1055 } | 1714 } |
1056 ++fUsed; | 1715 ++fUsed; |
1057 fClosest.push_back().reset(); | 1716 fClosest.push_back().reset(); |
| 1717 return true; |
1058 } | 1718 } |
1059 | 1719 |
1060 void finish(SkIntersections* intersections) const { | 1720 void finish(SkIntersections* intersections) const { |
| 1721 SkSTArray<TCurve::kMaxIntersections * 2, const SkClosestRecord<TCurve>*,
true> closestPtrs; |
1061 for (int index = 0; index < fUsed; ++index) { | 1722 for (int index = 0; index < fUsed; ++index) { |
1062 const SkClosestRecord<TCurve>& test = fClosest[index]; | 1723 closestPtrs.push_back(&fClosest[index]); |
1063 test.addIntersection(intersections); | 1724 } |
| 1725 SkTQSort<const SkClosestRecord<TCurve> >(closestPtrs.begin(), closestPtr
s.end() - 1); |
| 1726 for (int index = 0; index < fUsed; ++index) { |
| 1727 const SkClosestRecord<TCurve>* test = closestPtrs[index]; |
| 1728 test->addIntersection(intersections); |
1064 } | 1729 } |
1065 } | 1730 } |
1066 | 1731 |
1067 // this is oversized by one so that an extra record can merge into final one | 1732 // this is oversized so that an extra records can merge into final one |
1068 SkSTArray<TCurve::kMaxIntersections + 1, SkClosestRecord<TCurve>, true> fClo
sest; | 1733 SkSTArray<TCurve::kMaxIntersections * 2, SkClosestRecord<TCurve>, true> fClo
sest; |
1069 int fUsed; | 1734 int fUsed; |
1070 }; | 1735 }; |
1071 | 1736 |
1072 // returns true if the rect is too small to consider | 1737 // returns true if the rect is too small to consider |
1073 template<typename TCurve> | 1738 template<typename TCurve> |
1074 void SkTSect<TCurve>::BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersectio
ns* intersections) { | 1739 void SkTSect<TCurve>::BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersectio
ns* intersections) { |
| 1740 PATH_OPS_DEBUG_CODE(sect1->fOppSect = sect2); |
| 1741 PATH_OPS_DEBUG_CODE(sect2->fOppSect = sect1); |
1075 intersections->reset(); | 1742 intersections->reset(); |
1076 intersections->setMax(TCurve::kMaxIntersections); | 1743 intersections->setMax(TCurve::kMaxIntersections * 2); // give extra for slo
p |
1077 SkTSpan<TCurve>* span1 = sect1->fHead; | 1744 SkTSpan<TCurve>* span1 = sect1->fHead; |
1078 SkTSpan<TCurve>* span2 = sect2->fHead; | 1745 SkTSpan<TCurve>* span2 = sect2->fHead; |
1079 bool check; | 1746 int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect); |
1080 if (!span1->intersects(span2, &check)) { | 1747 // SkASSERT(between(0, sect, 2)); |
| 1748 if (!sect) { |
1081 return; | 1749 return; |
1082 } | 1750 } |
1083 if (check) { | 1751 if (sect == 2 && oppSect == 2) { |
1084 (void) EndsEqual(sect1, sect2, intersections); | 1752 (void) EndsEqual(sect1, sect2, intersections); |
1085 return; | 1753 return; |
1086 } | 1754 } |
1087 span1->fBounded.push_back() = span2; | 1755 span1->fBounded.push_back() = span2; |
1088 span2->fBounded.push_back() = span1; | 1756 span2->fBounded.push_back() = span1; |
1089 do { | 1757 do { |
1090 // find the largest bounds | 1758 // find the largest bounds |
1091 SkTSpan<TCurve>* largest1 = sect1->boundsMax(); | 1759 SkTSpan<TCurve>* largest1 = sect1->boundsMax(); |
1092 if (!largest1) { | 1760 if (!largest1) { |
1093 break; | 1761 break; |
1094 } | 1762 } |
1095 SkTSpan<TCurve>* largest2 = sect2->boundsMax(); | 1763 SkTSpan<TCurve>* largest2 = sect2->boundsMax(); |
1096 bool split1 = !largest2 || (largest1 && (largest1->fBoundsMax > largest2
->fBoundsMax | 1764 bool split1 = !largest2 || (largest1 && (largest1->fBoundsMax > largest2
->fBoundsMax |
1097 || (!largest1->fCollapsed && largest2->fCollapsed))); | 1765 || (!largest1->fCollapsed && largest2->fCollapsed))); |
1098 // split it | 1766 // split it |
1099 SkTSect* splitSect = split1 ? sect1 : sect2; | |
1100 SkTSpan<TCurve>* half1 = split1 ? largest1 : largest2; | 1767 SkTSpan<TCurve>* half1 = split1 ? largest1 : largest2; |
1101 SkASSERT(half1); | 1768 SkASSERT(half1); |
1102 if (half1->fCollapsed) { | 1769 if (half1->fCollapsed) { |
1103 break; | 1770 break; |
1104 } | 1771 } |
| 1772 SkTSect* splitSect = split1 ? sect1 : sect2; |
1105 // trim parts that don't intersect the opposite | 1773 // trim parts that don't intersect the opposite |
1106 SkTSpan<TCurve>* half2 = splitSect->addOne(); | 1774 SkTSpan<TCurve>* half2 = splitSect->addOne(); |
1107 SkTSect* unsplitSect = split1 ? sect2 : sect1; | 1775 SkTSect* unsplitSect = split1 ? sect2 : sect1; |
1108 if (!half2->split(half1)) { | 1776 if (!half2->split(half1)) { |
1109 break; | 1777 break; |
1110 } | 1778 } |
1111 splitSect->trim(half1, unsplitSect); | 1779 splitSect->trim(half1, unsplitSect); |
1112 splitSect->trim(half2, unsplitSect); | 1780 splitSect->trim(half2, unsplitSect); |
| 1781 sect1->validate(); |
| 1782 sect2->validate(); |
1113 // if there are 9 or more continuous spans on both sects, suspect coinci
dence | 1783 // if there are 9 or more continuous spans on both sects, suspect coinci
dence |
1114 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT | 1784 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT |
1115 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { | 1785 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { |
1116 sect1->coincidentCheck(sect2); | 1786 sect1->coincidentCheck(sect2); |
| 1787 sect1->validate(); |
| 1788 sect2->validate(); |
1117 } | 1789 } |
1118 #if DEBUG_T_SECT | 1790 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT |
1119 sect1->validate(); | 1791 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { |
1120 sect2->validate(); | 1792 sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail()); |
1121 #endif | 1793 sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail()); |
1122 #if DEBUG_T_SECT_DUMP > 1 | 1794 sect1->removeByPerpendicular(sect2); |
1123 sect1->dumpBoth(*sect2); | 1795 sect1->validate(); |
| 1796 sect2->validate(); |
| 1797 } |
| 1798 #if DEBUG_T_SECT_DUMP |
| 1799 sect1->dumpBoth(sect2); |
1124 #endif | 1800 #endif |
1125 if (!sect1->fHead || !sect2->fHead) { | 1801 if (!sect1->fHead || !sect2->fHead) { |
1126 return; | 1802 break; |
1127 } | 1803 } |
1128 } while (true); | 1804 } while (true); |
1129 if (sect1->fActiveCount >= 2 && sect2->fActiveCount >= 2) { | 1805 SkTSpan<TCurve>* coincident = sect1->fCoincident; |
1130 // check for coincidence | 1806 if (coincident) { |
1131 SkTSpan<TCurve>* first = sect1->fHead; | 1807 // if there is more than one coincident span, check loosely to see if th
ey should be joined |
| 1808 if (coincident->fNext) { |
| 1809 sect1->mergeCoincidence(sect2); |
| 1810 coincident = sect1->fCoincident; |
| 1811 } |
| 1812 SkASSERT(sect2->fCoincident); // courtesy check : coincidence only look
s at sect 1 |
1132 do { | 1813 do { |
1133 if (!first->fCoinStart.isCoincident()) { | 1814 SkASSERT(coincident->fCoinStart.isCoincident()); |
1134 continue; | 1815 SkASSERT(coincident->fCoinEnd.isCoincident()); |
1135 } | 1816 int index = intersections->insertCoincident(coincident->fStartT, |
1136 int spanCount = 1; | 1817 coincident->fCoinStart.perpT(), coincident->fPart[0]); |
1137 SkTSpan<TCurve>* last = first; | 1818 if ((intersections->insertCoincident(coincident->fEndT, |
1138 while (last->fCoinEnd.isCoincident()) { | 1819 coincident->fCoinEnd.perpT(), |
1139 SkTSpan<TCurve>* next = last->fNext; | 1820 coincident->fPart[TCurve::kPointLast]) < 0) && index >= 0) { |
1140 if (!next || !next->fCoinEnd.isCoincident()) { | |
1141 break; | |
1142 } | |
1143 last = next; | |
1144 ++spanCount; | |
1145 } | |
1146 if (spanCount < 2) { | |
1147 first = last; | |
1148 continue; | |
1149 } | |
1150 int index = intersections->insertCoincident(first->fStartT, first->f
CoinStart.perpT(), | |
1151 first->fPart[0]); | |
1152 if (intersections->insertCoincident(last->fEndT, last->fCoinEnd.perp
T(), | |
1153 last->fPart[TCurve::kPointLast]) < 0) { | |
1154 intersections->clearCoincidence(index); | 1821 intersections->clearCoincidence(index); |
1155 } | 1822 } |
1156 } while ((first = first->fNext)); | 1823 } while ((coincident = coincident->fNext)); |
| 1824 } |
| 1825 if (!sect1->fHead || !sect2->fHead) { |
| 1826 return; |
1157 } | 1827 } |
1158 int zeroOneSet = EndsEqual(sect1, sect2, intersections); | 1828 int zeroOneSet = EndsEqual(sect1, sect2, intersections); |
1159 sect1->recoverCollapsed(); | 1829 sect1->recoverCollapsed(); |
1160 sect2->recoverCollapsed(); | 1830 sect2->recoverCollapsed(); |
1161 SkTSpan<TCurve>* result1 = sect1->fHead; | 1831 SkTSpan<TCurve>* result1 = sect1->fHead; |
1162 // check heads and tails for zero and ones and insert them if we haven't alr
eady done so | 1832 // check heads and tails for zero and ones and insert them if we haven't alr
eady done so |
1163 const SkTSpan<TCurve>* head1 = result1; | 1833 const SkTSpan<TCurve>* head1 = result1; |
1164 if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStart
T)) { | 1834 if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStart
T)) { |
1165 const SkDPoint& start1 = sect1->fCurve[0]; | 1835 const SkDPoint& start1 = sect1->fCurve[0]; |
1166 double t = head1->closestBoundedT(start1); | 1836 if (head1->isBounded()) { |
1167 if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) { | 1837 double t = head1->closestBoundedT(start1); |
1168 intersections->insert(0, t, start1); | 1838 if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) { |
| 1839 intersections->insert(0, t, start1); |
| 1840 } |
1169 } | 1841 } |
1170 } | 1842 } |
1171 const SkTSpan<TCurve>* head2 = sect2->fHead; | 1843 const SkTSpan<TCurve>* head2 = sect2->fHead; |
1172 if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStart
T)) { | 1844 if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStart
T)) { |
1173 const SkDPoint& start2 = sect2->fCurve[0]; | 1845 const SkDPoint& start2 = sect2->fCurve[0]; |
1174 double t = head2->closestBoundedT(start2); | 1846 if (head2->isBounded()) { |
1175 if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) { | 1847 double t = head2->closestBoundedT(start2); |
1176 intersections->insert(t, 0, start2); | 1848 if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) { |
| 1849 intersections->insert(t, 0, start2); |
| 1850 } |
1177 } | 1851 } |
1178 } | 1852 } |
1179 const SkTSpan<TCurve>* tail1 = sect1->tail(); | 1853 const SkTSpan<TCurve>* tail1 = sect1->tail(); |
1180 if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT
)) { | 1854 if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT
)) { |
1181 const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast]; | 1855 const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast]; |
1182 double t = tail1->closestBoundedT(end1); | 1856 if (tail1->isBounded()) { |
1183 if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) { | 1857 double t = tail1->closestBoundedT(end1); |
1184 intersections->insert(1, t, end1); | 1858 if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) { |
| 1859 intersections->insert(1, t, end1); |
| 1860 } |
1185 } | 1861 } |
1186 } | 1862 } |
1187 const SkTSpan<TCurve>* tail2 = sect2->tail(); | 1863 const SkTSpan<TCurve>* tail2 = sect2->tail(); |
1188 if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT
)) { | 1864 if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT
)) { |
1189 const SkDPoint& end2 = sect2->fCurve[TCurve::kPointLast]; | 1865 const SkDPoint& end2 = sect2->fCurve[TCurve::kPointLast]; |
1190 double t = tail2->closestBoundedT(end2); | 1866 if (tail2->isBounded()) { |
1191 if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) { | 1867 double t = tail2->closestBoundedT(end2); |
1192 intersections->insert(t, 1, end2); | 1868 if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) { |
| 1869 intersections->insert(t, 1, end2); |
| 1870 } |
1193 } | 1871 } |
1194 } | 1872 } |
1195 SkClosestSect<TCurve> closest; | 1873 SkClosestSect<TCurve> closest; |
1196 do { | 1874 do { |
1197 while (result1 && result1->fCoinStart.isCoincident() && result1->fCoinEn
d.isCoincident()) { | 1875 while (result1 && result1->fCoinStart.isCoincident() && result1->fCoinEn
d.isCoincident()) { |
1198 result1 = result1->fNext; | 1876 result1 = result1->fNext; |
1199 } | 1877 } |
1200 if (!result1) { | 1878 if (!result1) { |
1201 break; | 1879 break; |
1202 } | 1880 } |
1203 SkTSpan<TCurve>* result2 = sect2->fHead; | 1881 SkTSpan<TCurve>* result2 = sect2->fHead; |
| 1882 bool found = false; |
1204 while (result2) { | 1883 while (result2) { |
1205 closest.find(result1, result2); | 1884 found |= closest.find(result1, result2); |
1206 result2 = result2->fNext; | 1885 result2 = result2->fNext; |
1207 } | 1886 } |
1208 | |
1209 } while ((result1 = result1->fNext)); | 1887 } while ((result1 = result1->fNext)); |
1210 closest.finish(intersections); | 1888 closest.finish(intersections); |
| 1889 // if there is more than one intersection and it isn't already coincident, c
heck |
| 1890 int last = intersections->used() - 1; |
| 1891 for (int index = 0; index < last; ) { |
| 1892 if (intersections->isCoincident(index) && intersections->isCoincident(in
dex + 1)) { |
| 1893 ++index; |
| 1894 continue; |
| 1895 } |
| 1896 double midT = ((*intersections)[0][index] + (*intersections)[0][index +
1]) / 2; |
| 1897 SkDPoint midPt = sect1->fCurve.ptAtT(midT); |
| 1898 // intersect perpendicular with opposite curve |
| 1899 SkTCoincident<TCurve> perp; |
| 1900 perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve); |
| 1901 if (!perp.isCoincident()) { |
| 1902 ++index; |
| 1903 continue; |
| 1904 } |
| 1905 if (intersections->isCoincident(index)) { |
| 1906 intersections->removeOne(index); |
| 1907 --last; |
| 1908 } else if (intersections->isCoincident(index + 1)) { |
| 1909 intersections->removeOne(index + 1); |
| 1910 --last; |
| 1911 } else { |
| 1912 intersections->setCoincident(index++); |
| 1913 } |
| 1914 intersections->setCoincident(index); |
| 1915 } |
| 1916 SkASSERT(intersections->used() <= TCurve::kMaxIntersections); |
1211 } | 1917 } |
OLD | NEW |