2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 #ifndef SkOpSegment_DEFINE
8 #define SkOpSegment_DEFINE
10 #include "SkOpAngle.h"
12 #include "SkPathOpsBounds.h"
13 #include "SkPathOpsCurve.h"
15 #include "SkTDArray.h"
17 #if defined(SK_DEBUG) || !FORCE_RELEASE
27 #if defined(SK_DEBUG) || !FORCE_RELEASE
28 fID = sk_atomic_inc(&SkPathOpsDebug::gSegmentID);
32 bool operator<(const SkOpSegment& rh) const {
33 return fBounds.fTop < rh.fBounds.fTop;
41 const SkOpSegment* fSegment;
42 const SkOpSegment* fOther1;
43 const SkOpSegment* fOther2;
46 const SkPathOpsBounds& bounds() const {
51 // when the edges are initially walked, they don't automatically get the prior and next
52 // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
53 // and would additionally remove the need for similar checks in condition edges. It would
54 // also allow intersection code to assume end of segment intersections (maybe?)
55 bool complete() const {
56 int count = fTs.count();
57 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
65 SkASSERT(fDoneSpans <= fTs.count());
66 return fDoneSpans == fTs.count();
69 bool done(int min) const {
70 return fTs[min].fDone;
73 bool done(const SkOpAngle* angle) const {
74 return done(SkMin32(angle->start(), angle->end()));
77 SkDPoint dPtAtT(double mid) const {
78 return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
81 SkVector dxdy(int index) const {
82 return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT);
85 SkScalar dy(int index) const {
86 return dxdy(index).fY;
89 bool hasMultiples() const {
93 bool hasSmall() const {
97 bool hasTiny() const {
101 bool intersected() const {
102 return fTs.count() > 0;
105 bool isCanceled(int tIndex) const {
106 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
109 bool isConnected(int startIndex, int endIndex) const {
110 return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum != SK_MinS32;
113 bool isHorizontal() const {
114 return fBounds.fTop == fBounds.fBottom;
117 bool isVertical() const {
118 return fBounds.fLeft == fBounds.fRight;
121 bool isVertical(int start, int end) const {
122 return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end);
125 bool operand() const {
129 int oppSign(const SkOpAngle* angle) const {
130 SkASSERT(angle->segment() == this);
131 return oppSign(angle->start(), angle->end());
134 int oppSign(int startIndex, int endIndex) const {
135 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[endIndex].fOppValue;
137 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
142 int oppSum(int tIndex) const {
143 return fTs[tIndex].fOppSum;
146 int oppSum(const SkOpAngle* angle) const {
147 int lesser = SkMin32(angle->start(), angle->end());
148 return fTs[lesser].fOppSum;
151 int oppValue(int tIndex) const {
152 return fTs[tIndex].fOppValue;
155 int oppValue(const SkOpAngle* angle) const {
156 int lesser = SkMin32(angle->start(), angle->end());
157 return fTs[lesser].fOppValue;
161 bool oppXor() const {
166 SkPoint ptAtT(double mid) const {
167 return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
170 const SkPoint* pts() const {
175 init(NULL, (SkPath::Verb) -1, false, false);
176 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
180 bool reversePoints(const SkPoint& p1, const SkPoint& p2) const;
182 void setOppXor(bool isOppXor) {
186 void setUpWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
187 int deltaSum = spanSign(index, endIndex);
188 *maxWinding = *sumWinding;
189 *sumWinding -= deltaSum;
192 const SkOpSpan& span(int tIndex) const {
196 const SkOpAngle* spanToAngle(int tStart, int tEnd) const {
197 SkASSERT(tStart != tEnd);
198 const SkOpSpan& span = fTs[tStart];
199 return tStart < tEnd ? span.fToAngle : span.fFromAngle;
202 // FIXME: create some sort of macro or template that avoids casting
203 SkOpAngle* spanToAngle(int tStart, int tEnd) {
204 const SkOpAngle* cAngle = (const_cast<const SkOpSegment*>(this))->spanToAngle(tStart, tEnd);
205 return const_cast<SkOpAngle*>(cAngle);
208 int spanSign(const SkOpAngle* angle) const {
209 SkASSERT(angle->segment() == this);
210 return spanSign(angle->start(), angle->end());
213 int spanSign(int startIndex, int endIndex) const {
214 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[endIndex].fWindValue;
216 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
221 double t(int tIndex) const {
222 return fTs[tIndex].fT;
225 double tAtMid(int start, int end, double mid) const {
226 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
229 void updatePts(const SkPoint pts[]) {
233 SkPath::Verb verb() const {
237 int windSum(int tIndex) const {
238 return fTs[tIndex].fWindSum;
241 int windValue(int tIndex) const {
242 return fTs[tIndex].fWindValue;
245 #if defined(SK_DEBUG) || DEBUG_WINDING
246 SkScalar xAtT(int index) const {
247 return xAtT(&fTs[index]);
252 bool _xor() const { // FIXME: used only by SkOpAngle::debugValidateLoop()
257 const SkPoint& xyAtT(const SkOpSpan* span) const {
261 const SkPoint& xyAtT(int index) const {
262 return xyAtT(&fTs[index]);
265 #if defined(SK_DEBUG) || DEBUG_WINDING
266 SkScalar yAtT(int index) const {
267 return yAtT(&fTs[index]);
271 const SkOpAngle* activeAngle(int index, int* start, int* end, bool* done,
272 bool* sortable) const;
273 SkPoint activeLeftTop(int* firstT) const;
274 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op);
275 bool activeWinding(int index, int endIndex);
276 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd);
277 void addCurveTo(int start, int end, SkPathWriter* path, bool active) const;
278 void addEndSpan(int endIndex);
279 void addLine(const SkPoint pts[2], bool operand, bool evenOdd);
280 void addOtherT(int index, double otherT, int otherIndex);
281 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd);
282 void addSimpleAngle(int endIndex);
283 int addSelfT(const SkPoint& pt, double newT);
284 void addStartSpan(int endIndex);
285 int addT(SkOpSegment* other, const SkPoint& pt, double newT);
286 void addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
287 void addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
289 const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
291 const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
292 const SkPoint& pt, const SkPoint& oPt);
293 void alignMultiples(SkTDArray<AlignedSpan>* aligned);
294 bool alignSpan(int index, double thisT, const SkPoint& thisPt);
295 void alignSpanState(int start, int end);
296 bool betweenTs(int lesser, double testT, int greater) const;
297 void blindCancel(const SkCoincidence& coincidence, SkOpSegment* other);
298 void blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other);
300 double calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max,
301 double hiEnd, const SkOpSegment* other, int thisEnd);
302 double calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, double max,
303 double hiEnd, const SkOpSegment* other, int thisEnd);
304 void checkDuplicates();
306 void checkMultiples();
308 bool checkSmall(int index) const;
310 int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType);
311 bool containsPt(const SkPoint& , int index, int endIndex) const;
312 int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething,
313 double mid, bool opp, bool current) const;
314 bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, int oEnd,
315 int step, SkPoint* startPt, SkPoint* endPt, double* endT) const;
316 SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
317 bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask);
318 SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
320 SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable);
321 int findExactT(double t, const SkOpSegment* ) const;
322 int findOtherT(double t, const SkOpSegment* ) const;
323 int findT(double t, const SkPoint& , const SkOpSegment* ) const;
324 SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool firstPass);
325 void fixOtherTIndex();
326 void initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType);
327 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
329 bool isMissing(double startT, const SkPoint& pt) const;
330 bool isTiny(const SkOpAngle* angle) const;
331 bool joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt, int step,
333 SkOpSpan* markAndChaseDoneBinary(int index, int endIndex);
334 SkOpSpan* markAndChaseDoneUnary(int index, int endIndex);
335 SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding);
336 SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
337 const SkOpAngle* angle);
338 void markDone(int index, int winding);
339 void markDoneBinary(int index);
340 void markDoneUnary(int index);
341 bool nextCandidate(int* start, int* end) const;
342 int nextSpan(int from, int step) const;
343 void pinT(const SkPoint& pt, double* t);
344 void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
345 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding);
347 bool subDivide(int start, int end, SkPoint edge[4]) const;
348 bool subDivide(int start, int end, SkDCubic* result) const;
349 void undoneSpan(int* start, int* end);
350 int updateOppWindingReverse(const SkOpAngle* angle) const;
351 int updateWindingReverse(const SkOpAngle* angle) const;
352 static bool UseInnerWinding(int outerWinding, int innerWinding);
353 static bool UseInnerWindingReverse(int outerWinding, int innerWinding);
354 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const;
355 int windSum(const SkOpAngle* angle) const;
356 // available for testing only
357 #if defined(SK_DEBUG) || !FORCE_RELEASE
358 int debugID() const {
362 int debugID() const {
366 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
367 void debugShowActiveSpans() const;
370 void debugShowTs(const char* prefix) const;
372 #if DEBUG_SHOW_WINDING
373 int debugShowWindingValues(int slotCount, int ofInterest) const;
375 const SkTDArray<SkOpSpan>& debugSpans() const;
376 void debugValidate() const;
377 // available to testing only
378 const SkOpAngle* debugLastAngle() const;
379 void dumpAngles() const;
380 void dumpContour(int firstID, int lastID) const;
381 void dumpPts() const;
382 void dumpSpans() const;
388 SkOpSegment* fSegment;
394 const SkOpAngle* activeAngleInner(int index, int* start, int* end, bool* done,
395 bool* sortable) const;
396 const SkOpAngle* activeAngleOther(int index, int* start, int* end, bool* done,
397 bool* sortable) const;
398 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
399 int* sumMiWinding, int* sumSuWinding);
400 bool activeWinding(int index, int endIndex, int* sumWinding);
401 void addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
402 void addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
403 SkOpAngle* addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** );
404 SkOpAngle* addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** );
405 SkOpAngle* addSingletonAngles(int step);
406 void alignSpan(const SkPoint& newPt, double newT, const SkOpSegment* other, double otherT,
407 const SkOpSegment* other2, SkOpSpan* oSpan, SkTDArray<AlignedSpan>* );
408 bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const;
409 void bumpCoincidentBlind(bool binary, int index, int last);
410 void bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index,
411 SkTArray<SkPoint, true>* outsideTs);
412 void bumpCoincidentOBlind(int index, int last);
413 void bumpCoincidentOther(const SkOpSpan& oTest, int* index,
414 SkTArray<SkPoint, true>* outsideTs);
415 bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta);
416 bool calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts);
417 bool checkForSmall(const SkOpSpan* span, const SkPoint& pt, double newT,
418 int* less, int* more) const;
419 void checkLinks(const SkOpSpan* ,
420 SkTArray<MissingSpan, true>* missingSpans) const;
421 static void CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
422 const SkOpSpan* oFirst, const SkOpSpan* oLast,
423 const SkOpSpan** missingPtr,
424 SkTArray<MissingSpan, true>* missingSpans);
425 int checkSetAngle(int tIndex) const;
426 void checkSmallCoincidence(const SkOpSpan& span, SkTArray<MissingSpan, true>* );
427 bool coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other) const;
428 bool clockwise(int tStart, int tEnd, bool* swap) const;
429 static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
430 SkOpAngle::IncludeType );
431 static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
432 SkOpAngle::IncludeType );
433 bool containsT(double t, const SkOpSegment* other, double otherT) const;
434 bool decrementSpan(SkOpSpan* span);
435 int findEndSpan(int endIndex) const;
436 int findStartSpan(int startIndex) const;
437 int firstActive(int tIndex) const;
438 const SkOpSpan& firstSpan(const SkOpSpan& thisSpan) const;
439 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd);
440 bool inCoincidentSpan(double t, const SkOpSegment* other) const;
441 bool inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const;
443 bool isSimple(int end) const;
445 SkOpSegment* isSimple(int* end, int* step);
447 bool isTiny(int index) const;
448 const SkOpSpan& lastSpan(const SkOpSpan& thisSpan) const;
449 void matchWindingValue(int tIndex, double t, bool borrowWind);
450 SkOpSpan* markAndChaseDone(int index, int endIndex, int winding);
451 SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding);
452 SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding);
453 SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding);
454 SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding);
455 SkOpSpan* markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle);
456 void markDoneBinary(int index, int winding, int oppWinding);
457 SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding);
458 void markOneDone(const char* funName, int tIndex, int winding);
459 void markOneDoneBinary(const char* funName, int tIndex);
460 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding);
461 void markOneDoneUnary(const char* funName, int tIndex);
462 SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding);
463 SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding);
464 void markWinding(int index, int winding);
465 void markWinding(int index, int winding, int oppWinding);
466 bool monotonicInY(int tStart, int tEnd) const;
468 bool multipleEnds() const { return fTs[count() - 2].fT == 1; }
469 bool multipleStarts() const { return fTs[1].fT == 0; }
471 SkOpSegment* nextChase(int* index, int* step, int* min, SkOpSpan** last);
472 int nextExactSpan(int from, int step) const;
473 bool serpentine(int tStart, int tEnd) const;
474 void setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
475 void setFromAngle(int endIndex, SkOpAngle* );
476 void setToAngle(int endIndex, SkOpAngle* );
477 void setUpWindings(int index, int endIndex, int* sumMiWinding,
478 int* maxWinding, int* sumWinding);
479 void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const;
480 static void TrackOutsidePair(SkTArray<SkPoint, true>* outsideTs, const SkPoint& endPt,
481 const SkPoint& startPt);
482 static void TrackOutside(SkTArray<SkPoint, true>* outsideTs, const SkPoint& startPt);
483 int updateOppWinding(int index, int endIndex) const;
484 int updateOppWinding(const SkOpAngle* angle) const;
485 int updateWinding(int index, int endIndex) const;
486 int updateWinding(const SkOpAngle* angle) const;
487 int updateWindingReverse(int index, int endIndex) const;
488 SkOpSpan* verifyOneWinding(const char* funName, int tIndex);
489 SkOpSpan* verifyOneWindingU(const char* funName, int tIndex);
491 SkScalar xAtT(const SkOpSpan* span) const {
492 return xyAtT(span).fX;
495 SkScalar yAtT(const SkOpSpan* span) const {
496 return xyAtT(span).fY;
499 void zeroSpan(SkOpSpan* span);
502 bool controlsContainedByEnds(int tStart, int tEnd) const;
504 void debugAddAngle(int start, int end);
506 void debugAddTPair(double t, const SkOpSegment& other, double otherT) const;
509 void debugCheckPointsEqualish(int tStart, int tEnd) const;
512 int debugInflections(int index, int endIndex) const;
514 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
515 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding);
516 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding);
519 static char as_digit(int value) {
520 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
523 // available to testing only
524 void debugConstruct();
525 void debugConstructCubic(SkPoint shortQuad[4]);
526 void debugConstructLine(SkPoint shortQuad[2]);
527 void debugConstructQuad(SkPoint shortQuad[3]);
529 void dumpDPts() const;
530 void dumpSpan(int index) const;
533 SkPathOpsBounds fBounds;
534 // FIXME: can't convert to SkTArray because it uses insert
535 SkTDArray<SkOpSpan> fTs; // 2+ (always includes t=0 t=1) -- at least (number of spans) + 1
536 SkOpAngleSet fAngles; // empty or 2+ -- (number of non-zero spans) * 2
537 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
538 int fDoneSpans; // quick check that segment is finished
539 // OPTIMIZATION: force the following to be byte-sized
541 bool fLoop; // set if cubic intersects itself
542 bool fMultiples; // set if curve intersects multiple other curves at one interior point
544 bool fXor; // set if original contour had even-odd fill
545 bool fOppXor; // set if opposite operand had even-odd fill
546 bool fSmall; // set if some span is small
547 bool fTiny; // set if some span is tiny
548 #if defined(SK_DEBUG) || !FORCE_RELEASE
552 friend class PathOpsSegmentTester;