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