SkOpSegment.h revision 7eaa53d8f7e48fd17d02b5e3bd91f90e9c1899ef
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 17class SkPathWriter; 18 19class SkOpSegment { 20public: 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 // OPTIMIZATION: mark as debugging only if used solely by tests 187 double t(int tIndex) const { 188 return fTs[tIndex].fT; 189 } 190 191 double tAtMid(int start, int end, double mid) const { 192 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid; 193 } 194 195 bool unsortable(int index) const { 196 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd; 197 } 198 199 void updatePts(const SkPoint pts[]) { 200 fPts = pts; 201 } 202 203 SkPath::Verb verb() const { 204 return fVerb; 205 } 206 207 int windSum(int tIndex) const { 208 return fTs[tIndex].fWindSum; 209 } 210 211 int windValue(int tIndex) const { 212 return fTs[tIndex].fWindValue; 213 } 214 215 SkScalar xAtT(int index) const { 216 return xAtT(&fTs[index]); 217 } 218 219 SkScalar xAtT(const SkOpSpan* span) const { 220 return xyAtT(span).fX; 221 } 222 223 const SkPoint& xyAtT(const SkOpSpan* span) const { 224 return span->fPt; 225 } 226 227 const SkPoint& xyAtT(int index) const { 228 return xyAtT(&fTs[index]); 229 } 230 231 SkScalar yAtT(int index) const { 232 return yAtT(&fTs[index]); 233 } 234 235 SkScalar yAtT(const SkOpSpan* span) const { 236 return xyAtT(span).fY; 237 } 238 239 bool activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles); 240 SkPoint activeLeftTop(bool onlySortable, int* firstT) const; 241 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op); 242 bool activeWinding(int index, int endIndex); 243 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd); 244 void addCurveTo(int start, int end, SkPathWriter* path, bool active) const; 245 void addLine(const SkPoint pts[2], bool operand, bool evenOdd); 246 void addOtherT(int index, double otherT, int otherIndex); 247 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd); 248 int addSelfT(SkOpSegment* other, const SkPoint& pt, double newT); 249 int addT(SkOpSegment* other, const SkPoint& pt, double newT, bool isNear); 250 void addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); 251 void addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT, 252 SkOpSegment* other); 253 void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt); 254 bool betweenTs(int lesser, double testT, int greater) const; 255 void checkEnds(); 256 bool checkSmall(int index) const; 257 void checkTiny(); 258 int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType, 259 SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted); 260 int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething, 261 double mid, bool opp, bool current) const; 262 SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd, 263 bool* unsortable, SkPathOp op, const int xorMiMask, 264 const int xorSuMask); 265 SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd, 266 bool* unsortable); 267 SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable); 268 SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool onlySortable); 269 void fixOtherTIndex(); 270 void initWinding(int start, int end); 271 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind, 272 SkScalar hitOppDx); 273 bool isMissing(double startT, const SkPoint& pt) const; 274 bool isTiny(const SkOpAngle* angle) const; 275 SkOpSpan* markAndChaseDoneBinary(int index, int endIndex); 276 SkOpSpan* markAndChaseDoneUnary(int index, int endIndex); 277 SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding); 278 SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding, 279 bool activeAngle, const SkOpAngle* angle); 280 void markDone(int index, int winding); 281 void markDoneBinary(int index); 282 void markDoneUnary(int index); 283 bool nextCandidate(int* start, int* end) const; 284 int nextSpan(int from, int step) const; 285 void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding, 286 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding); 287 enum SortAngleKind { 288 kMustBeOrdered_SortAngleKind, // required for winding calc 289 kMayBeUnordered_SortAngleKind // ok for find top 290 }; 291 static bool SortAngles(const SkTArray<SkOpAngle, true>& angles, // FIXME: replace with 292 SkTArray<SkOpAngle*, true>* angleList, // Sort Angles 2 293 SortAngleKind ); 294 static bool SortAngles2(const SkTArray<SkOpAngle, true>& angles, 295 SkTArray<SkOpAngle*, true>* angleList); 296 bool subDivide(int start, int end, SkPoint edge[4]) const; 297 bool subDivide(int start, int end, SkDCubic* result) const; 298 void undoneSpan(int* start, int* end); 299 int updateOppWindingReverse(const SkOpAngle* angle) const; 300 int updateWindingReverse(const SkOpAngle* angle) const; 301 static bool UseInnerWinding(int outerWinding, int innerWinding); 302 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const; 303 int windSum(const SkOpAngle* angle) const; 304 305#ifdef SK_DEBUG 306 int debugID() const { 307 return fID; 308 } 309#endif 310#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY 311 void debugShowActiveSpans() const; 312#endif 313#if DEBUG_SORT || DEBUG_SWAP_TOP 314 void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first, 315 const int contourWinding, const int oppContourWinding, bool sortable) const; 316 void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first, 317 bool sortable); 318#endif 319#if DEBUG_CONCIDENT 320 void debugShowTs(const char* prefix) const; 321#endif 322#if DEBUG_SHOW_WINDING 323 int debugShowWindingValues(int slotCount, int ofInterest) const; 324#endif 325 326private: 327 struct MissingSpan { 328 enum Command { 329 kNoAction, 330 kAddMissing, 331 kRemoveNear, 332 kZeroSpan, 333 } fCommand; 334 double fT; 335 double fEndT; 336 SkOpSegment* fSegment; 337 SkOpSegment* fOther; 338 double fOtherT; 339 SkPoint fPt; 340 }; 341 342 bool activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles); 343 bool activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles); 344 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op, 345 int* sumMiWinding, int* sumSuWinding, int* maxWinding, int* sumWinding, 346 int* oppMaxWinding, int* oppSumWinding); 347 bool activeWinding(int index, int endIndex, int* maxWinding, int* sumWinding); 348 void addAngle(SkTArray<SkOpAngle, true>* angles, int start, int end) const; 349 void addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); 350 void addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); 351 void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt, 352 const SkPoint& oPt); 353 void addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const; 354 void adjustMissingNear(const SkPoint& startPt, const SkPoint& endPt, 355 SkTArray<MissingSpan, true>* ); 356 void adjustNear(double startT, const SkPoint& endPt, SkTArray<MissingSpan, true>* ); 357 void adjustOtherNear(double startT, const SkPoint& startPt, const SkPoint& endPt, 358 SkTArray<MissingSpan, true>* ); 359 MissingSpan::Command adjustThisNear(double startT, const SkPoint& startPt, const SkPoint& endPt, 360 SkTArray<MissingSpan, true>* ); 361 int advanceCoincidentOther(double oEndT, int oIndex); 362 int advanceCoincidentThis(int index); 363 bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const; 364 bool buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool includeOpp) const; 365 void buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const; 366 void bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index, 367 SkTArray<SkPoint, true>* outsideTs); 368 bool bumpCoincident(SkOpSpan* test, bool bigger, bool binary); 369 void bumpCoincidentOther(const SkOpSpan& oTest, int* index, 370 SkTArray<SkPoint, true>* outsideTs); 371 bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta); 372 bool clockwise(int tStart, int tEnd) const; 373 static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, 374 SkOpAngle::IncludeType ); 375 static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, 376 SkOpAngle::IncludeType ); 377 bool decrementSpan(SkOpSpan* span); 378 int findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end); 379 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd); 380 bool isSimple(int end) const; 381 bool isTiny(int index) const; 382 void matchWindingValue(int tIndex, double t, bool borrowWind); 383 SkOpSpan* markAndChaseDone(int index, int endIndex, int winding); 384 SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding); 385 SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, const int winding); 386 SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding); 387 SkOpSpan* markAngle(int maxWinding, int sumWinding, bool activeAngle, const SkOpAngle* angle); 388 void markDoneBinary(int index, int winding, int oppWinding); 389 SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding); 390 void markOneDone(const char* funName, int tIndex, int winding); 391 void markOneDoneBinary(const char* funName, int tIndex); 392 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding); 393 void markOneDoneUnary(const char* funName, int tIndex); 394 SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding); 395 SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding); 396 void markWinding(int index, int winding); 397 void markWinding(int index, int winding, int oppWinding); 398 void markUnsortable(int start, int end); 399 bool monotonicInY(int tStart, int tEnd) const; 400 double missingNear(double otherT, const SkOpSegment* other, const SkPoint& startPt, 401 const SkPoint& endPt) const; 402 bool multipleSpans(int end) const; 403 SkOpSegment* nextChase(int* index, const int step, int* min, SkOpSpan** last); 404 int nextExactSpan(int from, int step) const; 405 bool serpentine(int tStart, int tEnd) const; 406 void setUpWindings(int index, int endIndex, int* sumMiWinding, 407 int* maxWinding, int* sumWinding); 408 void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const; 409 static void TrackOutsidePair(SkTArray<SkPoint, true>* outsideTs, const SkPoint& endPt, 410 const SkPoint& startPt); 411 static void TrackOutside(SkTArray<SkPoint, true>* outsideTs, const SkPoint& startPt); 412 int updateOppWinding(int index, int endIndex) const; 413 int updateOppWinding(const SkOpAngle* angle) const; 414 int updateWinding(int index, int endIndex) const; 415 int updateWinding(const SkOpAngle* angle) const; 416 int updateWindingReverse(int index, int endIndex) const; 417 static bool UseInnerWindingReverse(int outerWinding, int innerWinding); 418 SkOpSpan* verifyOneWinding(const char* funName, int tIndex); 419 SkOpSpan* verifyOneWindingU(const char* funName, int tIndex); 420 int windValue(const SkOpAngle* angle) const; 421 int windValueAt(double t) const; 422 void zeroSpan(SkOpSpan* span); 423 424#if DEBUG_SWAP_TOP 425 bool controlsContainedByEnds(int tStart, int tEnd) const; 426#endif 427#if DEBUG_CONCIDENT 428 void debugAddTPair(double t, const SkOpSegment& other, double otherT) const; 429#endif 430#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE 431 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding); 432 void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding); 433#endif 434#if DEBUG_WINDING 435 static char as_digit(int value) { 436 return value < 0 ? '?' : value <= 9 ? '0' + value : '+'; 437 } 438#endif 439 void debugValidate() const; 440#ifdef SK_DEBUG 441 void dumpPts() const; 442 void dumpDPts() const; 443 void dumpSpans() const; 444#endif 445 446 const SkPoint* fPts; 447 SkPathOpsBounds fBounds; 448 // FIXME: can't convert to SkTArray because it uses insert 449 SkTDArray<SkOpSpan> fTs; // two or more (always includes t=0 t=1) 450 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value 451 int fDoneSpans; // quick check that segment is finished 452 // OPTIMIZATION: force the following to be byte-sized 453 SkPath::Verb fVerb; 454 bool fOperand; 455 bool fXor; // set if original contour had even-odd fill 456 bool fOppXor; // set if opposite operand had even-odd fill 457#ifdef SK_DEBUG 458 int fID; 459#endif 460}; 461 462#endif 463