|
1 /* |
|
2 * Copyright 2012 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 #ifndef SkOpSegment_DEFINE |
|
8 #define SkOpSegment_DEFINE |
|
9 |
|
10 #include "SkOpAngle.h" |
|
11 #include "SkOpSpan.h" |
|
12 #include "SkPathOpsBounds.h" |
|
13 #include "SkPathOpsCurve.h" |
|
14 #include "SkTArray.h" |
|
15 #include "SkTDArray.h" |
|
16 |
|
17 class SkPathWriter; |
|
18 |
|
19 class SkOpSegment { |
|
20 public: |
|
21 SkOpSegment() { |
|
22 #ifdef SK_DEBUG |
|
23 fID = ++SkPathOpsDebug::gSegmentID; |
|
24 #endif |
|
25 } |
|
26 |
|
27 bool operator<(const SkOpSegment& rh) const { |
|
28 return fBounds.fTop < rh.fBounds.fTop; |
|
29 } |
|
30 |
|
31 const SkPathOpsBounds& bounds() const { |
|
32 return fBounds; |
|
33 } |
|
34 |
|
35 // OPTIMIZE |
|
36 // when the edges are initially walked, they don't automatically get the prior and next |
|
37 // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check, |
|
38 // and would additionally remove the need for similar checks in condition edges. It would |
|
39 // also allow intersection code to assume end of segment intersections (maybe?) |
|
40 bool complete() const { |
|
41 int count = fTs.count(); |
|
42 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1; |
|
43 } |
|
44 |
|
45 int count() const { |
|
46 return fTs.count(); |
|
47 } |
|
48 |
|
49 bool done() const { |
|
50 SkASSERT(fDoneSpans <= fTs.count()); |
|
51 return fDoneSpans == fTs.count(); |
|
52 } |
|
53 |
|
54 bool done(int min) const { |
|
55 return fTs[min].fDone; |
|
56 } |
|
57 |
|
58 bool done(const SkOpAngle* angle) const { |
|
59 return done(SkMin32(angle->start(), angle->end())); |
|
60 } |
|
61 |
|
62 // used only by partial coincidence detection |
|
63 SkDPoint dPtAtT(double mid) const { |
|
64 return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); |
|
65 } |
|
66 |
|
67 SkVector dxdy(int index) const { |
|
68 return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT); |
|
69 } |
|
70 |
|
71 SkScalar dy(int index) const { |
|
72 return dxdy(index).fY; |
|
73 } |
|
74 |
|
75 bool intersected() const { |
|
76 return fTs.count() > 0; |
|
77 } |
|
78 |
|
79 bool isCanceled(int tIndex) const { |
|
80 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0; |
|
81 } |
|
82 |
|
83 bool isConnected(int startIndex, int endIndex) const { |
|
84 return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum != SK_MinS32; |
|
85 } |
|
86 |
|
87 bool isHorizontal() const { |
|
88 return fBounds.fTop == fBounds.fBottom; |
|
89 } |
|
90 |
|
91 bool isVertical() const { |
|
92 return fBounds.fLeft == fBounds.fRight; |
|
93 } |
|
94 |
|
95 bool isVertical(int start, int end) const { |
|
96 return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end); |
|
97 } |
|
98 |
|
99 bool operand() const { |
|
100 return fOperand; |
|
101 } |
|
102 |
|
103 int oppSign(const SkOpAngle* angle) const { |
|
104 SkASSERT(angle->segment() == this); |
|
105 return oppSign(angle->start(), angle->end()); |
|
106 } |
|
107 |
|
108 int oppSign(int startIndex, int endIndex) const { |
|
109 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[endIndex].fOppValue; |
|
110 #if DEBUG_WIND_BUMP |
|
111 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result); |
|
112 #endif |
|
113 return result; |
|
114 } |
|
115 |
|
116 int oppSum(int tIndex) const { |
|
117 return fTs[tIndex].fOppSum; |
|
118 } |
|
119 |
|
120 int oppSum(const SkOpAngle* angle) const { |
|
121 int lesser = SkMin32(angle->start(), angle->end()); |
|
122 return fTs[lesser].fOppSum; |
|
123 } |
|
124 |
|
125 int oppValue(int tIndex) const { |
|
126 return fTs[tIndex].fOppValue; |
|
127 } |
|
128 |
|
129 int oppValue(const SkOpAngle* angle) const { |
|
130 int lesser = SkMin32(angle->start(), angle->end()); |
|
131 return fTs[lesser].fOppValue; |
|
132 } |
|
133 |
|
134 const SkOpSegment* other(int index) const { |
|
135 return fTs[index].fOther; |
|
136 } |
|
137 |
|
138 // was used only by right angle winding finding |
|
139 SkPoint ptAtT(double mid) const { |
|
140 return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); |
|
141 } |
|
142 |
|
143 const SkPoint* pts() const { |
|
144 return fPts; |
|
145 } |
|
146 |
|
147 void reset() { |
|
148 init(NULL, (SkPath::Verb) -1, false, false); |
|
149 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); |
|
150 fTs.reset(); |
|
151 } |
|
152 |
|
153 void setOppXor(bool isOppXor) { |
|
154 fOppXor = isOppXor; |
|
155 } |
|
156 |
|
157 void setUpWinding(int index, int endIndex, int* maxWinding, int* sumWinding) { |
|
158 int deltaSum = spanSign(index, endIndex); |
|
159 *maxWinding = *sumWinding; |
|
160 *sumWinding -= deltaSum; |
|
161 } |
|
162 |
|
163 // OPTIMIZATION: mark as debugging only if used solely by tests |
|
164 const SkOpSpan& span(int tIndex) const { |
|
165 return fTs[tIndex]; |
|
166 } |
|
167 |
|
168 // OPTIMIZATION: mark as debugging only if used solely by tests |
|
169 const SkTDArray<SkOpSpan>& spans() const { |
|
170 return fTs; |
|
171 } |
|
172 |
|
173 int spanSign(const SkOpAngle* angle) const { |
|
174 SkASSERT(angle->segment() == this); |
|
175 return spanSign(angle->start(), angle->end()); |
|
176 } |
|
177 |
|
178 int spanSign(int startIndex, int endIndex) const { |
|
179 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[endIndex].fWindValue; |
|
180 #if DEBUG_WIND_BUMP |
|
181 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result); |
|
182 #endif |
|
183 return result; |
|
184 } |
|
185 |
|
186 double t(int tIndex) const { |
|
187 return fTs[tIndex].fT; |
|
188 } |
|
189 |
|
190 double tAtMid(int start, int end, double mid) const { |
|
191 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid; |
|
192 } |
|
193 |
|
194 bool unsortable(int index) const { |
|
195 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd; |
|
196 } |
|
197 |
|
198 void updatePts(const SkPoint pts[]) { |
|
199 fPts = pts; |
|
200 } |
|
201 |
|
202 SkPath::Verb verb() const { |
|
203 return fVerb; |
|
204 } |
|
205 |
|
206 int windSum(int tIndex) const { |
|
207 return fTs[tIndex].fWindSum; |
|
208 } |
|
209 |
|
210 int windValue(int tIndex) const { |
|
211 return fTs[tIndex].fWindValue; |
|
212 } |
|
213 |
|
214 #if defined(SK_DEBUG) || DEBUG_WINDING |
|
215 SkScalar xAtT(int index) const { |
|
216 return xAtT(&fTs[index]); |
|
217 } |
|
218 #endif |
|
219 |
|
220 const SkPoint& xyAtT(const SkOpSpan* span) const { |
|
221 return span->fPt; |
|
222 } |
|
223 |
|
224 const SkPoint& xyAtT(int index) const { |
|
225 return xyAtT(&fTs[index]); |
|
226 } |
|
227 |
|
228 #if defined(SK_DEBUG) || DEBUG_WINDING |
|
229 SkScalar yAtT(int index) const { |
|
230 return yAtT(&fTs[index]); |
|
231 } |
|
232 #endif |
|
233 |
|
234 bool activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles); |
|
235 SkPoint activeLeftTop(bool onlySortable, int* firstT) const; |
|
236 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op); |
|
237 bool activeWinding(int index, int endIndex); |
|
238 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd); |
|
239 void addCurveTo(int start, int end, SkPathWriter* path, bool active) const; |
|
240 void addLine(const SkPoint pts[2], bool operand, bool evenOdd); |
|
241 void addOtherT(int index, double otherT, int otherIndex); |
|
242 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd); |
|
243 int addSelfT(SkOpSegment* other, const SkPoint& pt, double newT); |
|
244 int addT(SkOpSegment* other, const SkPoint& pt, double newT); |
|
245 void addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); |
|
246 void addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT, |
|
247 SkOpSegment* other); |
|
248 void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt); |
|
249 bool betweenTs(int lesser, double testT, int greater) const; |
|
250 void checkEnds(); |
|
251 bool checkSmall(int index) const; |
|
252 void checkTiny(); |
|
253 int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType, |
|
254 SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted); |
|
255 int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething, |
|
256 double mid, bool opp, bool current) const; |
|
257 bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, int oEnd, |
|
258 int step, SkPoint* startPt, SkPoint* endPt, double* endT) const; |
|
259 SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd, |
|
260 bool* unsortable, SkPathOp op, const int xorMiMask, |
|
261 const int xorSuMask); |
|
262 SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd, |
|
263 bool* unsortable); |
|
264 SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable); |
|
265 int findT(double t, const SkOpSegment* ) const; |
|
266 SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool onlySortable); |
|
267 void fixOtherTIndex(); |
|
268 void initWinding(int start, int end); |
|
269 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind, |
|
270 SkScalar hitOppDx); |
|
271 bool isMissing(double startT, const SkPoint& pt) const; |
|
272 bool isTiny(const SkOpAngle* angle) const; |
|
273 bool joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel); |
|
274 SkOpSpan* markAndChaseDoneBinary(int index, int endIndex); |
|
275 SkOpSpan* markAndChaseDoneUnary(int index, int endIndex); |
|
276 SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding); |
|
277 SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding, |
|
278 const SkOpAngle* angle); |
|
279 void markDone(int index, int winding); |
|
280 void markDoneBinary(int index); |
|
281 void markDoneUnary(int index); |
|
282 bool nextCandidate(int* start, int* end) const; |
|
283 int nextSpan(int from, int step) const; |
|
284 void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding, |
|
285 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding); |
|
286 enum SortAngleKind { |
|
287 kMustBeOrdered_SortAngleKind, // required for winding calc |
|
288 kMayBeUnordered_SortAngleKind // ok for find top |
|
289 }; |
|
290 static bool SortAngles(const SkTArray<SkOpAngle, true>& angles, // FIXME: replace with |
|
291 SkTArray<SkOpAngle*, true>* angleList, // Sort Angles 2 |
|
292 SortAngleKind ); |
|
293 static bool SortAngles2(const SkTArray<SkOpAngle, true>& angles, |
|
294 SkTArray<SkOpAngle*, true>* angleList); |
|
295 bool subDivide(int start, int end, SkPoint edge[4]) const; |
|
296 bool subDivide(int start, int end, SkDCubic* result) const; |
|
297 void undoneSpan(int* start, int* end); |
|
298 int updateOppWindingReverse(const SkOpAngle* angle) const; |
|
299 int updateWindingReverse(const SkOpAngle* angle) const; |
|
300 static bool UseInnerWinding(int outerWinding, int innerWinding); |
|
301 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const; |
|
302 int windSum(const SkOpAngle* angle) const; |
|
303 |
|
304 #ifdef SK_DEBUG |
|
305 int debugID() const { |
|
306 return fID; |
|
307 } |
|
308 #endif |
|
309 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
|
310 void debugShowActiveSpans() const; |
|
311 #endif |
|
312 #if DEBUG_SORT || DEBUG_SWAP_TOP |
|
313 void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first, |
|
314 const int contourWinding, const int oppContourWinding, bool sortable) const; |
|
315 void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first, |
|
316 bool sortable); |
|
317 #endif |
|
318 #if DEBUG_CONCIDENT |
|
319 void debugShowTs(const char* prefix) const; |
|
320 #endif |
|
321 #if DEBUG_SHOW_WINDING |
|
322 int debugShowWindingValues(int slotCount, int ofInterest) const; |
|
323 #endif |
|
324 |
|
325 private: |
|
326 struct MissingSpan { |
|
327 double fT; |
|
328 double fEndT; |
|
329 SkOpSegment* fSegment; |
|
330 SkOpSegment* fOther; |
|
331 double fOtherT; |
|
332 SkPoint fPt; |
|
333 }; |
|
334 |
|
335 bool activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles); |
|
336 bool activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles); |
|
337 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op, |
|
338 int* sumMiWinding, int* sumSuWinding, int* maxWinding, int* sumWinding, |
|
339 int* oppMaxWinding, int* oppSumWinding); |
|
340 bool activeWinding(int index, int endIndex, int* maxWinding, int* sumWinding); |
|
341 void addAngle(SkTArray<SkOpAngle, true>* angles, int start, int end) const; |
|
342 void addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); |
|
343 void addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); |
|
344 void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt, |
|
345 const SkPoint& oPt); |
|
346 void addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const; |
|
347 bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const; |
|
348 bool buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool includeOpp) const; |
|
349 void buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const; |
|
350 void bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index, |
|
351 SkTArray<SkPoint, true>* outsideTs); |
|
352 void bumpCoincidentOther(const SkOpSpan& oTest, int* index, |
|
353 SkTArray<SkPoint, true>* outsideTs); |
|
354 bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta); |
|
355 bool clockwise(int tStart, int tEnd) const; |
|
356 static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, |
|
357 SkOpAngle::IncludeType ); |
|
358 static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, |
|
359 SkOpAngle::IncludeType ); |
|
360 bool decrementSpan(SkOpSpan* span); |
|
361 int findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end); |
|
362 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd); |
|
363 bool isSimple(int end) const; |
|
364 bool isTiny(int index) const; |
|
365 void matchWindingValue(int tIndex, double t, bool borrowWind); |
|
366 SkOpSpan* markAndChaseDone(int index, int endIndex, int winding); |
|
367 SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding); |
|
368 SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, const int winding); |
|
369 SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding); |
|
370 SkOpSpan* markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle); |
|
371 void markDoneBinary(int index, int winding, int oppWinding); |
|
372 SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding); |
|
373 void markOneDone(const char* funName, int tIndex, int winding); |
|
374 void markOneDoneBinary(const char* funName, int tIndex); |
|
375 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding); |
|
376 void markOneDoneUnary(const char* funName, int tIndex); |
|
377 SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding); |
|
378 SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding); |
|
379 void markWinding(int index, int winding); |
|
380 void markWinding(int index, int winding, int oppWinding); |
|
381 void markUnsortable(int start, int end); |
|
382 bool monotonicInY(int tStart, int tEnd) const; |
|
383 bool multipleSpans(int end) const; |
|
384 SkOpSegment* nextChase(int* index, const int step, int* min, SkOpSpan** last); |
|
385 int nextExactSpan(int from, int step) const; |
|
386 bool serpentine(int tStart, int tEnd) const; |
|
387 void setUpWindings(int index, int endIndex, int* sumMiWinding, |
|
388 int* maxWinding, int* sumWinding); |
|
389 void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const; |
|
390 static void TrackOutsidePair(SkTArray<SkPoint, true>* outsideTs, const SkPoint& endPt, |
|
391 const SkPoint& startPt); |
|
392 static void TrackOutside(SkTArray<SkPoint, true>* outsideTs, const SkPoint& startPt); |
|
393 int updateOppWinding(int index, int endIndex) const; |
|
394 int updateOppWinding(const SkOpAngle* angle) const; |
|
395 int updateWinding(int index, int endIndex) const; |
|
396 int updateWinding(const SkOpAngle* angle) const; |
|
397 int updateWindingReverse(int index, int endIndex) const; |
|
398 static bool UseInnerWindingReverse(int outerWinding, int innerWinding); |
|
399 SkOpSpan* verifyOneWinding(const char* funName, int tIndex); |
|
400 SkOpSpan* verifyOneWindingU(const char* funName, int tIndex); |
|
401 |
|
402 SkScalar xAtT(const SkOpSpan* span) const { |
|
403 return xyAtT(span).fX; |
|
404 } |
|
405 |
|
406 SkScalar yAtT(const SkOpSpan* span) const { |
|
407 return xyAtT(span).fY; |
|
408 } |
|
409 |
|
410 void zeroSpan(SkOpSpan* span); |
|
411 |
|
412 #if DEBUG_SWAP_TOP |
|
413 bool controlsContainedByEnds(int tStart, int tEnd) const; |
|
414 #endif |
|
415 #if DEBUG_CONCIDENT |
|
416 void debugAddTPair(double t, const SkOpSegment& other, double otherT) const; |
|
417 #endif |
|
418 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE |
|
419 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding); |
|
420 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding); |
|
421 #endif |
|
422 #if DEBUG_WINDING |
|
423 static char as_digit(int value) { |
|
424 return value < 0 ? '?' : value <= 9 ? '0' + value : '+'; |
|
425 } |
|
426 #endif |
|
427 void debugValidate() const; |
|
428 #ifdef SK_DEBUG |
|
429 void dumpPts() const; |
|
430 void dumpDPts() const; |
|
431 void dumpSpans() const; |
|
432 #endif |
|
433 |
|
434 const SkPoint* fPts; |
|
435 SkPathOpsBounds fBounds; |
|
436 // FIXME: can't convert to SkTArray because it uses insert |
|
437 SkTDArray<SkOpSpan> fTs; // two or more (always includes t=0 t=1) |
|
438 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value |
|
439 int fDoneSpans; // quick check that segment is finished |
|
440 // OPTIMIZATION: force the following to be byte-sized |
|
441 SkPath::Verb fVerb; |
|
442 bool fOperand; |
|
443 bool fXor; // set if original contour had even-odd fill |
|
444 bool fOppXor; // set if opposite operand had even-odd fill |
|
445 #ifdef SK_DEBUG |
|
446 int fID; |
|
447 #endif |
|
448 }; |
|
449 |
|
450 #endif |