Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(228)

Side by Side Diff: src/pathops/SkPathOpsTSect.h

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

Powered by Google App Engine
This is Rietveld 408576698