1 /* 2 * Copyright 2014 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 SkPathOpsTSect_DEFINED 8 #define SkPathOpsTSect_DEFINED 9 10 #include "SkArenaAlloc.h" 11 #include "SkPathOpsBounds.h" 12 #include "SkPathOpsRect.h" 13 #include "SkIntersections.h" 14 #include "SkTSort.h" 15 16 #ifdef SK_DEBUG 17 typedef uint8_t SkOpDebugBool; 18 #else 19 typedef bool SkOpDebugBool; 20 #endif 21 22 /* TCurve and OppCurve are one of { SkDQuadratic, SkDConic, SkDCubic } */ 23 template<typename TCurve, typename OppCurve> 24 class SkTCoincident { 25 public: 26 SkTCoincident() { 27 this->init(); 28 } 29 30 void debugInit() { 31 #ifdef SK_DEBUG 32 this->fPerpPt.fX = this->fPerpPt.fY = SK_ScalarNaN; 33 this->fPerpT = SK_ScalarNaN; 34 this->fMatch = 0xFF; 35 #endif 36 } 37 38 char dumpIsCoincidentStr() const; 39 void dump() const; 40 41 bool isMatch() const { 42 SkASSERT(!!fMatch == fMatch); 43 return SkToBool(fMatch); 44 } 45 46 void init() { 47 fPerpT = -1; 48 fMatch = false; 49 fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN; 50 } 51 52 void markCoincident() { 53 if (!fMatch) { 54 fPerpT = -1; 55 } 56 fMatch = true; 57 } 58 59 const SkDPoint& perpPt() const { 60 return fPerpPt; 61 } 62 63 double perpT() const { 64 return fPerpT; 65 } 66 67 void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve& ); 68 69 private: 70 SkDPoint fPerpPt; 71 double fPerpT; // perpendicular intersection on opposite curve 72 SkOpDebugBool fMatch; 73 }; 74 75 template<typename TCurve, typename OppCurve> class SkTSect; 76 template<typename TCurve, typename OppCurve> class SkTSpan; 77 78 template<typename TCurve, typename OppCurve> 79 struct SkTSpanBounded { 80 SkTSpan<TCurve, OppCurve>* fBounded; 81 SkTSpanBounded* fNext; 82 }; 83 84 /* Curve is either TCurve or SkDCubic */ 85 template<typename TCurve, typename OppCurve> 86 class SkTSpan { 87 public: 88 void addBounded(SkTSpan<OppCurve, TCurve>* , SkArenaAlloc* ); 89 double closestBoundedT(const SkDPoint& pt) const; 90 bool contains(double t) const; 91 92 void debugInit() { 93 TCurve dummy; 94 dummy.debugInit(); 95 init(dummy); 96 initBounds(dummy); 97 fCoinStart.init(); 98 fCoinEnd.init(); 99 } 100 101 const SkTSect<OppCurve, TCurve>* debugOpp() const; 102 103 #ifdef SK_DEBUG 104 void debugSetGlobalState(SkOpGlobalState* state) { 105 fDebugGlobalState = state; 106 } 107 #endif 108 109 const SkTSpan* debugSpan(int ) const; 110 const SkTSpan* debugT(double t) const; 111 #ifdef SK_DEBUG 112 bool debugIsBefore(const SkTSpan* span) const; 113 #endif 114 void dump() const; 115 void dumpAll() const; 116 void dumpBounded(int id) const; 117 void dumpBounds() const; 118 void dumpCoin() const; 119 120 double endT() const { 121 return fEndT; 122 } 123 124 SkTSpan<OppCurve, TCurve>* findOppSpan(const SkTSpan<OppCurve, TCurve>* opp) const; 125 126 SkTSpan<OppCurve, TCurve>* findOppT(double t) const { 127 SkTSpan<OppCurve, TCurve>* result = oppT(t); 128 SkOPASSERT(result); 129 return result; 130 } 131 132 SkDEBUGCODE(SkOpGlobalState* globalState() const { return fDebugGlobalState; }) 133 134 bool hasOppT(double t) const { 135 return SkToBool(oppT(t)); 136 } 137 138 int hullsIntersect(SkTSpan<OppCurve, TCurve>* span, bool* start, bool* oppStart); 139 void init(const TCurve& ); 140 bool initBounds(const TCurve& ); 141 142 bool isBounded() const { 143 return fBounded != nullptr; 144 } 145 146 bool linearsIntersect(SkTSpan<OppCurve, TCurve>* span); 147 double linearT(const SkDPoint& ) const; 148 149 void markCoincident() { 150 fCoinStart.markCoincident(); 151 fCoinEnd.markCoincident(); 152 } 153 154 const SkTSpan* next() const { 155 return fNext; 156 } 157 158 bool onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, bool* start, 159 bool* oppStart, bool* ptsInCommon); 160 161 const TCurve& part() const { 162 return fPart; 163 } 164 165 bool removeAllBounded(); 166 bool removeBounded(const SkTSpan<OppCurve, TCurve>* opp); 167 168 void reset() { 169 fBounded = nullptr; 170 } 171 172 void resetBounds(const TCurve& curve) { 173 fIsLinear = fIsLine = false; 174 initBounds(curve); 175 } 176 177 bool split(SkTSpan* work, SkArenaAlloc* heap) { 178 return splitAt(work, (work->fStartT + work->fEndT) * 0.5, heap); 179 } 180 181 bool splitAt(SkTSpan* work, double t, SkArenaAlloc* heap); 182 183 double startT() const { 184 return fStartT; 185 } 186 187 private: 188 189 // implementation is for testing only 190 int debugID() const { 191 return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); 192 } 193 194 void dumpID() const; 195 196 int hullCheck(const SkTSpan<OppCurve, TCurve>* opp, bool* start, bool* oppStart); 197 int linearIntersects(const OppCurve& ) const; 198 SkTSpan<OppCurve, TCurve>* oppT(double t) const; 199 200 void validate() const; 201 void validateBounded() const; 202 void validatePerpT(double oppT) const; 203 void validatePerpPt(double t, const SkDPoint& ) const; 204 205 TCurve fPart; 206 SkTCoincident<TCurve, OppCurve> fCoinStart; 207 SkTCoincident<TCurve, OppCurve> fCoinEnd; 208 SkTSpanBounded<OppCurve, TCurve>* fBounded; 209 SkTSpan* fPrev; 210 SkTSpan* fNext; 211 SkDRect fBounds; 212 double fStartT; 213 double fEndT; 214 double fBoundsMax; 215 SkOpDebugBool fCollapsed; 216 SkOpDebugBool fHasPerp; 217 SkOpDebugBool fIsLinear; 218 SkOpDebugBool fIsLine; 219 SkOpDebugBool fDeleted; 220 SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); 221 SkDEBUGCODE(SkTSect<TCurve, OppCurve>* fDebugSect); 222 PATH_OPS_DEBUG_T_SECT_CODE(int fID); 223 friend class SkTSect<TCurve, OppCurve>; 224 friend class SkTSect<OppCurve, TCurve>; 225 friend class SkTSpan<OppCurve, TCurve>; 226 }; 227 228 template<typename TCurve, typename OppCurve> 229 class SkTSect { 230 public: 231 SkTSect(const TCurve& c SkDEBUGPARAMS(SkOpGlobalState* ) PATH_OPS_DEBUG_T_SECT_PARAMS(int id)); 232 static void BinarySearch(SkTSect* sect1, SkTSect<OppCurve, TCurve>* sect2, 233 SkIntersections* intersections); 234 235 SkDEBUGCODE(SkOpGlobalState* globalState() { return fDebugGlobalState; }) 236 // for testing only 237 bool debugHasBounded(const SkTSpan<OppCurve, TCurve>* ) const; 238 239 const SkTSect<OppCurve, TCurve>* debugOpp() const { 240 return SkDEBUGRELEASE(fOppSect, nullptr); 241 } 242 243 const SkTSpan<TCurve, OppCurve>* debugSpan(int id) const; 244 const SkTSpan<TCurve, OppCurve>* debugT(double t) const; 245 void dump() const; 246 void dumpBoth(SkTSect<OppCurve, TCurve>* ) const; 247 void dumpBounded(int id) const; 248 void dumpBounds() const; 249 void dumpCoin() const; 250 void dumpCoinCurves() const; 251 void dumpCurves() const; 252 253 private: 254 enum { 255 kZeroS1Set = 1, 256 kOneS1Set = 2, 257 kZeroS2Set = 4, 258 kOneS2Set = 8 259 }; 260 261 SkTSpan<TCurve, OppCurve>* addFollowing(SkTSpan<TCurve, OppCurve>* prior); 262 void addForPerp(SkTSpan<OppCurve, TCurve>* span, double t); 263 SkTSpan<TCurve, OppCurve>* addOne(); 264 265 SkTSpan<TCurve, OppCurve>* addSplitAt(SkTSpan<TCurve, OppCurve>* span, double t) { 266 SkTSpan<TCurve, OppCurve>* result = this->addOne(); 267 SkDEBUGCODE(result->debugSetGlobalState(this->globalState())); 268 result->splitAt(span, t, &fHeap); 269 result->initBounds(fCurve); 270 span->initBounds(fCurve); 271 return result; 272 } 273 274 bool binarySearchCoin(SkTSect<OppCurve, TCurve>* , double tStart, double tStep, double* t, 275 double* oppT); 276 SkTSpan<TCurve, OppCurve>* boundsMax() const; 277 bool coincidentCheck(SkTSect<OppCurve, TCurve>* sect2); 278 void coincidentForce(SkTSect<OppCurve, TCurve>* sect2, double start1s, double start1e); 279 bool coincidentHasT(double t); 280 int collapsed() const; 281 void computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first, 282 SkTSpan<TCurve, OppCurve>* last); 283 int countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first, 284 SkTSpan<TCurve, OppCurve>** last) const; 285 286 int debugID() const { 287 return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); 288 } 289 290 bool deleteEmptySpans(); 291 void dumpCommon(const SkTSpan<TCurve, OppCurve>* ) const; 292 void dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* ) const; 293 static int EndsEqual(const SkTSect* sect1, const SkTSect<OppCurve, TCurve>* sect2, 294 SkIntersections* ); 295 bool extractCoincident(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first, 296 SkTSpan<TCurve, OppCurve>* last, SkTSpan<TCurve, OppCurve>** result); 297 SkTSpan<TCurve, OppCurve>* findCoincidentRun(SkTSpan<TCurve, OppCurve>* first, 298 SkTSpan<TCurve, OppCurve>** lastPtr); 299 int intersects(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp, 300 SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult); 301 bool isParallel(const SkDLine& thisLine, const SkTSect<OppCurve, TCurve>* opp) const; 302 int linesIntersect(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp, 303 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* ); 304 bool markSpanGone(SkTSpan<TCurve, OppCurve>* span); 305 bool matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2) const; 306 void matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2, 307 bool* calcMatched, bool* oppMatched) const; 308 void mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2); 309 SkTSpan<TCurve, OppCurve>* prev(SkTSpan<TCurve, OppCurve>* ) const; 310 void removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp); 311 void recoverCollapsed(); 312 void removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween); 313 void removeAllBut(const SkTSpan<OppCurve, TCurve>* keep, SkTSpan<TCurve, OppCurve>* span, 314 SkTSect<OppCurve, TCurve>* opp); 315 bool removeSpan(SkTSpan<TCurve, OppCurve>* span); 316 void removeSpanRange(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last); 317 void removeSpans(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); 318 void removedEndCheck(SkTSpan<TCurve, OppCurve>* span); 319 320 void resetRemovedEnds() { 321 fRemovedStartT = fRemovedEndT = false; 322 } 323 324 SkTSpan<TCurve, OppCurve>* spanAtT(double t, SkTSpan<TCurve, OppCurve>** priorSpan); 325 SkTSpan<TCurve, OppCurve>* tail(); 326 bool trim(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); 327 void unlinkSpan(SkTSpan<TCurve, OppCurve>* span); 328 bool updateBounded(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last, 329 SkTSpan<OppCurve, TCurve>* oppFirst); 330 void validate() const; 331 void validateBounded() const; 332 333 const TCurve& fCurve; 334 SkArenaAlloc fHeap; 335 SkTSpan<TCurve, OppCurve>* fHead; 336 SkTSpan<TCurve, OppCurve>* fCoincident; 337 SkTSpan<TCurve, OppCurve>* fDeleted; 338 int fActiveCount; 339 bool fRemovedStartT; 340 bool fRemovedEndT; 341 SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); 342 SkDEBUGCODE(SkTSect<OppCurve, TCurve>* fOppSect); 343 PATH_OPS_DEBUG_T_SECT_CODE(int fID); 344 PATH_OPS_DEBUG_T_SECT_CODE(int fDebugCount); 345 #if DEBUG_T_SECT 346 int fDebugAllocatedCount; 347 #endif 348 friend class SkTSpan<TCurve, OppCurve>; 349 friend class SkTSpan<OppCurve, TCurve>; 350 friend class SkTSect<OppCurve, TCurve>; 351 }; 352 353 #define COINCIDENT_SPAN_COUNT 9 354 355 template<typename TCurve, typename OppCurve> 356 void SkTCoincident<TCurve, OppCurve>::setPerp(const TCurve& c1, double t, 357 const SkDPoint& cPt, const OppCurve& c2) { 358 SkDVector dxdy = c1.dxdyAtT(t); 359 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; 360 SkIntersections i SkDEBUGCODE((c1.globalState())); 361 int used = i.intersectRay(c2, perp); 362 // only keep closest 363 if (used == 0 || used == 3) { 364 this->init(); 365 return; 366 } 367 fPerpT = i[0][0]; 368 fPerpPt = i.pt(0); 369 SkASSERT(used <= 2); 370 if (used == 2) { 371 double distSq = (fPerpPt - cPt).lengthSquared(); 372 double dist2Sq = (i.pt(1) - cPt).lengthSquared(); 373 if (dist2Sq < distSq) { 374 fPerpT = i[0][1]; 375 fPerpPt = i.pt(1); 376 } 377 } 378 #if DEBUG_T_SECT 379 SkDebugf("setPerp t=%1.9g cPt=(%1.9g,%1.9g) %s oppT=%1.9g fPerpPt=(%1.9g,%1.9g)\n", 380 t, cPt.fX, cPt.fY, 381 cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpT, fPerpPt.fX, fPerpPt.fY); 382 #endif 383 fMatch = cPt.approximatelyEqual(fPerpPt); 384 #if DEBUG_T_SECT 385 if (fMatch) { 386 SkDebugf(""); // allow setting breakpoint 387 } 388 #endif 389 } 390 391 template<typename TCurve, typename OppCurve> 392 void SkTSpan<TCurve, OppCurve>::addBounded(SkTSpan<OppCurve, TCurve>* span, SkArenaAlloc* heap) { 393 SkTSpanBounded<OppCurve, TCurve>* bounded = heap->make<SkTSpanBounded<OppCurve, TCurve>>(); 394 bounded->fBounded = span; 395 bounded->fNext = fBounded; 396 fBounded = bounded; 397 } 398 399 template<typename TCurve, typename OppCurve> 400 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addFollowing( 401 SkTSpan<TCurve, OppCurve>* prior) { 402 SkTSpan<TCurve, OppCurve>* result = this->addOne(); 403 SkDEBUGCODE(result->debugSetGlobalState(this->globalState())); 404 result->fStartT = prior ? prior->fEndT : 0; 405 SkTSpan<TCurve, OppCurve>* next = prior ? prior->fNext : fHead; 406 result->fEndT = next ? next->fStartT : 1; 407 result->fPrev = prior; 408 result->fNext = next; 409 if (prior) { 410 prior->fNext = result; 411 } else { 412 fHead = result; 413 } 414 if (next) { 415 next->fPrev = result; 416 } 417 result->resetBounds(fCurve); 418 result->validate(); 419 return result; 420 } 421 422 template<typename TCurve, typename OppCurve> 423 void SkTSect<TCurve, OppCurve>::addForPerp(SkTSpan<OppCurve, TCurve>* span, double t) { 424 if (!span->hasOppT(t)) { 425 SkTSpan<TCurve, OppCurve>* priorSpan; 426 SkTSpan<TCurve, OppCurve>* opp = this->spanAtT(t, &priorSpan); 427 if (!opp) { 428 opp = this->addFollowing(priorSpan); 429 #if DEBUG_PERP 430 SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan ? 431 priorSpan->debugID() : -1, t, opp->debugID()); 432 #endif 433 } 434 #if DEBUG_PERP 435 opp->dump(); SkDebugf("\n"); 436 SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan ? 437 priorSpan->debugID() : -1, opp->debugID()); 438 #endif 439 opp->addBounded(span, &fHeap); 440 span->addBounded(opp, &fHeap); 441 } 442 this->validate(); 443 #if DEBUG_T_SECT 444 span->validatePerpT(t); 445 #endif 446 } 447 448 template<typename TCurve, typename OppCurve> 449 double SkTSpan<TCurve, OppCurve>::closestBoundedT(const SkDPoint& pt) const { 450 double result = -1; 451 double closest = DBL_MAX; 452 const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; 453 while (testBounded) { 454 const SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded; 455 double startDist = test->fPart[0].distanceSquared(pt); 456 if (closest > startDist) { 457 closest = startDist; 458 result = test->fStartT; 459 } 460 double endDist = test->fPart[OppCurve::kPointLast].distanceSquared(pt); 461 if (closest > endDist) { 462 closest = endDist; 463 result = test->fEndT; 464 } 465 testBounded = testBounded->fNext; 466 } 467 SkASSERT(between(0, result, 1)); 468 return result; 469 } 470 471 #ifdef SK_DEBUG 472 template<typename TCurve, typename OppCurve> 473 bool SkTSpan<TCurve, OppCurve>::debugIsBefore(const SkTSpan* span) const { 474 const SkTSpan* work = this; 475 do { 476 if (span == work) { 477 return true; 478 } 479 } while ((work = work->fNext)); 480 return false; 481 } 482 #endif 483 484 template<typename TCurve, typename OppCurve> 485 bool SkTSpan<TCurve, OppCurve>::contains(double t) const { 486 const SkTSpan* work = this; 487 do { 488 if (between(work->fStartT, t, work->fEndT)) { 489 return true; 490 } 491 } while ((work = work->fNext)); 492 return false; 493 } 494 495 template<typename TCurve, typename OppCurve> 496 const SkTSect<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::debugOpp() const { 497 return SkDEBUGRELEASE(fDebugSect->debugOpp(), nullptr); 498 } 499 500 template<typename TCurve, typename OppCurve> 501 SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::findOppSpan( 502 const SkTSpan<OppCurve, TCurve>* opp) const { 503 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 504 while (bounded) { 505 SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; 506 if (opp == test) { 507 return test; 508 } 509 bounded = bounded->fNext; 510 } 511 return nullptr; 512 } 513 514 // returns 0 if no hull intersection 515 // 1 if hulls intersect 516 // 2 if hulls only share a common endpoint 517 // -1 if linear and further checking is required 518 template<typename TCurve, typename OppCurve> 519 int SkTSpan<TCurve, OppCurve>::hullCheck(const SkTSpan<OppCurve, TCurve>* opp, 520 bool* start, bool* oppStart) { 521 if (fIsLinear) { 522 return -1; 523 } 524 bool ptsInCommon; 525 if (onlyEndPointsInCommon(opp, start, oppStart, &ptsInCommon)) { 526 SkASSERT(ptsInCommon); 527 return 2; 528 } 529 bool linear; 530 if (fPart.hullIntersects(opp->fPart, &linear)) { 531 if (!linear) { // check set true if linear 532 return 1; 533 } 534 fIsLinear = true; 535 fIsLine = fPart.controlsInside(); 536 return ptsInCommon ? 1 : -1; 537 } else { // hull is not linear; check set true if intersected at the end points 538 return ((int) ptsInCommon) << 1; // 0 or 2 539 } 540 return 0; 541 } 542 543 // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear, 544 // use line intersection to guess a better split than 0.5 545 // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all future splits are linear 546 template<typename TCurve, typename OppCurve> 547 int SkTSpan<TCurve, OppCurve>::hullsIntersect(SkTSpan<OppCurve, TCurve>* opp, 548 bool* start, bool* oppStart) { 549 if (!fBounds.intersects(opp->fBounds)) { 550 return 0; 551 } 552 int hullSect = this->hullCheck(opp, start, oppStart); 553 if (hullSect >= 0) { 554 return hullSect; 555 } 556 hullSect = opp->hullCheck(this, oppStart, start); 557 if (hullSect >= 0) { 558 return hullSect; 559 } 560 return -1; 561 } 562 563 template<typename TCurve, typename OppCurve> 564 void SkTSpan<TCurve, OppCurve>::init(const TCurve& c) { 565 fPrev = fNext = nullptr; 566 fStartT = 0; 567 fEndT = 1; 568 fBounded = nullptr; 569 resetBounds(c); 570 } 571 572 template<typename TCurve, typename OppCurve> 573 bool SkTSpan<TCurve, OppCurve>::initBounds(const TCurve& c) { 574 fPart = c.subDivide(fStartT, fEndT); 575 fBounds.setBounds(fPart); 576 fCoinStart.init(); 577 fCoinEnd.init(); 578 fBoundsMax = SkTMax(fBounds.width(), fBounds.height()); 579 fCollapsed = fPart.collapsed(); 580 fHasPerp = false; 581 fDeleted = false; 582 #if DEBUG_T_SECT 583 if (fCollapsed) { 584 SkDebugf(""); // for convenient breakpoints 585 } 586 #endif 587 return fBounds.valid(); 588 } 589 590 template<typename TCurve, typename OppCurve> 591 bool SkTSpan<TCurve, OppCurve>::linearsIntersect(SkTSpan<OppCurve, TCurve>* span) { 592 int result = this->linearIntersects(span->fPart); 593 if (result <= 1) { 594 return SkToBool(result); 595 } 596 SkASSERT(span->fIsLinear); 597 result = span->linearIntersects(this->fPart); 598 // SkASSERT(result <= 1); 599 return SkToBool(result); 600 } 601 602 template<typename TCurve, typename OppCurve> 603 double SkTSpan<TCurve, OppCurve>::linearT(const SkDPoint& pt) const { 604 SkDVector len = fPart[TCurve::kPointLast] - fPart[0]; 605 return fabs(len.fX) > fabs(len.fY) 606 ? (pt.fX - fPart[0].fX) / len.fX 607 : (pt.fY - fPart[0].fY) / len.fY; 608 } 609 610 template<typename TCurve, typename OppCurve> 611 int SkTSpan<TCurve, OppCurve>::linearIntersects(const OppCurve& q2) const { 612 // looks like q1 is near-linear 613 int start = 0, end = TCurve::kPointLast; // the outside points are usually the extremes 614 if (!fPart.controlsInside()) { 615 double dist = 0; // if there's any question, compute distance to find best outsiders 616 for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) { 617 for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) { 618 double test = (fPart[outer] - fPart[inner]).lengthSquared(); 619 if (dist > test) { 620 continue; 621 } 622 dist = test; 623 start = outer; 624 end = inner; 625 } 626 } 627 } 628 // see if q2 is on one side of the line formed by the extreme points 629 double origX = fPart[start].fX; 630 double origY = fPart[start].fY; 631 double adj = fPart[end].fX - origX; 632 double opp = fPart[end].fY - origY; 633 double maxPart = SkTMax(fabs(adj), fabs(opp)); 634 double sign = 0; // initialization to shut up warning in release build 635 for (int n = 0; n < OppCurve::kPointCount; ++n) { 636 double dx = q2[n].fY - origY; 637 double dy = q2[n].fX - origX; 638 double maxVal = SkTMax(maxPart, SkTMax(fabs(dx), fabs(dy))); 639 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; 640 if (precisely_zero_when_compared_to(test, maxVal)) { 641 return 1; 642 } 643 if (approximately_zero_when_compared_to(test, maxVal)) { 644 return 3; 645 } 646 if (n == 0) { 647 sign = test; 648 continue; 649 } 650 if (test * sign < 0) { 651 return 1; 652 } 653 } 654 return 0; 655 } 656 657 template<typename TCurve, typename OppCurve> 658 bool SkTSpan<TCurve, OppCurve>::onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, 659 bool* start, bool* oppStart, bool* ptsInCommon) { 660 if (opp->fPart[0] == fPart[0]) { 661 *start = *oppStart = true; 662 } else if (opp->fPart[0] == fPart[TCurve::kPointLast]) { 663 *start = false; 664 *oppStart = true; 665 } else if (opp->fPart[OppCurve::kPointLast] == fPart[0]) { 666 *start = true; 667 *oppStart = false; 668 } else if (opp->fPart[OppCurve::kPointLast] == fPart[TCurve::kPointLast]) { 669 *start = *oppStart = false; 670 } else { 671 *ptsInCommon = false; 672 return false; 673 } 674 *ptsInCommon = true; 675 const SkDPoint* otherPts[TCurve::kPointCount - 1], * oppOtherPts[OppCurve::kPointCount - 1]; 676 int baseIndex = *start ? 0 : TCurve::kPointLast; 677 fPart.otherPts(baseIndex, otherPts); 678 opp->fPart.otherPts(*oppStart ? 0 : OppCurve::kPointLast, oppOtherPts); 679 const SkDPoint& base = fPart[baseIndex]; 680 for (int o1 = 0; o1 < (int) SK_ARRAY_COUNT(otherPts); ++o1) { 681 SkDVector v1 = *otherPts[o1] - base; 682 for (int o2 = 0; o2 < (int) SK_ARRAY_COUNT(oppOtherPts); ++o2) { 683 SkDVector v2 = *oppOtherPts[o2] - base; 684 if (v2.dot(v1) >= 0) { 685 return false; 686 } 687 } 688 } 689 return true; 690 } 691 692 template<typename TCurve, typename OppCurve> 693 SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::oppT(double t) const { 694 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 695 while (bounded) { 696 SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; 697 if (between(test->fStartT, t, test->fEndT)) { 698 return test; 699 } 700 bounded = bounded->fNext; 701 } 702 return nullptr; 703 } 704 705 template<typename TCurve, typename OppCurve> 706 bool SkTSpan<TCurve, OppCurve>::removeAllBounded() { 707 bool deleteSpan = false; 708 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 709 while (bounded) { 710 SkTSpan<OppCurve, TCurve>* opp = bounded->fBounded; 711 deleteSpan |= opp->removeBounded(this); 712 bounded = bounded->fNext; 713 } 714 return deleteSpan; 715 } 716 717 template<typename TCurve, typename OppCurve> 718 bool SkTSpan<TCurve, OppCurve>::removeBounded(const SkTSpan<OppCurve, TCurve>* opp) { 719 if (fHasPerp) { 720 bool foundStart = false; 721 bool foundEnd = false; 722 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 723 while (bounded) { 724 SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; 725 if (opp != test) { 726 foundStart |= between(test->fStartT, fCoinStart.perpT(), test->fEndT); 727 foundEnd |= between(test->fStartT, fCoinEnd.perpT(), test->fEndT); 728 } 729 bounded = bounded->fNext; 730 } 731 if (!foundStart || !foundEnd) { 732 fHasPerp = false; 733 fCoinStart.init(); 734 fCoinEnd.init(); 735 } 736 } 737 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 738 SkTSpanBounded<OppCurve, TCurve>* prev = nullptr; 739 while (bounded) { 740 SkTSpanBounded<OppCurve, TCurve>* boundedNext = bounded->fNext; 741 if (opp == bounded->fBounded) { 742 if (prev) { 743 prev->fNext = boundedNext; 744 return false; 745 } else { 746 fBounded = boundedNext; 747 return fBounded == nullptr; 748 } 749 } 750 prev = bounded; 751 bounded = boundedNext; 752 } 753 SkOPASSERT(0); 754 return false; 755 } 756 757 template<typename TCurve, typename OppCurve> 758 bool SkTSpan<TCurve, OppCurve>::splitAt(SkTSpan* work, double t, SkArenaAlloc* heap) { 759 fStartT = t; 760 fEndT = work->fEndT; 761 if (fStartT == fEndT) { 762 fCollapsed = true; 763 return false; 764 } 765 work->fEndT = t; 766 if (work->fStartT == work->fEndT) { 767 work->fCollapsed = true; 768 return false; 769 } 770 fPrev = work; 771 fNext = work->fNext; 772 fIsLinear = work->fIsLinear; 773 fIsLine = work->fIsLine; 774 775 work->fNext = this; 776 if (fNext) { 777 fNext->fPrev = this; 778 } 779 this->validate(); 780 SkTSpanBounded<OppCurve, TCurve>* bounded = work->fBounded; 781 fBounded = nullptr; 782 while (bounded) { 783 this->addBounded(bounded->fBounded, heap); 784 bounded = bounded->fNext; 785 } 786 bounded = fBounded; 787 while (bounded) { 788 bounded->fBounded->addBounded(this, heap); 789 bounded = bounded->fNext; 790 } 791 return true; 792 } 793 794 template<typename TCurve, typename OppCurve> 795 void SkTSpan<TCurve, OppCurve>::validate() const { 796 #if DEBUG_VALIDATE 797 SkASSERT(this != fPrev); 798 SkASSERT(this != fNext); 799 SkASSERT(fNext == nullptr || fNext != fPrev); 800 SkASSERT(fNext == nullptr || this == fNext->fPrev); 801 SkASSERT(fPrev == nullptr || this == fPrev->fNext); 802 this->validateBounded(); 803 #endif 804 #if DEBUG_T_SECT 805 SkASSERT(fBounds.width() || fBounds.height() || fCollapsed); 806 SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height()) || fCollapsed == 0xFF); 807 SkASSERT(0 <= fStartT); 808 SkASSERT(fEndT <= 1); 809 SkASSERT(fStartT <= fEndT); 810 SkASSERT(fBounded || fCollapsed == 0xFF); 811 if (fHasPerp) { 812 if (fCoinStart.isMatch()) { 813 validatePerpT(fCoinStart.perpT()); 814 validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt()); 815 } 816 if (fCoinEnd.isMatch()) { 817 validatePerpT(fCoinEnd.perpT()); 818 validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt()); 819 } 820 } 821 #endif 822 } 823 824 template<typename TCurve, typename OppCurve> 825 void SkTSpan<TCurve, OppCurve>::validateBounded() const { 826 #if DEBUG_VALIDATE 827 const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; 828 while (testBounded) { 829 SkDEBUGCODE(const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded); 830 SkASSERT(!overlap->fDeleted); 831 #if DEBUG_T_SECT 832 SkASSERT(((this->debugID() ^ overlap->debugID()) & 1) == 1); 833 SkASSERT(overlap->findOppSpan(this)); 834 #endif 835 testBounded = testBounded->fNext; 836 } 837 #endif 838 } 839 840 template<typename TCurve, typename OppCurve> 841 void SkTSpan<TCurve, OppCurve>::validatePerpT(double oppT) const { 842 const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; 843 while (testBounded) { 844 const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded; 845 if (precisely_between(overlap->fStartT, oppT, overlap->fEndT)) { 846 return; 847 } 848 testBounded = testBounded->fNext; 849 } 850 SkASSERT(0); 851 } 852 853 template<typename TCurve, typename OppCurve> 854 void SkTSpan<TCurve, OppCurve>::validatePerpPt(double t, const SkDPoint& pt) const { 855 SkASSERT(fDebugSect->fOppSect->fCurve.ptAtT(t) == pt); 856 } 857 858 859 template<typename TCurve, typename OppCurve> 860 SkTSect<TCurve, OppCurve>::SkTSect(const TCurve& c 861 SkDEBUGPARAMS(SkOpGlobalState* debugGlobalState) 862 PATH_OPS_DEBUG_T_SECT_PARAMS(int id)) 863 : fCurve(c) 864 , fHeap(sizeof(SkTSpan<TCurve, OppCurve>) * 4) 865 , fCoincident(nullptr) 866 , fDeleted(nullptr) 867 , fActiveCount(0) 868 SkDEBUGPARAMS(fDebugGlobalState(debugGlobalState)) 869 PATH_OPS_DEBUG_T_SECT_PARAMS(fID(id)) 870 PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0)) 871 PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0)) 872 { 873 this->resetRemovedEnds(); 874 fHead = this->addOne(); 875 SkDEBUGCODE(fHead->debugSetGlobalState(debugGlobalState)); 876 fHead->init(c); 877 } 878 879 template<typename TCurve, typename OppCurve> 880 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addOne() { 881 SkTSpan<TCurve, OppCurve>* result; 882 if (fDeleted) { 883 result = fDeleted; 884 fDeleted = result->fNext; 885 } else { 886 result = fHeap.make<SkTSpan<TCurve, OppCurve>>(); 887 #if DEBUG_T_SECT 888 ++fDebugAllocatedCount; 889 #endif 890 } 891 result->reset(); 892 result->fHasPerp = false; 893 result->fDeleted = false; 894 ++fActiveCount; 895 PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID); 896 SkDEBUGCODE(result->fDebugSect = this); 897 #ifdef SK_DEBUG 898 result->fPart.debugInit(); 899 result->fCoinStart.debugInit(); 900 result->fCoinEnd.debugInit(); 901 result->fPrev = result->fNext = nullptr; 902 result->fBounds.debugInit(); 903 result->fStartT = result->fEndT = result->fBoundsMax = SK_ScalarNaN; 904 result->fCollapsed = result->fIsLinear = result->fIsLine = 0xFF; 905 #endif 906 return result; 907 } 908 909 template<typename TCurve, typename OppCurve> 910 bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect2, double tStart, 911 double tStep, double* resultT, double* oppT) { 912 SkTSpan<TCurve, OppCurve> work; 913 double result = work.fStartT = work.fEndT = tStart; 914 SkDEBUGCODE(work.fDebugSect = this); 915 SkDPoint last = fCurve.ptAtT(tStart); 916 SkDPoint oppPt; 917 bool flip = false; 918 bool contained = false; 919 SkDEBUGCODE(bool down = tStep < 0); 920 const OppCurve& opp = sect2->fCurve; 921 do { 922 tStep *= 0.5; 923 work.fStartT += tStep; 924 if (flip) { 925 tStep = -tStep; 926 flip = false; 927 } 928 work.initBounds(fCurve); 929 if (work.fCollapsed) { 930 return false; 931 } 932 if (last.approximatelyEqual(work.fPart[0])) { 933 break; 934 } 935 last = work.fPart[0]; 936 work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp); 937 if (work.fCoinStart.isMatch()) { 938 #if DEBUG_T_SECT 939 work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt()); 940 #endif 941 double oppTTest = work.fCoinStart.perpT(); 942 if (sect2->fHead->contains(oppTTest)) { 943 *oppT = oppTTest; 944 oppPt = work.fCoinStart.perpPt(); 945 contained = true; 946 SkASSERT(down ? result > work.fStartT : result < work.fStartT); 947 result = work.fStartT; 948 continue; 949 } 950 } 951 tStep = -tStep; 952 flip = true; 953 } while (true); 954 if (!contained) { 955 return false; 956 } 957 if (last.approximatelyEqual(fCurve[0])) { 958 result = 0; 959 } else if (last.approximatelyEqual(fCurve[TCurve::kPointLast])) { 960 result = 1; 961 } 962 if (oppPt.approximatelyEqual(opp[0])) { 963 *oppT = 0; 964 } else if (oppPt.approximatelyEqual(opp[OppCurve::kPointLast])) { 965 *oppT = 1; 966 } 967 *resultT = result; 968 return true; 969 } 970 971 // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in quad span 972 // so that each quad sect has a pointer to the largest, and can update it as spans 973 // are split 974 template<typename TCurve, typename OppCurve> 975 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::boundsMax() const { 976 SkTSpan<TCurve, OppCurve>* test = fHead; 977 SkTSpan<TCurve, OppCurve>* largest = fHead; 978 bool lCollapsed = largest->fCollapsed; 979 while ((test = test->fNext)) { 980 bool tCollapsed = test->fCollapsed; 981 if ((lCollapsed && !tCollapsed) || (lCollapsed == tCollapsed && 982 largest->fBoundsMax < test->fBoundsMax)) { 983 largest = test; 984 lCollapsed = test->fCollapsed; 985 } 986 } 987 return largest; 988 } 989 990 template<typename TCurve, typename OppCurve> 991 bool SkTSect<TCurve, OppCurve>::coincidentCheck(SkTSect<OppCurve, TCurve>* sect2) { 992 SkTSpan<TCurve, OppCurve>* first = fHead; 993 if (!first) { 994 return false; 995 } 996 SkTSpan<TCurve, OppCurve>* last, * next; 997 do { 998 int consecutive = this->countConsecutiveSpans(first, &last); 999 next = last->fNext; 1000 if (consecutive < COINCIDENT_SPAN_COUNT) { 1001 continue; 1002 } 1003 this->validate(); 1004 sect2->validate(); 1005 this->computePerpendiculars(sect2, first, last); 1006 this->validate(); 1007 sect2->validate(); 1008 // check to see if a range of points are on the curve 1009 SkTSpan<TCurve, OppCurve>* coinStart = first; 1010 do { 1011 bool success = this->extractCoincident(sect2, coinStart, last, &coinStart); 1012 if (!success) { 1013 return false; 1014 } 1015 } while (coinStart && !last->fDeleted); 1016 if (!fHead || !sect2->fHead) { 1017 break; 1018 } 1019 if (!next || next->fDeleted) { 1020 break; 1021 } 1022 } while ((first = next)); 1023 return true; 1024 } 1025 1026 template<typename TCurve, typename OppCurve> 1027 void SkTSect<TCurve, OppCurve>::coincidentForce(SkTSect<OppCurve, TCurve>* sect2, 1028 double start1s, double start1e) { 1029 SkTSpan<TCurve, OppCurve>* first = fHead; 1030 SkTSpan<TCurve, OppCurve>* last = this->tail(); 1031 SkTSpan<OppCurve, TCurve>* oppFirst = sect2->fHead; 1032 SkTSpan<OppCurve, TCurve>* oppLast = sect2->tail(); 1033 bool deleteEmptySpans = this->updateBounded(first, last, oppFirst); 1034 deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first); 1035 this->removeSpanRange(first, last); 1036 sect2->removeSpanRange(oppFirst, oppLast); 1037 first->fStartT = start1s; 1038 first->fEndT = start1e; 1039 first->resetBounds(fCurve); 1040 first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve); 1041 first->fCoinEnd.setPerp(fCurve, start1e, fCurve[TCurve::kPointLast], sect2->fCurve); 1042 bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT(); 1043 double oppStartT = first->fCoinStart.perpT() == -1 ? 0 : SkTMax(0., first->fCoinStart.perpT()); 1044 double oppEndT = first->fCoinEnd.perpT() == -1 ? 1 : SkTMin(1., first->fCoinEnd.perpT()); 1045 if (!oppMatched) { 1046 SkTSwap(oppStartT, oppEndT); 1047 } 1048 oppFirst->fStartT = oppStartT; 1049 oppFirst->fEndT = oppEndT; 1050 oppFirst->resetBounds(sect2->fCurve); 1051 this->removeCoincident(first, false); 1052 sect2->removeCoincident(oppFirst, true); 1053 if (deleteEmptySpans) { 1054 this->deleteEmptySpans(); 1055 sect2->deleteEmptySpans(); 1056 } 1057 } 1058 1059 template<typename TCurve, typename OppCurve> 1060 bool SkTSect<TCurve, OppCurve>::coincidentHasT(double t) { 1061 SkTSpan<TCurve, OppCurve>* test = fCoincident; 1062 while (test) { 1063 if (between(test->fStartT, t, test->fEndT)) { 1064 return true; 1065 } 1066 test = test->fNext; 1067 } 1068 return false; 1069 } 1070 1071 template<typename TCurve, typename OppCurve> 1072 int SkTSect<TCurve, OppCurve>::collapsed() const { 1073 int result = 0; 1074 const SkTSpan<TCurve, OppCurve>* test = fHead; 1075 while (test) { 1076 if (test->fCollapsed) { 1077 ++result; 1078 } 1079 test = test->next(); 1080 } 1081 return result; 1082 } 1083 1084 template<typename TCurve, typename OppCurve> 1085 void SkTSect<TCurve, OppCurve>::computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, 1086 SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last) { 1087 const OppCurve& opp = sect2->fCurve; 1088 SkTSpan<TCurve, OppCurve>* work = first; 1089 SkTSpan<TCurve, OppCurve>* prior = nullptr; 1090 do { 1091 if (!work->fHasPerp && !work->fCollapsed) { 1092 if (prior) { 1093 work->fCoinStart = prior->fCoinEnd; 1094 } else { 1095 work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp); 1096 } 1097 if (work->fCoinStart.isMatch()) { 1098 double perpT = work->fCoinStart.perpT(); 1099 if (sect2->coincidentHasT(perpT)) { 1100 work->fCoinStart.init(); 1101 } else { 1102 sect2->addForPerp(work, perpT); 1103 } 1104 } 1105 work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPointLast], opp); 1106 if (work->fCoinEnd.isMatch()) { 1107 double perpT = work->fCoinEnd.perpT(); 1108 if (sect2->coincidentHasT(perpT)) { 1109 work->fCoinEnd.init(); 1110 } else { 1111 sect2->addForPerp(work, perpT); 1112 } 1113 } 1114 work->fHasPerp = true; 1115 } 1116 if (work == last) { 1117 break; 1118 } 1119 prior = work; 1120 work = work->fNext; 1121 SkASSERT(work); 1122 } while (true); 1123 } 1124 1125 template<typename TCurve, typename OppCurve> 1126 int SkTSect<TCurve, OppCurve>::countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first, 1127 SkTSpan<TCurve, OppCurve>** lastPtr) const { 1128 int consecutive = 1; 1129 SkTSpan<TCurve, OppCurve>* last = first; 1130 do { 1131 SkTSpan<TCurve, OppCurve>* next = last->fNext; 1132 if (!next) { 1133 break; 1134 } 1135 if (next->fStartT > last->fEndT) { 1136 break; 1137 } 1138 ++consecutive; 1139 last = next; 1140 } while (true); 1141 *lastPtr = last; 1142 return consecutive; 1143 } 1144 1145 template<typename TCurve, typename OppCurve> 1146 bool SkTSect<TCurve, OppCurve>::debugHasBounded(const SkTSpan<OppCurve, TCurve>* span) const { 1147 const SkTSpan<TCurve, OppCurve>* test = fHead; 1148 if (!test) { 1149 return false; 1150 } 1151 do { 1152 if (test->findOppSpan(span)) { 1153 return true; 1154 } 1155 } while ((test = test->next())); 1156 return false; 1157 } 1158 1159 template<typename TCurve, typename OppCurve> 1160 bool SkTSect<TCurve, OppCurve>::deleteEmptySpans() { 1161 SkTSpan<TCurve, OppCurve>* test; 1162 SkTSpan<TCurve, OppCurve>* next = fHead; 1163 int safetyHatch = 1000; 1164 while ((test = next)) { 1165 next = test->fNext; 1166 if (!test->fBounded) { 1167 if (!this->removeSpan(test)) { 1168 return false; 1169 } 1170 } 1171 if (--safetyHatch < 0) { 1172 return false; 1173 } 1174 } 1175 return true; 1176 } 1177 1178 template<typename TCurve, typename OppCurve> 1179 bool SkTSect<TCurve, OppCurve>::extractCoincident( 1180 SkTSect<OppCurve, TCurve>* sect2, 1181 SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last, 1182 SkTSpan<TCurve, OppCurve>** result) { 1183 first = findCoincidentRun(first, &last); 1184 if (!first || !last) { 1185 *result = nullptr; 1186 return true; 1187 } 1188 // march outwards to find limit of coincidence from here to previous and next spans 1189 double startT = first->fStartT; 1190 double oppStartT SK_INIT_TO_AVOID_WARNING; 1191 double oppEndT SK_INIT_TO_AVOID_WARNING; 1192 SkTSpan<TCurve, OppCurve>* prev = first->fPrev; 1193 SkASSERT(first->fCoinStart.isMatch()); 1194 SkTSpan<OppCurve, TCurve>* oppFirst = first->findOppT(first->fCoinStart.perpT()); 1195 SkOPASSERT(last->fCoinEnd.isMatch()); 1196 bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT(); 1197 double coinStart; 1198 SkDEBUGCODE(double coinEnd); 1199 SkTSpan<OppCurve, TCurve>* cutFirst; 1200 if (prev && prev->fEndT == startT 1201 && this->binarySearchCoin(sect2, startT, prev->fStartT - startT, &coinStart, 1202 &oppStartT) 1203 && prev->fStartT < coinStart && coinStart < startT 1204 && (cutFirst = prev->oppT(oppStartT))) { 1205 oppFirst = cutFirst; 1206 first = this->addSplitAt(prev, coinStart); 1207 first->markCoincident(); 1208 prev->fCoinEnd.markCoincident(); 1209 if (oppFirst->fStartT < oppStartT && oppStartT < oppFirst->fEndT) { 1210 SkTSpan<OppCurve, TCurve>* oppHalf = sect2->addSplitAt(oppFirst, oppStartT); 1211 if (oppMatched) { 1212 oppFirst->fCoinEnd.markCoincident(); 1213 oppHalf->markCoincident(); 1214 oppFirst = oppHalf; 1215 } else { 1216 oppFirst->markCoincident(); 1217 oppHalf->fCoinStart.markCoincident(); 1218 } 1219 } 1220 } else { 1221 SkDEBUGCODE(coinStart = first->fStartT); 1222 FAIL_IF(!oppFirst); 1223 SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT); 1224 } 1225 // FIXME: incomplete : if we're not at the end, find end of coin 1226 SkTSpan<OppCurve, TCurve>* oppLast; 1227 SkOPASSERT(last->fCoinEnd.isMatch()); 1228 oppLast = last->findOppT(last->fCoinEnd.perpT()); 1229 SkDEBUGCODE(coinEnd = last->fEndT); 1230 #ifdef SK_DEBUG 1231 if (!this->globalState() || !this->globalState()->debugSkipAssert()) { 1232 oppEndT = oppMatched ? oppLast->fEndT : oppLast->fStartT; 1233 } 1234 #endif 1235 if (!oppMatched) { 1236 SkTSwap(oppFirst, oppLast); 1237 SkTSwap(oppStartT, oppEndT); 1238 } 1239 SkOPASSERT(oppStartT < oppEndT); 1240 SkASSERT(coinStart == first->fStartT); 1241 SkASSERT(coinEnd == last->fEndT); 1242 SkOPASSERT(oppStartT == oppFirst->fStartT); 1243 SkOPASSERT(oppEndT == oppLast->fEndT); 1244 if (!oppFirst) { 1245 *result = nullptr; 1246 return true; 1247 } 1248 if (!oppLast) { 1249 *result = nullptr; 1250 return true; 1251 } 1252 // reduce coincident runs to single entries 1253 this->validate(); 1254 sect2->validate(); 1255 bool deleteEmptySpans = this->updateBounded(first, last, oppFirst); 1256 deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first); 1257 this->removeSpanRange(first, last); 1258 sect2->removeSpanRange(oppFirst, oppLast); 1259 first->fEndT = last->fEndT; 1260 first->resetBounds(this->fCurve); 1261 first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], sect2->fCurve); 1262 first->fCoinEnd.setPerp(fCurve, first->fEndT, first->fPart[TCurve::kPointLast], sect2->fCurve); 1263 oppStartT = first->fCoinStart.perpT(); 1264 oppEndT = first->fCoinEnd.perpT(); 1265 if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) { 1266 if (!oppMatched) { 1267 SkTSwap(oppStartT, oppEndT); 1268 } 1269 oppFirst->fStartT = oppStartT; 1270 oppFirst->fEndT = oppEndT; 1271 oppFirst->resetBounds(sect2->fCurve); 1272 } 1273 this->validateBounded(); 1274 sect2->validateBounded(); 1275 last = first->fNext; 1276 this->removeCoincident(first, false); 1277 sect2->removeCoincident(oppFirst, true); 1278 if (deleteEmptySpans) { 1279 if (!this->deleteEmptySpans() || !sect2->deleteEmptySpans()) { 1280 *result = nullptr; 1281 return false; 1282 } 1283 } 1284 this->validate(); 1285 sect2->validate(); 1286 *result = last && !last->fDeleted && fHead && sect2->fHead ? last : nullptr; 1287 return true; 1288 } 1289 1290 template<typename TCurve, typename OppCurve> 1291 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::findCoincidentRun( 1292 SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>** lastPtr) { 1293 SkTSpan<TCurve, OppCurve>* work = first; 1294 SkTSpan<TCurve, OppCurve>* lastCandidate = nullptr; 1295 first = nullptr; 1296 // find the first fully coincident span 1297 do { 1298 if (work->fCoinStart.isMatch()) { 1299 #if DEBUG_T_SECT 1300 work->validatePerpT(work->fCoinStart.perpT()); 1301 work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt()); 1302 #endif 1303 SkOPASSERT(work->hasOppT(work->fCoinStart.perpT())); 1304 if (!work->fCoinEnd.isMatch()) { 1305 break; 1306 } 1307 lastCandidate = work; 1308 if (!first) { 1309 first = work; 1310 } 1311 } else if (first && work->fCollapsed) { 1312 *lastPtr = lastCandidate; 1313 return first; 1314 } else { 1315 lastCandidate = nullptr; 1316 SkOPASSERT(!first); 1317 } 1318 if (work == *lastPtr) { 1319 return first; 1320 } 1321 work = work->fNext; 1322 if (!work) { 1323 return nullptr; 1324 } 1325 } while (true); 1326 if (lastCandidate) { 1327 *lastPtr = lastCandidate; 1328 } 1329 return first; 1330 } 1331 1332 template<typename TCurve, typename OppCurve> 1333 int SkTSect<TCurve, OppCurve>::intersects(SkTSpan<TCurve, OppCurve>* span, 1334 SkTSect<OppCurve, TCurve>* opp, 1335 SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult) { 1336 bool spanStart, oppStart; 1337 int hullResult = span->hullsIntersect(oppSpan, &spanStart, &oppStart); 1338 if (hullResult >= 0) { 1339 if (hullResult == 2) { // hulls have one point in common 1340 if (!span->fBounded || !span->fBounded->fNext) { 1341 SkASSERT(!span->fBounded || span->fBounded->fBounded == oppSpan); 1342 if (spanStart) { 1343 span->fEndT = span->fStartT; 1344 } else { 1345 span->fStartT = span->fEndT; 1346 } 1347 } else { 1348 hullResult = 1; 1349 } 1350 if (!oppSpan->fBounded || !oppSpan->fBounded->fNext) { 1351 SkASSERT(!oppSpan->fBounded || oppSpan->fBounded->fBounded == span); 1352 if (oppStart) { 1353 oppSpan->fEndT = oppSpan->fStartT; 1354 } else { 1355 oppSpan->fStartT = oppSpan->fEndT; 1356 } 1357 *oppResult = 2; 1358 } else { 1359 *oppResult = 1; 1360 } 1361 } else { 1362 *oppResult = 1; 1363 } 1364 return hullResult; 1365 } 1366 if (span->fIsLine && oppSpan->fIsLine) { 1367 SkIntersections i; 1368 int sects = this->linesIntersect(span, opp, oppSpan, &i); 1369 if (sects == 2) { 1370 return *oppResult = 1; 1371 } 1372 if (!sects) { 1373 return -1; 1374 } 1375 this->removedEndCheck(span); 1376 span->fStartT = span->fEndT = i[0][0]; 1377 opp->removedEndCheck(oppSpan); 1378 oppSpan->fStartT = oppSpan->fEndT = i[1][0]; 1379 return *oppResult = 2; 1380 } 1381 if (span->fIsLinear || oppSpan->fIsLinear) { 1382 return *oppResult = (int) span->linearsIntersect(oppSpan); 1383 } 1384 return *oppResult = 1; 1385 } 1386 1387 template<typename TCurve> 1388 static bool is_parallel(const SkDLine& thisLine, const TCurve& opp) { 1389 if (!opp.IsConic()) { 1390 return false; // FIXME : breaks a lot of stuff now 1391 } 1392 int finds = 0; 1393 SkDLine thisPerp; 1394 thisPerp.fPts[0].fX = thisLine.fPts[1].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY); 1395 thisPerp.fPts[0].fY = thisLine.fPts[1].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX); 1396 thisPerp.fPts[1] = thisLine.fPts[1]; 1397 SkIntersections perpRayI; 1398 perpRayI.intersectRay(opp, thisPerp); 1399 for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { 1400 finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[1]); 1401 } 1402 thisPerp.fPts[1].fX = thisLine.fPts[0].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY); 1403 thisPerp.fPts[1].fY = thisLine.fPts[0].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX); 1404 thisPerp.fPts[0] = thisLine.fPts[0]; 1405 perpRayI.intersectRay(opp, thisPerp); 1406 for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { 1407 finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[0]); 1408 } 1409 return finds >= 2; 1410 } 1411 1412 // while the intersection points are sufficiently far apart: 1413 // construct the tangent lines from the intersections 1414 // find the point where the tangent line intersects the opposite curve 1415 template<typename TCurve, typename OppCurve> 1416 int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span, 1417 SkTSect<OppCurve, TCurve>* opp, 1418 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) { 1419 SkIntersections thisRayI SkDEBUGCODE((span->fDebugGlobalState)); 1420 SkIntersections oppRayI SkDEBUGCODE((span->fDebugGlobalState)); 1421 SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; 1422 SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast] }}; 1423 int loopCount = 0; 1424 double bestDistSq = DBL_MAX; 1425 if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { 1426 return 0; 1427 } 1428 if (!oppRayI.intersectRay(this->fCurve, oppLine)) { 1429 return 0; 1430 } 1431 // if the ends of each line intersect the opposite curve, the lines are coincident 1432 if (thisRayI.used() > 1) { 1433 int ptMatches = 0; 1434 for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) { 1435 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) { 1436 ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPts[lIndex]); 1437 } 1438 } 1439 if (ptMatches == 2 || is_parallel(thisLine, opp->fCurve)) { 1440 return 2; 1441 } 1442 } 1443 if (oppRayI.used() > 1) { 1444 int ptMatches = 0; 1445 for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) { 1446 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) { 1447 ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[lIndex]); 1448 } 1449 } 1450 if (ptMatches == 2|| is_parallel(oppLine, this->fCurve)) { 1451 return 2; 1452 } 1453 } 1454 do { 1455 // pick the closest pair of points 1456 double closest = DBL_MAX; 1457 int closeIndex SK_INIT_TO_AVOID_WARNING; 1458 int oppCloseIndex SK_INIT_TO_AVOID_WARNING; 1459 for (int index = 0; index < oppRayI.used(); ++index) { 1460 if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT)) { 1461 continue; 1462 } 1463 for (int oIndex = 0; oIndex < thisRayI.used(); ++oIndex) { 1464 if (!roughly_between(oppSpan->fStartT, thisRayI[0][oIndex], oppSpan->fEndT)) { 1465 continue; 1466 } 1467 double distSq = thisRayI.pt(index).distanceSquared(oppRayI.pt(oIndex)); 1468 if (closest > distSq) { 1469 closest = distSq; 1470 closeIndex = index; 1471 oppCloseIndex = oIndex; 1472 } 1473 } 1474 } 1475 if (closest == DBL_MAX) { 1476 break; 1477 } 1478 const SkDPoint& oppIPt = thisRayI.pt(oppCloseIndex); 1479 const SkDPoint& iPt = oppRayI.pt(closeIndex); 1480 if (between(span->fStartT, oppRayI[0][closeIndex], span->fEndT) 1481 && between(oppSpan->fStartT, thisRayI[0][oppCloseIndex], oppSpan->fEndT) 1482 && oppIPt.approximatelyEqual(iPt)) { 1483 i->merge(oppRayI, closeIndex, thisRayI, oppCloseIndex); 1484 return i->used(); 1485 } 1486 double distSq = oppIPt.distanceSquared(iPt); 1487 if (bestDistSq < distSq || ++loopCount > 5) { 1488 return 0; 1489 } 1490 bestDistSq = distSq; 1491 double oppStart = oppRayI[0][closeIndex]; 1492 thisLine[0] = fCurve.ptAtT(oppStart); 1493 thisLine[1] = thisLine[0] + fCurve.dxdyAtT(oppStart); 1494 if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { 1495 break; 1496 } 1497 double start = thisRayI[0][oppCloseIndex]; 1498 oppLine[0] = opp->fCurve.ptAtT(start); 1499 oppLine[1] = oppLine[0] + opp->fCurve.dxdyAtT(start); 1500 if (!oppRayI.intersectRay(this->fCurve, oppLine)) { 1501 break; 1502 } 1503 } while (true); 1504 // convergence may fail if the curves are nearly coincident 1505 SkTCoincident<OppCurve, TCurve> oCoinS, oCoinE; 1506 oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->fPart[0], fCurve); 1507 oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->fPart[OppCurve::kPointLast], fCurve); 1508 double tStart = oCoinS.perpT(); 1509 double tEnd = oCoinE.perpT(); 1510 bool swap = tStart > tEnd; 1511 if (swap) { 1512 SkTSwap(tStart, tEnd); 1513 } 1514 tStart = SkTMax(tStart, span->fStartT); 1515 tEnd = SkTMin(tEnd, span->fEndT); 1516 if (tStart > tEnd) { 1517 return 0; 1518 } 1519 SkDVector perpS, perpE; 1520 if (tStart == span->fStartT) { 1521 SkTCoincident<TCurve, OppCurve> coinS; 1522 coinS.setPerp(fCurve, span->fStartT, span->fPart[0], opp->fCurve); 1523 perpS = span->fPart[0] - coinS.perpPt(); 1524 } else if (swap) { 1525 perpS = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast]; 1526 } else { 1527 perpS = oCoinS.perpPt() - oppSpan->fPart[0]; 1528 } 1529 if (tEnd == span->fEndT) { 1530 SkTCoincident<TCurve, OppCurve> coinE; 1531 coinE.setPerp(fCurve, span->fEndT, span->fPart[TCurve::kPointLast], opp->fCurve); 1532 perpE = span->fPart[TCurve::kPointLast] - coinE.perpPt(); 1533 } else if (swap) { 1534 perpE = oCoinS.perpPt() - oppSpan->fPart[0]; 1535 } else { 1536 perpE = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast]; 1537 } 1538 if (perpS.dot(perpE) >= 0) { 1539 return 0; 1540 } 1541 SkTCoincident<TCurve, OppCurve> coinW; 1542 double workT = tStart; 1543 double tStep = tEnd - tStart; 1544 SkDPoint workPt; 1545 do { 1546 tStep *= 0.5; 1547 if (precisely_zero(tStep)) { 1548 return 0; 1549 } 1550 workT += tStep; 1551 workPt = fCurve.ptAtT(workT); 1552 coinW.setPerp(fCurve, workT, workPt, opp->fCurve); 1553 double perpT = coinW.perpT(); 1554 if (coinW.isMatch() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) { 1555 continue; 1556 } 1557 SkDVector perpW = workPt - coinW.perpPt(); 1558 if ((perpS.dot(perpW) >= 0) == (tStep < 0)) { 1559 tStep = -tStep; 1560 } 1561 if (workPt.approximatelyEqual(coinW.perpPt())) { 1562 break; 1563 } 1564 } while (true); 1565 double oppTTest = coinW.perpT(); 1566 if (!opp->fHead->contains(oppTTest)) { 1567 return 0; 1568 } 1569 i->setMax(1); 1570 i->insert(workT, oppTTest, workPt); 1571 return 1; 1572 } 1573 1574 1575 template<typename TCurve, typename OppCurve> 1576 bool SkTSect<TCurve, OppCurve>::markSpanGone(SkTSpan<TCurve, OppCurve>* span) { 1577 if (--fActiveCount < 0) { 1578 return false; 1579 } 1580 span->fNext = fDeleted; 1581 fDeleted = span; 1582 SkOPASSERT(!span->fDeleted); 1583 span->fDeleted = true; 1584 return true; 1585 } 1586 1587 template<typename TCurve, typename OppCurve> 1588 bool SkTSect<TCurve, OppCurve>::matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, 1589 double t2) const { 1590 SkDVector dxdy = this->fCurve.dxdyAtT(t); 1591 SkDVector dxdy2 = sect2->fCurve.dxdyAtT(t2); 1592 return dxdy.dot(dxdy2) >= 0; 1593 } 1594 1595 template<typename TCurve, typename OppCurve> 1596 void SkTSect<TCurve, OppCurve>::matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, 1597 double t2, bool* calcMatched, bool* oppMatched) const { 1598 if (*calcMatched) { 1599 SkASSERT(*oppMatched == this->matchedDirection(t, sect2, t2)); 1600 } else { 1601 *oppMatched = this->matchedDirection(t, sect2, t2); 1602 *calcMatched = true; 1603 } 1604 } 1605 1606 template<typename TCurve, typename OppCurve> 1607 void SkTSect<TCurve, OppCurve>::mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2) { 1608 double smallLimit = 0; 1609 do { 1610 // find the smallest unprocessed span 1611 SkTSpan<TCurve, OppCurve>* smaller = nullptr; 1612 SkTSpan<TCurve, OppCurve>* test = fCoincident; 1613 do { 1614 if (!test) { 1615 return; 1616 } 1617 if (test->fStartT < smallLimit) { 1618 continue; 1619 } 1620 if (smaller && smaller->fEndT < test->fStartT) { 1621 continue; 1622 } 1623 smaller = test; 1624 } while ((test = test->fNext)); 1625 if (!smaller) { 1626 return; 1627 } 1628 smallLimit = smaller->fEndT; 1629 // find next larger span 1630 SkTSpan<TCurve, OppCurve>* prior = nullptr; 1631 SkTSpan<TCurve, OppCurve>* larger = nullptr; 1632 SkTSpan<TCurve, OppCurve>* largerPrior = nullptr; 1633 test = fCoincident; 1634 do { 1635 if (test->fStartT < smaller->fEndT) { 1636 continue; 1637 } 1638 SkOPASSERT(test->fStartT != smaller->fEndT); 1639 if (larger && larger->fStartT < test->fStartT) { 1640 continue; 1641 } 1642 largerPrior = prior; 1643 larger = test; 1644 } while ((prior = test), (test = test->fNext)); 1645 if (!larger) { 1646 continue; 1647 } 1648 // check middle t value to see if it is coincident as well 1649 double midT = (smaller->fEndT + larger->fStartT) / 2; 1650 SkDPoint midPt = fCurve.ptAtT(midT); 1651 SkTCoincident<TCurve, OppCurve> coin; 1652 coin.setPerp(fCurve, midT, midPt, sect2->fCurve); 1653 if (coin.isMatch()) { 1654 smaller->fEndT = larger->fEndT; 1655 smaller->fCoinEnd = larger->fCoinEnd; 1656 if (largerPrior) { 1657 largerPrior->fNext = larger->fNext; 1658 largerPrior->validate(); 1659 } else { 1660 fCoincident = larger->fNext; 1661 } 1662 } 1663 } while (true); 1664 } 1665 1666 template<typename TCurve, typename OppCurve> 1667 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::prev( 1668 SkTSpan<TCurve, OppCurve>* span) const { 1669 SkTSpan<TCurve, OppCurve>* result = nullptr; 1670 SkTSpan<TCurve, OppCurve>* test = fHead; 1671 while (span != test) { 1672 result = test; 1673 test = test->fNext; 1674 SkASSERT(test); 1675 } 1676 return result; 1677 } 1678 1679 template<typename TCurve, typename OppCurve> 1680 void SkTSect<TCurve, OppCurve>::recoverCollapsed() { 1681 SkTSpan<TCurve, OppCurve>* deleted = fDeleted; 1682 while (deleted) { 1683 SkTSpan<TCurve, OppCurve>* delNext = deleted->fNext; 1684 if (deleted->fCollapsed) { 1685 SkTSpan<TCurve, OppCurve>** spanPtr = &fHead; 1686 while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) { 1687 spanPtr = &(*spanPtr)->fNext; 1688 } 1689 deleted->fNext = *spanPtr; 1690 *spanPtr = deleted; 1691 } 1692 deleted = delNext; 1693 } 1694 } 1695 1696 template<typename TCurve, typename OppCurve> 1697 void SkTSect<TCurve, OppCurve>::removeAllBut(const SkTSpan<OppCurve, TCurve>* keep, 1698 SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp) { 1699 const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded; 1700 while (testBounded) { 1701 SkTSpan<OppCurve, TCurve>* bounded = testBounded->fBounded; 1702 const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext; 1703 // may have been deleted when opp did 'remove all but' 1704 if (bounded != keep && !bounded->fDeleted) { 1705 SkAssertResult(SkDEBUGCODE(!) span->removeBounded(bounded)); 1706 if (bounded->removeBounded(span)) { 1707 opp->removeSpan(bounded); 1708 } 1709 } 1710 testBounded = next; 1711 } 1712 SkASSERT(!span->fDeleted); 1713 SkASSERT(span->findOppSpan(keep)); 1714 SkASSERT(keep->findOppSpan(span)); 1715 } 1716 1717 template<typename TCurve, typename OppCurve> 1718 void SkTSect<TCurve, OppCurve>::removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp) { 1719 SkTSpan<TCurve, OppCurve>* test = fHead; 1720 SkTSpan<TCurve, OppCurve>* next; 1721 do { 1722 next = test->fNext; 1723 if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) { 1724 continue; 1725 } 1726 SkDVector startV = test->fCoinStart.perpPt() - test->fPart[0]; 1727 SkDVector endV = test->fCoinEnd.perpPt() - test->fPart[TCurve::kPointLast]; 1728 #if DEBUG_T_SECT 1729 SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUNCTION__, 1730 startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV)); 1731 #endif 1732 if (startV.dot(endV) <= 0) { 1733 continue; 1734 } 1735 this->removeSpans(test, opp); 1736 } while ((test = next)); 1737 } 1738 1739 template<typename TCurve, typename OppCurve> 1740 void SkTSect<TCurve, OppCurve>::removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween) { 1741 this->unlinkSpan(span); 1742 if (isBetween || between(0, span->fCoinStart.perpT(), 1)) { 1743 --fActiveCount; 1744 span->fNext = fCoincident; 1745 fCoincident = span; 1746 } else { 1747 this->markSpanGone(span); 1748 } 1749 } 1750 1751 template<typename TCurve, typename OppCurve> 1752 void SkTSect<TCurve, OppCurve>::removedEndCheck(SkTSpan<TCurve, OppCurve>* span) { 1753 if (!span->fStartT) { 1754 fRemovedStartT = true; 1755 } 1756 if (1 == span->fEndT) { 1757 fRemovedEndT = true; 1758 } 1759 } 1760 1761 template<typename TCurve, typename OppCurve> 1762 bool SkTSect<TCurve, OppCurve>::removeSpan(SkTSpan<TCurve, OppCurve>* span) {\ 1763 this->removedEndCheck(span); 1764 this->unlinkSpan(span); 1765 return this->markSpanGone(span); 1766 } 1767 1768 template<typename TCurve, typename OppCurve> 1769 void SkTSect<TCurve, OppCurve>::removeSpanRange(SkTSpan<TCurve, OppCurve>* first, 1770 SkTSpan<TCurve, OppCurve>* last) { 1771 if (first == last) { 1772 return; 1773 } 1774 SkTSpan<TCurve, OppCurve>* span = first; 1775 SkASSERT(span); 1776 SkTSpan<TCurve, OppCurve>* final = last->fNext; 1777 SkTSpan<TCurve, OppCurve>* next = span->fNext; 1778 while ((span = next) && span != final) { 1779 next = span->fNext; 1780 this->markSpanGone(span); 1781 } 1782 if (final) { 1783 final->fPrev = first; 1784 } 1785 first->fNext = final; 1786 first->validate(); 1787 } 1788 1789 template<typename TCurve, typename OppCurve> 1790 void SkTSect<TCurve, OppCurve>::removeSpans(SkTSpan<TCurve, OppCurve>* span, 1791 SkTSect<OppCurve, TCurve>* opp) { 1792 SkTSpanBounded<OppCurve, TCurve>* bounded = span->fBounded; 1793 while (bounded) { 1794 SkTSpan<OppCurve, TCurve>* spanBounded = bounded->fBounded; 1795 SkTSpanBounded<OppCurve, TCurve>* next = bounded->fNext; 1796 if (span->removeBounded(spanBounded)) { // shuffles last into position 0 1797 this->removeSpan(span); 1798 } 1799 if (spanBounded->removeBounded(span)) { 1800 opp->removeSpan(spanBounded); 1801 } 1802 SkASSERT(!span->fDeleted || !opp->debugHasBounded(span)); 1803 bounded = next; 1804 } 1805 } 1806 1807 template<typename TCurve, typename OppCurve> 1808 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::spanAtT(double t, 1809 SkTSpan<TCurve, OppCurve>** priorSpan) { 1810 SkTSpan<TCurve, OppCurve>* test = fHead; 1811 SkTSpan<TCurve, OppCurve>* prev = nullptr; 1812 while (test && test->fEndT < t) { 1813 prev = test; 1814 test = test->fNext; 1815 } 1816 *priorSpan = prev; 1817 return test && test->fStartT <= t ? test : nullptr; 1818 } 1819 1820 template<typename TCurve, typename OppCurve> 1821 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::tail() { 1822 SkTSpan<TCurve, OppCurve>* result = fHead; 1823 SkTSpan<TCurve, OppCurve>* next = fHead; 1824 while ((next = next->fNext)) { 1825 if (next->fEndT > result->fEndT) { 1826 result = next; 1827 } 1828 } 1829 return result; 1830 } 1831 1832 /* Each span has a range of opposite spans it intersects. After the span is split in two, 1833 adjust the range to its new size */ 1834 template<typename TCurve, typename OppCurve> 1835 bool SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span, 1836 SkTSect<OppCurve, TCurve>* opp) { 1837 FAIL_IF(!span->initBounds(fCurve)); 1838 const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded; 1839 while (testBounded) { 1840 SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded; 1841 const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext; 1842 int oppSects, sects = this->intersects(span, opp, test, &oppSects); 1843 if (sects >= 1) { 1844 if (oppSects == 2) { 1845 test->initBounds(opp->fCurve); 1846 opp->removeAllBut(span, test, this); 1847 } 1848 if (sects == 2) { 1849 span->initBounds(fCurve); 1850 this->removeAllBut(test, span, opp); 1851 return true; 1852 } 1853 } else { 1854 if (span->removeBounded(test)) { 1855 this->removeSpan(span); 1856 } 1857 if (test->removeBounded(span)) { 1858 opp->removeSpan(test); 1859 } 1860 } 1861 testBounded = next; 1862 } 1863 return true; 1864 } 1865 1866 template<typename TCurve, typename OppCurve> 1867 void SkTSect<TCurve, OppCurve>::unlinkSpan(SkTSpan<TCurve, OppCurve>* span) { 1868 SkTSpan<TCurve, OppCurve>* prev = span->fPrev; 1869 SkTSpan<TCurve, OppCurve>* next = span->fNext; 1870 if (prev) { 1871 prev->fNext = next; 1872 if (next) { 1873 next->fPrev = prev; 1874 next->validate(); 1875 } 1876 } else { 1877 fHead = next; 1878 if (next) { 1879 next->fPrev = nullptr; 1880 } 1881 } 1882 } 1883 1884 template<typename TCurve, typename OppCurve> 1885 bool SkTSect<TCurve, OppCurve>::updateBounded(SkTSpan<TCurve, OppCurve>* first, 1886 SkTSpan<TCurve, OppCurve>* last, SkTSpan<OppCurve, TCurve>* oppFirst) { 1887 SkTSpan<TCurve, OppCurve>* test = first; 1888 const SkTSpan<TCurve, OppCurve>* final = last->next(); 1889 bool deleteSpan = false; 1890 do { 1891 deleteSpan |= test->removeAllBounded(); 1892 } while ((test = test->fNext) != final && test); 1893 first->fBounded = nullptr; 1894 first->addBounded(oppFirst, &fHeap); 1895 // cannot call validate until remove span range is called 1896 return deleteSpan; 1897 } 1898 1899 1900 template<typename TCurve, typename OppCurve> 1901 void SkTSect<TCurve, OppCurve>::validate() const { 1902 #if DEBUG_VALIDATE 1903 int count = 0; 1904 double last = 0; 1905 if (fHead) { 1906 const SkTSpan<TCurve, OppCurve>* span = fHead; 1907 SkASSERT(!span->fPrev); 1908 const SkTSpan<TCurve, OppCurve>* next; 1909 do { 1910 span->validate(); 1911 SkASSERT(span->fStartT >= last); 1912 last = span->fEndT; 1913 ++count; 1914 next = span->fNext; 1915 SkASSERT(next != span); 1916 } while ((span = next) != nullptr); 1917 } 1918 SkASSERT(count == fActiveCount); 1919 #endif 1920 #if DEBUG_T_SECT 1921 SkASSERT(fActiveCount <= fDebugAllocatedCount); 1922 int deletedCount = 0; 1923 const SkTSpan<TCurve, OppCurve>* deleted = fDeleted; 1924 while (deleted) { 1925 ++deletedCount; 1926 deleted = deleted->fNext; 1927 } 1928 const SkTSpan<TCurve, OppCurve>* coincident = fCoincident; 1929 while (coincident) { 1930 ++deletedCount; 1931 coincident = coincident->fNext; 1932 } 1933 SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount); 1934 #endif 1935 } 1936 1937 template<typename TCurve, typename OppCurve> 1938 void SkTSect<TCurve, OppCurve>::validateBounded() const { 1939 #if DEBUG_VALIDATE 1940 if (!fHead) { 1941 return; 1942 } 1943 const SkTSpan<TCurve, OppCurve>* span = fHead; 1944 do { 1945 span->validateBounded(); 1946 } while ((span = span->fNext) != nullptr); 1947 #endif 1948 } 1949 1950 template<typename TCurve, typename OppCurve> 1951 int SkTSect<TCurve, OppCurve>::EndsEqual(const SkTSect<TCurve, OppCurve>* sect1, 1952 const SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) { 1953 int zeroOneSet = 0; 1954 if (sect1->fCurve[0] == sect2->fCurve[0]) { 1955 zeroOneSet |= kZeroS1Set | kZeroS2Set; 1956 intersections->insert(0, 0, sect1->fCurve[0]); 1957 } 1958 if (sect1->fCurve[0] == sect2->fCurve[OppCurve::kPointLast]) { 1959 zeroOneSet |= kZeroS1Set | kOneS2Set; 1960 intersections->insert(0, 1, sect1->fCurve[0]); 1961 } 1962 if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[0]) { 1963 zeroOneSet |= kOneS1Set | kZeroS2Set; 1964 intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]); 1965 } 1966 if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[OppCurve::kPointLast]) { 1967 zeroOneSet |= kOneS1Set | kOneS2Set; 1968 intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]); 1969 } 1970 // check for zero 1971 if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set)) 1972 && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) { 1973 zeroOneSet |= kZeroS1Set | kZeroS2Set; 1974 intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]); 1975 } 1976 if (!(zeroOneSet & (kZeroS1Set | kOneS2Set)) 1977 && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[OppCurve::kPointLast])) { 1978 zeroOneSet |= kZeroS1Set | kOneS2Set; 1979 intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[OppCurve::kPointLast]); 1980 } 1981 // check for one 1982 if (!(zeroOneSet & (kOneS1Set | kZeroS2Set)) 1983 && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0])) { 1984 zeroOneSet |= kOneS1Set | kZeroS2Set; 1985 intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], sect2->fCurve[0]); 1986 } 1987 if (!(zeroOneSet & (kOneS1Set | kOneS2Set)) 1988 && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[ 1989 OppCurve::kPointLast])) { 1990 zeroOneSet |= kOneS1Set | kOneS2Set; 1991 intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast], 1992 sect2->fCurve[OppCurve::kPointLast]); 1993 } 1994 return zeroOneSet; 1995 } 1996 1997 template<typename TCurve, typename OppCurve> 1998 struct SkClosestRecord { 1999 bool operator<(const SkClosestRecord& rh) const { 2000 return fClosest < rh.fClosest; 2001 } 2002 2003 void addIntersection(SkIntersections* intersections) const { 2004 double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT(); 2005 double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT(); 2006 intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]); 2007 } 2008 2009 void findEnd(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2, 2010 int c1Index, int c2Index) { 2011 const TCurve& c1 = span1->part(); 2012 const OppCurve& c2 = span2->part(); 2013 if (!c1[c1Index].approximatelyEqual(c2[c2Index])) { 2014 return; 2015 } 2016 double dist = c1[c1Index].distanceSquared(c2[c2Index]); 2017 if (fClosest < dist) { 2018 return; 2019 } 2020 fC1Span = span1; 2021 fC2Span = span2; 2022 fC1StartT = span1->startT(); 2023 fC1EndT = span1->endT(); 2024 fC2StartT = span2->startT(); 2025 fC2EndT = span2->endT(); 2026 fC1Index = c1Index; 2027 fC2Index = c2Index; 2028 fClosest = dist; 2029 } 2030 2031 bool matesWith(const SkClosestRecord& mate SkDEBUGPARAMS(SkIntersections* i)) const { 2032 SkOPOBJASSERT(i, fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT() 2033 || mate.fC1Span->endT() <= fC1Span->startT()); 2034 SkOPOBJASSERT(i, fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->startT() 2035 || mate.fC2Span->endT() <= fC2Span->startT()); 2036 return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->startT() 2037 || fC1Span->startT() == mate.fC1Span->endT() 2038 || fC2Span == mate.fC2Span 2039 || fC2Span->endT() == mate.fC2Span->startT() 2040 || fC2Span->startT() == mate.fC2Span->endT(); 2041 } 2042 2043 void merge(const SkClosestRecord& mate) { 2044 fC1Span = mate.fC1Span; 2045 fC2Span = mate.fC2Span; 2046 fClosest = mate.fClosest; 2047 fC1Index = mate.fC1Index; 2048 fC2Index = mate.fC2Index; 2049 } 2050 2051 void reset() { 2052 fClosest = FLT_MAX; 2053 SkDEBUGCODE(fC1Span = nullptr); 2054 SkDEBUGCODE(fC2Span = nullptr); 2055 SkDEBUGCODE(fC1Index = fC2Index = -1); 2056 } 2057 2058 void update(const SkClosestRecord& mate) { 2059 fC1StartT = SkTMin(fC1StartT, mate.fC1StartT); 2060 fC1EndT = SkTMax(fC1EndT, mate.fC1EndT); 2061 fC2StartT = SkTMin(fC2StartT, mate.fC2StartT); 2062 fC2EndT = SkTMax(fC2EndT, mate.fC2EndT); 2063 } 2064 2065 const SkTSpan<TCurve, OppCurve>* fC1Span; 2066 const SkTSpan<OppCurve, TCurve>* fC2Span; 2067 double fC1StartT; 2068 double fC1EndT; 2069 double fC2StartT; 2070 double fC2EndT; 2071 double fClosest; 2072 int fC1Index; 2073 int fC2Index; 2074 }; 2075 2076 template<typename TCurve, typename OppCurve> 2077 struct SkClosestSect { 2078 SkClosestSect() 2079 : fUsed(0) { 2080 fClosest.push_back().reset(); 2081 } 2082 2083 bool find(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2 2084 SkDEBUGPARAMS(SkIntersections* i)) { 2085 SkClosestRecord<TCurve, OppCurve>* record = &fClosest[fUsed]; 2086 record->findEnd(span1, span2, 0, 0); 2087 record->findEnd(span1, span2, 0, OppCurve::kPointLast); 2088 record->findEnd(span1, span2, TCurve::kPointLast, 0); 2089 record->findEnd(span1, span2, TCurve::kPointLast, OppCurve::kPointLast); 2090 if (record->fClosest == FLT_MAX) { 2091 return false; 2092 } 2093 for (int index = 0; index < fUsed; ++index) { 2094 SkClosestRecord<TCurve, OppCurve>* test = &fClosest[index]; 2095 if (test->matesWith(*record SkDEBUGPARAMS(i))) { 2096 if (test->fClosest > record->fClosest) { 2097 test->merge(*record); 2098 } 2099 test->update(*record); 2100 record->reset(); 2101 return false; 2102 } 2103 } 2104 ++fUsed; 2105 fClosest.push_back().reset(); 2106 return true; 2107 } 2108 2109 void finish(SkIntersections* intersections) const { 2110 SkSTArray<TCurve::kMaxIntersections * 3, 2111 const SkClosestRecord<TCurve, OppCurve>*, true> closestPtrs; 2112 for (int index = 0; index < fUsed; ++index) { 2113 closestPtrs.push_back(&fClosest[index]); 2114 } 2115 SkTQSort<const SkClosestRecord<TCurve, OppCurve> >(closestPtrs.begin(), closestPtrs.end() 2116 - 1); 2117 for (int index = 0; index < fUsed; ++index) { 2118 const SkClosestRecord<TCurve, OppCurve>* test = closestPtrs[index]; 2119 test->addIntersection(intersections); 2120 } 2121 } 2122 2123 // this is oversized so that an extra records can merge into final one 2124 SkSTArray<TCurve::kMaxIntersections * 2, SkClosestRecord<TCurve, OppCurve>, true> fClosest; 2125 int fUsed; 2126 }; 2127 2128 // returns true if the rect is too small to consider 2129 template<typename TCurve, typename OppCurve> 2130 void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, 2131 SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) { 2132 #if DEBUG_T_SECT_DUMP > 1 2133 gDumpTSectNum = 0; 2134 #endif 2135 SkDEBUGCODE(sect1->fOppSect = sect2); 2136 SkDEBUGCODE(sect2->fOppSect = sect1); 2137 intersections->reset(); 2138 intersections->setMax(TCurve::kMaxIntersections + 4); // give extra for slop 2139 SkTSpan<TCurve, OppCurve>* span1 = sect1->fHead; 2140 SkTSpan<OppCurve, TCurve>* span2 = sect2->fHead; 2141 int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect); 2142 // SkASSERT(between(0, sect, 2)); 2143 if (!sect) { 2144 return; 2145 } 2146 if (sect == 2 && oppSect == 2) { 2147 (void) EndsEqual(sect1, sect2, intersections); 2148 return; 2149 } 2150 span1->addBounded(span2, §1->fHeap); 2151 span2->addBounded(span1, §2->fHeap); 2152 const int kMaxCoinLoopCount = 8; 2153 int coinLoopCount = kMaxCoinLoopCount; 2154 double start1s SK_INIT_TO_AVOID_WARNING; 2155 double start1e SK_INIT_TO_AVOID_WARNING; 2156 do { 2157 // find the largest bounds 2158 SkTSpan<TCurve, OppCurve>* largest1 = sect1->boundsMax(); 2159 if (!largest1) { 2160 break; 2161 } 2162 SkTSpan<OppCurve, TCurve>* largest2 = sect2->boundsMax(); 2163 // split it 2164 if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax 2165 || (!largest1->fCollapsed && largest2->fCollapsed)))) { 2166 if (largest1->fCollapsed) { 2167 break; 2168 } 2169 sect1->resetRemovedEnds(); 2170 sect2->resetRemovedEnds(); 2171 // trim parts that don't intersect the opposite 2172 SkTSpan<TCurve, OppCurve>* half1 = sect1->addOne(); 2173 SkDEBUGCODE(half1->debugSetGlobalState(sect1->globalState())); 2174 if (!half1->split(largest1, §1->fHeap)) { 2175 break; 2176 } 2177 if (!sect1->trim(largest1, sect2)) { 2178 SkOPOBJASSERT(intersections, 0); 2179 return; 2180 } 2181 if (!sect1->trim(half1, sect2)) { 2182 SkOPOBJASSERT(intersections, 0); 2183 return; 2184 } 2185 } else { 2186 if (largest2->fCollapsed) { 2187 break; 2188 } 2189 sect1->resetRemovedEnds(); 2190 sect2->resetRemovedEnds(); 2191 // trim parts that don't intersect the opposite 2192 SkTSpan<OppCurve, TCurve>* half2 = sect2->addOne(); 2193 SkDEBUGCODE(half2->debugSetGlobalState(sect2->globalState())); 2194 if (!half2->split(largest2, §2->fHeap)) { 2195 break; 2196 } 2197 if (!sect2->trim(largest2, sect1)) { 2198 SkOPOBJASSERT(intersections, 0); 2199 return; 2200 } 2201 if (!sect2->trim(half2, sect1)) { 2202 SkOPOBJASSERT(intersections, 0); 2203 return; 2204 } 2205 } 2206 sect1->validate(); 2207 sect2->validate(); 2208 #if DEBUG_T_SECT_LOOP_COUNT 2209 intersections->debugBumpLoopCount(SkIntersections::kIterations_DebugLoop); 2210 #endif 2211 // if there are 9 or more continuous spans on both sects, suspect coincidence 2212 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT 2213 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { 2214 if (coinLoopCount == kMaxCoinLoopCount) { 2215 start1s = sect1->fHead->fStartT; 2216 start1e = sect1->tail()->fEndT; 2217 } 2218 if (!sect1->coincidentCheck(sect2)) { 2219 return; 2220 } 2221 sect1->validate(); 2222 sect2->validate(); 2223 #if DEBUG_T_SECT_LOOP_COUNT 2224 intersections->debugBumpLoopCount(SkIntersections::kCoinCheck_DebugLoop); 2225 #endif 2226 if (!--coinLoopCount && sect1->fHead && sect2->fHead) { 2227 /* All known working cases resolve in two tries. Sadly, cubicConicTests[0] 2228 gets stuck in a loop. It adds an extension to allow a coincident end 2229 perpendicular to track its intersection in the opposite curve. However, 2230 the bounding box of the extension does not intersect the original curve, 2231 so the extension is discarded, only to be added again the next time around. */ 2232 sect1->coincidentForce(sect2, start1s, start1e); 2233 sect1->validate(); 2234 sect2->validate(); 2235 } 2236 } 2237 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT 2238 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { 2239 if (!sect1->fHead) { 2240 return; 2241 } 2242 sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail()); 2243 if (!sect2->fHead) { 2244 return; 2245 } 2246 sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail()); 2247 sect1->removeByPerpendicular(sect2); 2248 sect1->validate(); 2249 sect2->validate(); 2250 #if DEBUG_T_SECT_LOOP_COUNT 2251 intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop); 2252 #endif 2253 if (sect1->collapsed() > TCurve::kMaxIntersections) { 2254 break; 2255 } 2256 } 2257 #if DEBUG_T_SECT_DUMP 2258 sect1->dumpBoth(sect2); 2259 #endif 2260 if (!sect1->fHead || !sect2->fHead) { 2261 break; 2262 } 2263 } while (true); 2264 SkTSpan<TCurve, OppCurve>* coincident = sect1->fCoincident; 2265 if (coincident) { 2266 // if there is more than one coincident span, check loosely to see if they should be joined 2267 if (coincident->fNext) { 2268 sect1->mergeCoincidence(sect2); 2269 coincident = sect1->fCoincident; 2270 } 2271 SkASSERT(sect2->fCoincident); // courtesy check : coincidence only looks at sect 1 2272 do { 2273 if (!coincident) { 2274 return; 2275 } 2276 if (!coincident->fCoinStart.isMatch()) { 2277 continue; 2278 } 2279 if (!coincident->fCoinEnd.isMatch()) { 2280 continue; 2281 } 2282 double perpT = coincident->fCoinStart.perpT(); 2283 if (perpT < 0) { 2284 return; 2285 } 2286 int index = intersections->insertCoincident(coincident->fStartT, 2287 perpT, coincident->fPart[0]); 2288 if ((intersections->insertCoincident(coincident->fEndT, 2289 coincident->fCoinEnd.perpT(), 2290 coincident->fPart[TCurve::kPointLast]) < 0) && index >= 0) { 2291 intersections->clearCoincidence(index); 2292 } 2293 } while ((coincident = coincident->fNext)); 2294 } 2295 int zeroOneSet = EndsEqual(sect1, sect2, intersections); 2296 // if (!sect1->fHead || !sect2->fHead) { 2297 // if the final iteration contains an end (0 or 1), 2298 if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) { 2299 SkTCoincident<TCurve, OppCurve> perp; // intersect perpendicular with opposite curve 2300 perp.setPerp(sect1->fCurve, 0, sect1->fCurve[0], sect2->fCurve); 2301 if (perp.isMatch()) { 2302 intersections->insert(0, perp.perpT(), perp.perpPt()); 2303 } 2304 } 2305 if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) { 2306 SkTCoincident<TCurve, OppCurve> perp; 2307 perp.setPerp(sect1->fCurve, 1, sect1->fCurve[TCurve::kPointLast], sect2->fCurve); 2308 if (perp.isMatch()) { 2309 intersections->insert(1, perp.perpT(), perp.perpPt()); 2310 } 2311 } 2312 if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) { 2313 SkTCoincident<OppCurve, TCurve> perp; 2314 perp.setPerp(sect2->fCurve, 0, sect2->fCurve[0], sect1->fCurve); 2315 if (perp.isMatch()) { 2316 intersections->insert(perp.perpT(), 0, perp.perpPt()); 2317 } 2318 } 2319 if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) { 2320 SkTCoincident<OppCurve, TCurve> perp; 2321 perp.setPerp(sect2->fCurve, 1, sect2->fCurve[OppCurve::kPointLast], sect1->fCurve); 2322 if (perp.isMatch()) { 2323 intersections->insert(perp.perpT(), 1, perp.perpPt()); 2324 } 2325 } 2326 // } 2327 if (!sect1->fHead || !sect2->fHead) { 2328 return; 2329 } 2330 sect1->recoverCollapsed(); 2331 sect2->recoverCollapsed(); 2332 SkTSpan<TCurve, OppCurve>* result1 = sect1->fHead; 2333 // check heads and tails for zero and ones and insert them if we haven't already done so 2334 const SkTSpan<TCurve, OppCurve>* head1 = result1; 2335 if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStartT)) { 2336 const SkDPoint& start1 = sect1->fCurve[0]; 2337 if (head1->isBounded()) { 2338 double t = head1->closestBoundedT(start1); 2339 if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) { 2340 intersections->insert(0, t, start1); 2341 } 2342 } 2343 } 2344 const SkTSpan<OppCurve, TCurve>* head2 = sect2->fHead; 2345 if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStartT)) { 2346 const SkDPoint& start2 = sect2->fCurve[0]; 2347 if (head2->isBounded()) { 2348 double t = head2->closestBoundedT(start2); 2349 if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) { 2350 intersections->insert(t, 0, start2); 2351 } 2352 } 2353 } 2354 const SkTSpan<TCurve, OppCurve>* tail1 = sect1->tail(); 2355 if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT)) { 2356 const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast]; 2357 if (tail1->isBounded()) { 2358 double t = tail1->closestBoundedT(end1); 2359 if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) { 2360 intersections->insert(1, t, end1); 2361 } 2362 } 2363 } 2364 const SkTSpan<OppCurve, TCurve>* tail2 = sect2->tail(); 2365 if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT)) { 2366 const SkDPoint& end2 = sect2->fCurve[OppCurve::kPointLast]; 2367 if (tail2->isBounded()) { 2368 double t = tail2->closestBoundedT(end2); 2369 if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) { 2370 intersections->insert(t, 1, end2); 2371 } 2372 } 2373 } 2374 SkClosestSect<TCurve, OppCurve> closest; 2375 do { 2376 while (result1 && result1->fCoinStart.isMatch() && result1->fCoinEnd.isMatch()) { 2377 result1 = result1->fNext; 2378 } 2379 if (!result1) { 2380 break; 2381 } 2382 SkTSpan<OppCurve, TCurve>* result2 = sect2->fHead; 2383 bool found = false; 2384 while (result2) { 2385 found |= closest.find(result1, result2 SkDEBUGPARAMS(intersections)); 2386 result2 = result2->fNext; 2387 } 2388 } while ((result1 = result1->fNext)); 2389 closest.finish(intersections); 2390 // if there is more than one intersection and it isn't already coincident, check 2391 int last = intersections->used() - 1; 2392 for (int index = 0; index < last; ) { 2393 if (intersections->isCoincident(index) && intersections->isCoincident(index + 1)) { 2394 ++index; 2395 continue; 2396 } 2397 double midT = ((*intersections)[0][index] + (*intersections)[0][index + 1]) / 2; 2398 SkDPoint midPt = sect1->fCurve.ptAtT(midT); 2399 // intersect perpendicular with opposite curve 2400 SkTCoincident<TCurve, OppCurve> perp; 2401 perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve); 2402 if (!perp.isMatch()) { 2403 ++index; 2404 continue; 2405 } 2406 if (intersections->isCoincident(index)) { 2407 intersections->removeOne(index); 2408 --last; 2409 } else if (intersections->isCoincident(index + 1)) { 2410 intersections->removeOne(index + 1); 2411 --last; 2412 } else { 2413 intersections->setCoincident(index++); 2414 } 2415 intersections->setCoincident(index); 2416 } 2417 SkOPOBJASSERT(intersections, intersections->used() <= TCurve::kMaxIntersections); 2418 } 2419 2420 #endif 2421