OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkChunkAlloc.h" | 8 #include "SkChunkAlloc.h" |
| 9 #include "SkPathOpsBounds.h" |
9 #include "SkPathOpsRect.h" | 10 #include "SkPathOpsRect.h" |
10 #include "SkPathOpsQuad.h" | 11 #include "SkPathOpsQuad.h" |
11 #include "SkIntersections.h" | 12 #include "SkIntersections.h" |
12 #include "SkTArray.h" | 13 #include "SkTSort.h" |
13 | 14 |
14 /* TCurve is either SkDQuadratic or SkDCubic */ | 15 /* TCurve is either SkDQuadratic or SkDCubic */ |
15 template<typename TCurve> | 16 template<typename TCurve> |
16 class SkTCoincident { | 17 class SkTCoincident { |
17 public: | 18 public: |
| 19 SkTCoincident() |
| 20 : fCoincident(false) { |
| 21 } |
| 22 |
| 23 void clear() { |
| 24 fPerpT = -1; |
| 25 fCoincident = false; |
| 26 } |
| 27 |
18 bool isCoincident() const { | 28 bool isCoincident() const { |
19 return fCoincident; | 29 return fCoincident; |
20 } | 30 } |
21 | 31 |
22 void init() { | 32 void init() { |
23 fCoincident = false; | 33 fCoincident = false; |
24 SkDEBUGCODE(fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN); | 34 SkDEBUGCODE(fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN); |
25 SkDEBUGCODE(fPerpT = SK_ScalarNaN); | 35 SkDEBUGCODE(fPerpT = SK_ScalarNaN); |
26 } | 36 } |
27 | 37 |
(...skipping 14 matching lines...) Expand all Loading... |
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 Loading... |
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 Loading... |
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, §1->fHeap); |
1088 span2->fBounded.push_back() = span1; | 1795 span2->addBounded(span1, §2->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 } |
OLD | NEW |