OLD | NEW |
(Empty) | |
| 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 "SkPathOpsRect.h" |
| 10 #include "SkPathOpsQuad.h" |
| 11 #include "SkIntersections.h" |
| 12 #include "SkTArray.h" |
| 13 |
| 14 /* TCurve is either SkDQuadratic or SkDCubic */ |
| 15 template<typename TCurve> |
| 16 class SkTCoincident { |
| 17 public: |
| 18 bool isCoincident() const { |
| 19 return fCoincident; |
| 20 } |
| 21 |
| 22 void init() { |
| 23 fCoincident = false; |
| 24 SkDEBUGCODE(fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN); |
| 25 SkDEBUGCODE(fPerpT = SK_ScalarNaN); |
| 26 } |
| 27 |
| 28 void markCoincident() { |
| 29 if (!fCoincident) { |
| 30 fPerpT = -1; |
| 31 } |
| 32 fCoincident = true; |
| 33 } |
| 34 |
| 35 const SkDPoint& perpPt() const { |
| 36 return fPerpPt; |
| 37 } |
| 38 |
| 39 double perpT() const { |
| 40 return fPerpT; |
| 41 } |
| 42 |
| 43 void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const TCurve&
); |
| 44 |
| 45 private: |
| 46 SkDPoint fPerpPt; |
| 47 double fPerpT; // perpendicular intersection on opposite curve |
| 48 bool fCoincident; |
| 49 }; |
| 50 |
| 51 template<typename TCurve> class SkTSect; |
| 52 |
| 53 /* Curve is either TCurve or SkDCubic */ |
| 54 template<typename TCurve> |
| 55 class SkTSpan { |
| 56 public: |
| 57 void init(const TCurve& ); |
| 58 void initBounds(const TCurve& ); |
| 59 |
| 60 double closestBoundedT(const SkDPoint& pt) const; |
| 61 |
| 62 bool contains(double t) const { |
| 63 return !! const_cast<SkTSpan*>(this)->innerFind(t); |
| 64 } |
| 65 |
| 66 bool contains(const SkTSpan* span) const; |
| 67 |
| 68 double endT() const { |
| 69 return fEndT; |
| 70 } |
| 71 |
| 72 SkTSpan* find(double t) { |
| 73 SkTSpan* result = innerFind(t); |
| 74 SkASSERT(result); |
| 75 return result; |
| 76 } |
| 77 |
| 78 bool intersects(const SkTSpan* span, bool* check); |
| 79 |
| 80 const SkTSpan* next() const { |
| 81 return fNext; |
| 82 } |
| 83 |
| 84 const TCurve& part() const { |
| 85 return fPart; |
| 86 } |
| 87 |
| 88 void reset() { |
| 89 fBounded.reset(); |
| 90 } |
| 91 |
| 92 bool split(SkTSpan* work) { |
| 93 return splitAt(work, (work->fStartT + work->fEndT) * 0.5); |
| 94 } |
| 95 |
| 96 bool splitAt(SkTSpan* work, double t); |
| 97 |
| 98 double startT() const { |
| 99 return fStartT; |
| 100 } |
| 101 |
| 102 bool tightBoundsIntersects(const SkTSpan* span) const; |
| 103 |
| 104 // implementation is for testing only |
| 105 void dump() const { |
| 106 dump(NULL); |
| 107 } |
| 108 |
| 109 private: |
| 110 SkTSpan* innerFind(double t); |
| 111 bool linearIntersects(const TCurve& ) const; |
| 112 |
| 113 // implementation is for testing only |
| 114 #if DEBUG_T_SECT |
| 115 int debugID(const SkTSect<TCurve>* ) const { return fDebugID; } |
| 116 #else |
| 117 int debugID(const SkTSect<TCurve>* ) const; |
| 118 #endif |
| 119 void dump(const SkTSect<TCurve>* ) const; |
| 120 void dumpID(const SkTSect<TCurve>* ) const; |
| 121 |
| 122 #if DEBUG_T_SECT |
| 123 void validate() const; |
| 124 #endif |
| 125 |
| 126 TCurve fPart; |
| 127 SkTCoincident<TCurve> fCoinStart; |
| 128 SkTCoincident<TCurve> fCoinEnd; |
| 129 SkSTArray<4, SkTSpan*, true> fBounded; |
| 130 SkTSpan* fPrev; |
| 131 SkTSpan* fNext; |
| 132 SkDRect fBounds; |
| 133 double fStartT; |
| 134 double fEndT; |
| 135 double fBoundsMax; |
| 136 bool fCollapsed; |
| 137 bool fHasPerp; |
| 138 bool fIsLinear; |
| 139 #if DEBUG_T_SECT |
| 140 int fDebugID; |
| 141 bool fDebugDeleted; |
| 142 #endif |
| 143 friend class SkTSect<TCurve>; |
| 144 }; |
| 145 |
| 146 template<typename TCurve> |
| 147 class SkTSect { |
| 148 public: |
| 149 SkTSect(const TCurve& c PATH_OPS_DEBUG_PARAMS(int id)); |
| 150 static void BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersections* in
tersections); |
| 151 |
| 152 // for testing only |
| 153 void dump() const; |
| 154 void dumpBoth(const SkTSect& opp) const; |
| 155 void dumpBoth(const SkTSect* opp) const; |
| 156 void dumpCurves() const; |
| 157 |
| 158 private: |
| 159 enum { |
| 160 kZeroS1Set = 1, |
| 161 kOneS1Set = 2, |
| 162 kZeroS2Set = 4, |
| 163 kOneS2Set = 8 |
| 164 }; |
| 165 |
| 166 SkTSpan<TCurve>* addOne(); |
| 167 bool binarySearchCoin(const SkTSect& , double tStart, double tStep, double*
t, double* oppT); |
| 168 SkTSpan<TCurve>* boundsMax() const; |
| 169 void coincidentCheck(SkTSect* sect2); |
| 170 static int EndsEqual(const SkTSect* sect1, const SkTSect* sect2, SkIntersect
ions* ); |
| 171 bool intersects(SkTSpan<TCurve>* span, const SkTSect* opp, |
| 172 const SkTSpan<TCurve>* oppSpan) const; |
| 173 void onCurveCheck(SkTSect* sect2, SkTSpan<TCurve>* first, SkTSpan<TCurve>* l
ast); |
| 174 void recoverCollapsed(); |
| 175 void removeSpan(SkTSpan<TCurve>* span); |
| 176 void removeOne(const SkTSpan<TCurve>* test, SkTSpan<TCurve>* span); |
| 177 void removeSpans(SkTSpan<TCurve>* span, SkTSect* opp); |
| 178 void setPerp(const TCurve& opp, SkTSpan<TCurve>* first, SkTSpan<TCurve>* las
t); |
| 179 const SkTSpan<TCurve>* tail() const; |
| 180 void trim(SkTSpan<TCurve>* span, SkTSect* opp); |
| 181 |
| 182 #if DEBUG_T_SECT |
| 183 int debugID() const { return fDebugID; } |
| 184 void validate() const; |
| 185 #else |
| 186 int debugID() const { return 0; } |
| 187 #endif |
| 188 const TCurve& fCurve; |
| 189 SkChunkAlloc fHeap; |
| 190 SkTSpan<TCurve>* fHead; |
| 191 SkTSpan<TCurve>* fDeleted; |
| 192 int fActiveCount; |
| 193 #if DEBUG_T_SECT |
| 194 int fDebugID; |
| 195 int fDebugCount; |
| 196 int fDebugAllocatedCount; |
| 197 #endif |
| 198 friend class SkTSpan<TCurve>; // only used by debug id |
| 199 }; |
| 200 |
| 201 #define COINCIDENT_SPAN_COUNT 9 |
| 202 |
| 203 template<typename TCurve> |
| 204 void SkTCoincident<TCurve>::setPerp(const TCurve& c1, double t, |
| 205 const SkDPoint& cPt, const TCurve& c2) { |
| 206 SkDVector dxdy = c1.dxdyAtT(t); |
| 207 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; |
| 208 SkIntersections i; |
| 209 int used = i.intersectRay(c2, perp); |
| 210 // only keep closest |
| 211 if (used == 0) { |
| 212 fPerpT = -1; |
| 213 return; |
| 214 } |
| 215 fPerpT = i[0][0]; |
| 216 fPerpPt = i.pt(0); |
| 217 SkASSERT(used <= 2); |
| 218 if (used == 2) { |
| 219 double distSq = (fPerpPt - cPt).lengthSquared(); |
| 220 double dist2Sq = (i.pt(1) - cPt).lengthSquared(); |
| 221 if (dist2Sq < distSq) { |
| 222 fPerpT = i[0][1]; |
| 223 fPerpPt = i.pt(1); |
| 224 } |
| 225 } |
| 226 fCoincident = cPt.approximatelyEqual(fPerpPt); |
| 227 #if DEBUG_T_SECT |
| 228 if (fCoincident) { |
| 229 SkDebugf(""); // allow setting breakpoint |
| 230 } |
| 231 #endif |
| 232 } |
| 233 |
| 234 template<typename TCurve> |
| 235 void SkTSpan<TCurve>::init(const TCurve& c) { |
| 236 fPrev = fNext = NULL; |
| 237 fIsLinear = false; |
| 238 fStartT = 0; |
| 239 fEndT = 1; |
| 240 initBounds(c); |
| 241 } |
| 242 |
| 243 template<typename TCurve> |
| 244 void SkTSpan<TCurve>::initBounds(const TCurve& c) { |
| 245 fPart = c.subDivide(fStartT, fEndT); |
| 246 fBounds.setBounds(fPart); |
| 247 fCoinStart.init(); |
| 248 fCoinEnd.init(); |
| 249 fBoundsMax = SkTMax(fBounds.width(), fBounds.height()); |
| 250 fCollapsed = fPart.collapsed(); |
| 251 fHasPerp = false; |
| 252 #if DEBUG_T_SECT |
| 253 fDebugDeleted = false; |
| 254 if (fCollapsed) { |
| 255 SkDebugf(""); // for convenient breakpoints |
| 256 } |
| 257 #endif |
| 258 } |
| 259 |
| 260 template<typename TCurve> |
| 261 double SkTSpan<TCurve>::closestBoundedT(const SkDPoint& pt) const { |
| 262 int count = fBounded.count(); |
| 263 double result = -1; |
| 264 double closest = FLT_MAX; |
| 265 for (int index = 0; index < count; ++index) { |
| 266 const SkTSpan* test = fBounded[index]; |
| 267 double startDist = test->fPart[0].distanceSquared(pt); |
| 268 if (closest > startDist) { |
| 269 closest = startDist; |
| 270 result = test->fStartT; |
| 271 } |
| 272 double endDist = test->fPart[TCurve::kPointLast].distanceSquared(pt); |
| 273 if (closest > endDist) { |
| 274 closest = endDist; |
| 275 result = test->fEndT; |
| 276 } |
| 277 } |
| 278 SkASSERT(between(0, result, 1)); |
| 279 return result; |
| 280 } |
| 281 |
| 282 template<typename TCurve> |
| 283 bool SkTSpan<TCurve>::contains(const SkTSpan* span) const { |
| 284 int count = fBounded.count(); |
| 285 for (int index = 0; index < count; ++index) { |
| 286 const SkTSpan* test = fBounded[index]; |
| 287 if (span == test) { |
| 288 return true; |
| 289 } |
| 290 } |
| 291 return false; |
| 292 } |
| 293 |
| 294 template<typename TCurve> |
| 295 SkTSpan<TCurve>* SkTSpan<TCurve>::innerFind(double t) { |
| 296 SkTSpan* work = this; |
| 297 do { |
| 298 if (between(work->fStartT, t, work->fEndT)) { |
| 299 return work; |
| 300 } |
| 301 } while ((work = work->fNext)); |
| 302 return NULL; |
| 303 } |
| 304 |
| 305 // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear, |
| 306 // use line intersection to guess a better split than 0.5 |
| 307 // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all futu
re splits are linear |
| 308 template<typename TCurve> |
| 309 bool SkTSpan<TCurve>::intersects(const SkTSpan* span, bool* check) { |
| 310 if (!fBounds.intersects(span->fBounds)) { |
| 311 *check = false; // no need to check to see if the bounds have end point
s in common |
| 312 return false; |
| 313 } |
| 314 if (!fIsLinear && fPart.hullIntersects(span->fPart, check)) { |
| 315 if (!*check) { |
| 316 return true; |
| 317 } |
| 318 fIsLinear = true; |
| 319 } |
| 320 if (fIsLinear) { |
| 321 *check = false; |
| 322 return linearIntersects(span->fPart); |
| 323 } |
| 324 return *check; |
| 325 } |
| 326 |
| 327 template<typename TCurve> |
| 328 bool SkTSpan<TCurve>::linearIntersects(const TCurve& q2) const { |
| 329 // looks like q1 is near-linear |
| 330 int start = 0, end = TCurve::kPointCount - 1; // the outside points are usu
ally the extremes |
| 331 if (!fPart.controlsInside()) { |
| 332 double dist = 0; // if there's any question, compute distance to find b
est outsiders |
| 333 for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) { |
| 334 for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) { |
| 335 double test = (fPart[outer] - fPart[inner]).lengthSquared(); |
| 336 if (dist > test) { |
| 337 continue; |
| 338 } |
| 339 dist = test; |
| 340 start = outer; |
| 341 end = inner; |
| 342 } |
| 343 } |
| 344 } |
| 345 // see if q2 is on one side of the line formed by the extreme points |
| 346 double origX = fPart[start].fX; |
| 347 double origY = fPart[start].fY; |
| 348 double adj = fPart[end].fX - origX; |
| 349 double opp = fPart[end].fY - origY; |
| 350 double sign; |
| 351 for (int n = 0; n < TCurve::kPointCount; ++n) { |
| 352 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; |
| 353 if (precisely_zero(test)) { |
| 354 return true; |
| 355 } |
| 356 if (n == 0) { |
| 357 sign = test; |
| 358 continue; |
| 359 } |
| 360 if (test * sign < 0) { |
| 361 return true; |
| 362 } |
| 363 } |
| 364 return false; |
| 365 } |
| 366 |
| 367 template<typename TCurve> |
| 368 bool SkTSpan<TCurve>::splitAt(SkTSpan* work, double t) { |
| 369 fStartT = t; |
| 370 fEndT = work->fEndT; |
| 371 if (fStartT == fEndT) { |
| 372 fCollapsed = true; |
| 373 return false; |
| 374 } |
| 375 work->fEndT = t; |
| 376 if (work->fStartT == work->fEndT) { |
| 377 work->fCollapsed = true; |
| 378 return false; |
| 379 } |
| 380 fPrev = work; |
| 381 fNext = work->fNext; |
| 382 fIsLinear = work->fIsLinear; |
| 383 work->fNext = this; |
| 384 if (fNext) { |
| 385 fNext->fPrev = this; |
| 386 } |
| 387 fBounded = work->fBounded; |
| 388 int count = fBounded.count(); |
| 389 for (int index = 0; index < count; ++index) { |
| 390 fBounded[index]->fBounded.push_back() = this; |
| 391 } |
| 392 return true; |
| 393 } |
| 394 |
| 395 template<typename TCurve> |
| 396 bool SkTSpan<TCurve>::tightBoundsIntersects(const SkTSpan* span) const { |
| 397 // skew all to an axis |
| 398 SkDVector v2_0 = fPart[TCurve::kPointLast] - fPart[0]; |
| 399 bool skewToXAxis = fabs(v2_0.fX) > fabs(v2_0.fY); |
| 400 double ratio = skewToXAxis ? v2_0.fY / v2_0.fX : v2_0.fX / v2_0.fY; |
| 401 TCurve r1 = fPart; |
| 402 if (skewToXAxis) { |
| 403 r1[1].fY -= (fPart[1].fX - r1[0].fX) * ratio; |
| 404 if (TCurve::IsCubic()) { |
| 405 r1[2].fY -= (fPart[2].fX - r1[0].fX) * ratio; |
| 406 r1[3].fY = r1[0].fY; |
| 407 } else { |
| 408 r1[2].fY = r1[0].fY; |
| 409 } |
| 410 } else { |
| 411 r1[1].fX -= (fPart[1].fY - r1[0].fY) * ratio; |
| 412 if (TCurve::IsCubic()) { |
| 413 r1[2].fX -= (fPart[2].fY - r1[0].fY) * ratio; |
| 414 r1[3].fX = r1[0].fX; |
| 415 } else { |
| 416 r1[2].fX = r1[0].fX; |
| 417 } |
| 418 } |
| 419 // compute the tight skewed bounds |
| 420 SkDRect bounds; |
| 421 bounds.setBounds(r1); |
| 422 // see if opposite ends are within range of tight skewed bounds |
| 423 TCurve r2 = span->fPart; |
| 424 for (int i = 0; i < TCurve::kPointCount; i += 2) { |
| 425 if (skewToXAxis) { |
| 426 r2[i].fY -= (r2[i].fX - r1[0].fX) * ratio; |
| 427 if (between(bounds.fTop, r2[i].fY, bounds.fBottom)) { |
| 428 return true; |
| 429 } |
| 430 } else { |
| 431 r2[i].fX -= (r2[i].fY - r1[0].fY) * ratio; |
| 432 if (between(bounds.fLeft, r2[i].fX, bounds.fRight)) { |
| 433 return true; |
| 434 } |
| 435 } |
| 436 } |
| 437 // see if opposite ends are on either side of tight skewed bounds |
| 438 if ((skewToXAxis ? (r2[0].fY - r1[0].fY) * (r2[TCurve::kPointLast].fY - r1[0
].fY) |
| 439 : (r2[0].fX - r1[0].fX) * (r2[TCurve::kPointLast].fX - r
1[0].fX)) < 0) { |
| 440 return true; |
| 441 } |
| 442 // compute opposite tight skewed bounds |
| 443 if (skewToXAxis) { |
| 444 r2[1].fY -= (r2[1].fX - r1[0].fX) * ratio; |
| 445 if (TCurve::IsCubic()) { |
| 446 r2[2].fY -= (r2[2].fX - r1[0].fX) * ratio; |
| 447 } |
| 448 } else { |
| 449 r2[1].fX -= (r2[1].fY - r1[0].fY) * ratio; |
| 450 if (TCurve::IsCubic()) { |
| 451 r2[2].fX -= (r2[2].fY - r1[0].fY) * ratio; |
| 452 } |
| 453 } |
| 454 SkDRect sBounds; |
| 455 sBounds.setBounds(r2); |
| 456 // see if tight bounds overlap |
| 457 if (skewToXAxis) { |
| 458 return bounds.fTop <= sBounds.fBottom && sBounds.fTop <= bounds.fBottom;
|
| 459 } else { |
| 460 return bounds.fLeft <= sBounds.fRight && sBounds.fLeft <= bounds.fRight;
|
| 461 } |
| 462 } |
| 463 |
| 464 #if DEBUG_T_SECT |
| 465 template<typename TCurve> |
| 466 void SkTSpan<TCurve>::validate() const { |
| 467 SkASSERT(fNext == NULL || fNext != fPrev); |
| 468 SkASSERT(fNext == NULL || this == fNext->fPrev); |
| 469 SkASSERT(fBounds.width() || fBounds.height()); |
| 470 SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height())); |
| 471 SkASSERT(0 <= fStartT); |
| 472 SkASSERT(fEndT <= 1); |
| 473 SkASSERT(fStartT < fEndT); |
| 474 SkASSERT(fBounded.count() > 0); |
| 475 for (int index = 0; index < fBounded.count(); ++index) { |
| 476 const SkTSpan* overlap = fBounded[index]; |
| 477 SkASSERT(((fDebugID ^ overlap->fDebugID) & 1) == 1); |
| 478 SkASSERT(overlap->contains(this)); |
| 479 } |
| 480 } |
| 481 #endif |
| 482 |
| 483 template<typename TCurve> |
| 484 SkTSect<TCurve>::SkTSect(const TCurve& c PATH_OPS_DEBUG_PARAMS(int id)) |
| 485 : fCurve(c) |
| 486 , fHeap(sizeof(SkTSpan<TCurve>) * 4) |
| 487 , fDeleted(NULL) |
| 488 , fActiveCount(0) |
| 489 PATH_OPS_DEBUG_PARAMS(fDebugID(id)) |
| 490 PATH_OPS_DEBUG_PARAMS(fDebugCount(0)) |
| 491 PATH_OPS_DEBUG_PARAMS(fDebugAllocatedCount(0)) |
| 492 { |
| 493 fHead = addOne(); |
| 494 fHead->init(c); |
| 495 } |
| 496 |
| 497 template<typename TCurve> |
| 498 SkTSpan<TCurve>* SkTSect<TCurve>::addOne() { |
| 499 SkTSpan<TCurve>* result; |
| 500 if (fDeleted) { |
| 501 result = fDeleted; |
| 502 result->reset(); |
| 503 fDeleted = result->fNext; |
| 504 } else { |
| 505 result = SkNEW_PLACEMENT(fHeap.allocThrow(sizeof(SkTSpan<TCurve>)), SkTS
pan<TCurve>); |
| 506 #if DEBUG_T_SECT |
| 507 ++fDebugAllocatedCount; |
| 508 #endif |
| 509 } |
| 510 ++fActiveCount; |
| 511 #if DEBUG_T_SECT |
| 512 result->fDebugID = fDebugCount++ * 2 + fDebugID; |
| 513 #endif |
| 514 return result; |
| 515 } |
| 516 |
| 517 template<typename TCurve> |
| 518 bool SkTSect<TCurve>::binarySearchCoin(const SkTSect& sect2, double tStart, doub
le tStep, |
| 519 double* resultT, double* oppT) { |
| 520 SkTSpan<TCurve> work; |
| 521 double result = work.fStartT = work.fEndT = tStart; |
| 522 SkDPoint last = fCurve.ptAtT(tStart); |
| 523 SkDPoint oppPt; |
| 524 bool flip = false; |
| 525 SkDEBUGCODE(bool down = tStep < 0); |
| 526 const TCurve& opp = sect2.fCurve; |
| 527 do { |
| 528 tStep *= 0.5; |
| 529 work.fStartT += tStep; |
| 530 if (flip) { |
| 531 tStep = -tStep; |
| 532 flip = false; |
| 533 } |
| 534 work.initBounds(fCurve); |
| 535 if (work.fCollapsed) { |
| 536 return false; |
| 537 } |
| 538 if (last.approximatelyEqual(work.fPart[0])) { |
| 539 break; |
| 540 } |
| 541 last = work.fPart[0]; |
| 542 work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp); |
| 543 if (work.fCoinStart.isCoincident()) { |
| 544 double oppTTest = work.fCoinStart.perpT(); |
| 545 if (sect2.fHead->contains(oppTTest)) { |
| 546 *oppT = oppTTest; |
| 547 oppPt = work.fCoinStart.perpPt(); |
| 548 SkASSERT(down ? result > work.fStartT : result < work.fStartT); |
| 549 result = work.fStartT; |
| 550 continue; |
| 551 } |
| 552 } |
| 553 tStep = -tStep; |
| 554 flip = true; |
| 555 } while (true); |
| 556 if (last.approximatelyEqual(fCurve[0])) { |
| 557 result = 0; |
| 558 } else if (last.approximatelyEqual(fCurve[TCurve::kPointLast])) { |
| 559 result = 1; |
| 560 } |
| 561 if (oppPt.approximatelyEqual(opp[0])) { |
| 562 *oppT = 0; |
| 563 } else if (oppPt.approximatelyEqual(opp[TCurve::kPointLast])) { |
| 564 *oppT = 1; |
| 565 } |
| 566 *resultT = result; |
| 567 return true; |
| 568 } |
| 569 |
| 570 // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in
quad span |
| 571 // so that each quad sect has a pointer to the largest, and can updat
e it as spans |
| 572 // are split |
| 573 template<typename TCurve> |
| 574 SkTSpan<TCurve>* SkTSect<TCurve>::boundsMax() const { |
| 575 SkTSpan<TCurve>* test = fHead; |
| 576 SkTSpan<TCurve>* largest = fHead; |
| 577 bool largestCoin = largest->fCoinStart.isCoincident() && largest->fCoinEnd.i
sCoincident(); |
| 578 while ((test = test->fNext)) { |
| 579 bool testCoin = test->fCoinStart.isCoincident() || test->fCoinEnd.isCoin
cident(); |
| 580 if ((largestCoin && !testCoin) || (largestCoin == testCoin |
| 581 && (largest->fBoundsMax < test->fBoundsMax |
| 582 || (largest->fCollapsed && !test->fCollapsed)))) { |
| 583 largest = test; |
| 584 largestCoin = testCoin; |
| 585 } |
| 586 } |
| 587 return largestCoin ? NULL : largest; |
| 588 } |
| 589 |
| 590 template<typename TCurve> |
| 591 void SkTSect<TCurve>::coincidentCheck(SkTSect* sect2) { |
| 592 SkTSpan<TCurve>* first = fHead; |
| 593 SkTSpan<TCurve>* next; |
| 594 do { |
| 595 int consecutive = 1; |
| 596 SkTSpan<TCurve>* last = first; |
| 597 do { |
| 598 next = last->fNext; |
| 599 if (!next) { |
| 600 break; |
| 601 } |
| 602 if (next->fStartT > last->fEndT) { |
| 603 break; |
| 604 } |
| 605 ++consecutive; |
| 606 last = next; |
| 607 } while (true); |
| 608 if (consecutive < COINCIDENT_SPAN_COUNT) { |
| 609 continue; |
| 610 } |
| 611 setPerp(sect2->fCurve, first, last); |
| 612 // check to see if a range of points are on the curve |
| 613 onCurveCheck(sect2, first, last); |
| 614 SkTSpan<TCurve>* removalCandidate = NULL; |
| 615 if (!first->fCoinStart.isCoincident()) { |
| 616 SkTSpan<TCurve>* firstCoin = first->fNext; |
| 617 removalCandidate = first; |
| 618 first = firstCoin; |
| 619 } |
| 620 if (!first->fCoinStart.isCoincident()) { |
| 621 continue; |
| 622 } |
| 623 if (removalCandidate) { |
| 624 removeSpans(removalCandidate, sect2); |
| 625 } |
| 626 if (!last->fCoinStart.isCoincident()) { |
| 627 continue; |
| 628 } |
| 629 if (!last->fCoinEnd.isCoincident()) { |
| 630 if (--consecutive < COINCIDENT_SPAN_COUNT) { |
| 631 continue; |
| 632 } |
| 633 last = last->fPrev; |
| 634 SkASSERT(last->fCoinStart.isCoincident()); |
| 635 SkASSERT(last->fCoinEnd.isCoincident()); |
| 636 } |
| 637 SkASSERT(between(0, first->fCoinStart.perpT(), 1) || first->fCoinStart.p
erpT() == -1); |
| 638 if (first->fCoinStart.perpT() < 0) { |
| 639 first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], s
ect2->fCurve); |
| 640 } |
| 641 SkASSERT(between(0, last->fCoinEnd.perpT(), 1) || last->fCoinEnd.perpT()
== -1); |
| 642 if (last->fCoinEnd.perpT() < 0) { |
| 643 last->fCoinEnd.setPerp(fCurve, last->fEndT, last->fPart[TCurve::kPoi
ntLast], |
| 644 sect2->fCurve); |
| 645 } |
| 646 SkTSpan<TCurve>* removeMe = first->fNext; |
| 647 while (removeMe != last) { |
| 648 SkTSpan<TCurve>* removeNext = removeMe->fNext; |
| 649 removeSpans(removeMe, sect2); |
| 650 removeMe = removeNext; |
| 651 } |
| 652 } while ((first = next)); |
| 653 } |
| 654 |
| 655 template<typename TCurve> |
| 656 bool SkTSect<TCurve>::intersects(SkTSpan<TCurve>* span, const SkTSect* opp, |
| 657 const SkTSpan<TCurve>* oppSpan) const { |
| 658 bool check; // we ignore whether the end points are in common or not |
| 659 if (!span->intersects(oppSpan, &check)) { |
| 660 return false; |
| 661 } |
| 662 if (fActiveCount < COINCIDENT_SPAN_COUNT || opp->fActiveCount < COINCIDENT_S
PAN_COUNT) { |
| 663 return true; |
| 664 } |
| 665 return span->tightBoundsIntersects(oppSpan); |
| 666 } |
| 667 |
| 668 template<typename TCurve> |
| 669 void SkTSect<TCurve>::onCurveCheck(SkTSect* sect2, SkTSpan<TCurve>* first, SkTSp
an<TCurve>* last) { |
| 670 SkTSpan<TCurve>* work = first; |
| 671 first = NULL; |
| 672 do { |
| 673 if (work->fCoinStart.isCoincident()) { |
| 674 if (!first) { |
| 675 first = work; |
| 676 } |
| 677 } else if (first) { |
| 678 break; |
| 679 } |
| 680 if (work == last) { |
| 681 break; |
| 682 } |
| 683 work = work->fNext; |
| 684 SkASSERT(work); |
| 685 } while (true); |
| 686 if (!first) { |
| 687 return; |
| 688 } |
| 689 // march outwards to find limit of coincidence from here to previous and nex
t spans |
| 690 double startT = first->fStartT; |
| 691 double oppT; |
| 692 SkTSpan<TCurve>* prev = first->fPrev; |
| 693 if (prev) { |
| 694 double coinStart; |
| 695 if (binarySearchCoin(*sect2, startT, prev->fStartT - startT, &coinStart,
&oppT)) { |
| 696 if (coinStart < startT) { |
| 697 SkASSERT(prev->fStartT < coinStart && coinStart < prev->fEndT); |
| 698 SkTSpan<TCurve>* oppStart = sect2->fHead->find(oppT); |
| 699 if (oppStart->fStartT < oppT && oppT < oppStart->fEndT) { |
| 700 // split prev at coinStart if needed |
| 701 SkTSpan<TCurve>* half2 = addOne(); |
| 702 half2->splitAt(prev, coinStart); |
| 703 half2->initBounds(fCurve); |
| 704 prev->initBounds(fCurve); |
| 705 prev->fCoinEnd.markCoincident(); |
| 706 half2->fCoinStart.markCoincident(); |
| 707 half2->fCoinEnd.markCoincident(); |
| 708 // find span containing opposite t, and split that too |
| 709 SkTSpan<TCurve>* oppHalf = sect2->addOne(); |
| 710 oppHalf->splitAt(oppStart, oppT); |
| 711 oppHalf->initBounds(sect2->fCurve); |
| 712 oppStart->initBounds(sect2->fCurve); |
| 713 } else { |
| 714 SkASSERT(oppStart->fStartT == oppT || oppT == oppStart->fEnd
T); |
| 715 first->fStartT = coinStart; |
| 716 prev->fEndT = coinStart; |
| 717 first->initBounds(fCurve); |
| 718 prev->initBounds(fCurve); |
| 719 first->fCoinStart.markCoincident(); |
| 720 first->fCoinEnd.markCoincident(); |
| 721 } |
| 722 } |
| 723 } |
| 724 } |
| 725 if (!work->fCoinEnd.isCoincident()) { |
| 726 if (work->fEndT == 1) { |
| 727 SkDebugf("!"); |
| 728 } |
| 729 // SkASSERT(work->fEndT < 1); |
| 730 startT = work->fStartT; |
| 731 double coinEnd; |
| 732 if (binarySearchCoin(*sect2, startT, work->fEndT - startT, &coinEnd, &op
pT)) { |
| 733 if (coinEnd > startT) { |
| 734 SkTSpan<TCurve>* oppStart = sect2->fHead->find(oppT); |
| 735 if (oppStart->fStartT < oppT && oppT < oppStart->fEndT) { |
| 736 SkASSERT(coinEnd < work->fEndT); |
| 737 // split prev at coinEnd if needed |
| 738 SkTSpan<TCurve>* half2 = addOne(); |
| 739 half2->splitAt(work, coinEnd); |
| 740 half2->initBounds(fCurve); |
| 741 work->initBounds(fCurve); |
| 742 work->fCoinStart.markCoincident(); |
| 743 work->fCoinEnd.markCoincident(); |
| 744 half2->fCoinStart.markCoincident(); |
| 745 SkTSpan<TCurve>* oppHalf = sect2->addOne(); |
| 746 oppHalf->splitAt(oppStart, oppT); |
| 747 oppHalf->initBounds(sect2->fCurve); |
| 748 oppStart->initBounds(sect2->fCurve); |
| 749 } else { |
| 750 SkASSERT(oppStart->fStartT == oppT || oppT == oppStart->fEnd
T); |
| 751 SkTSpan<TCurve>* next = work->fNext; |
| 752 bool hasNext = next && work->fEndT == next->fStartT; |
| 753 work->fEndT = coinEnd; |
| 754 work->initBounds(fCurve); |
| 755 work->fCoinStart.markCoincident(); |
| 756 work->fCoinEnd.markCoincident(); |
| 757 if (hasNext) { |
| 758 next->fStartT = coinEnd; |
| 759 next->initBounds(fCurve); |
| 760 } |
| 761 } |
| 762 } |
| 763 } |
| 764 } |
| 765 } |
| 766 |
| 767 template<typename TCurve> |
| 768 void SkTSect<TCurve>::recoverCollapsed() { |
| 769 SkTSpan<TCurve>* deleted = fDeleted; |
| 770 while (deleted) { |
| 771 SkTSpan<TCurve>* delNext = deleted->fNext; |
| 772 if (deleted->fCollapsed) { |
| 773 SkTSpan<TCurve>** spanPtr = &fHead; |
| 774 while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) { |
| 775 spanPtr = &(*spanPtr)->fNext; |
| 776 } |
| 777 deleted->fNext = *spanPtr; |
| 778 *spanPtr = deleted; |
| 779 } |
| 780 deleted = delNext; |
| 781 } |
| 782 } |
| 783 |
| 784 template<typename TCurve> |
| 785 void SkTSect<TCurve>::removeSpan(SkTSpan<TCurve>* span) { |
| 786 SkTSpan<TCurve>* prev = span->fPrev; |
| 787 SkTSpan<TCurve>* next = span->fNext; |
| 788 if (prev) { |
| 789 prev->fNext = next; |
| 790 if (next) { |
| 791 next->fPrev = prev; |
| 792 } |
| 793 } else { |
| 794 fHead = next; |
| 795 if (next) { |
| 796 next->fPrev = NULL; |
| 797 } |
| 798 } |
| 799 --fActiveCount; |
| 800 span->fNext = fDeleted; |
| 801 fDeleted = span; |
| 802 #if DEBUG_T_SECT |
| 803 SkASSERT(!span->fDebugDeleted); |
| 804 span->fDebugDeleted = true; |
| 805 #endif |
| 806 } |
| 807 |
| 808 template<typename TCurve> |
| 809 void SkTSect<TCurve>::removeOne(const SkTSpan<TCurve>* test, SkTSpan<TCurve>* sp
an) { |
| 810 int last = span->fBounded.count() - 1; |
| 811 for (int index = 0; index <= last; ++index) { |
| 812 if (span->fBounded[index] == test) { |
| 813 span->fBounded.removeShuffle(index); |
| 814 if (!last) { |
| 815 removeSpan(span); |
| 816 } |
| 817 return; |
| 818 } |
| 819 } |
| 820 } |
| 821 |
| 822 template<typename TCurve> |
| 823 void SkTSect<TCurve>::removeSpans(SkTSpan<TCurve>* span, SkTSect<TCurve>* opp) { |
| 824 int count = span->fBounded.count(); |
| 825 for (int index = 0; index < count; ++index) { |
| 826 SkTSpan<TCurve>* bounded = span->fBounded[0]; |
| 827 removeOne(bounded, span); // shuffles last into position 0 |
| 828 opp->removeOne(span, bounded); |
| 829 } |
| 830 } |
| 831 |
| 832 template<typename TCurve> |
| 833 void SkTSect<TCurve>::setPerp(const TCurve& opp, SkTSpan<TCurve>* first, SkTSpan
<TCurve>* last) { |
| 834 SkTSpan<TCurve>* work = first; |
| 835 if (!work->fHasPerp) { |
| 836 work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp); |
| 837 } |
| 838 do { |
| 839 if (!work->fHasPerp) { |
| 840 work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPoi
ntLast], opp); |
| 841 work->fHasPerp = true; |
| 842 } |
| 843 if (work == last) { |
| 844 break; |
| 845 } |
| 846 SkTSpan<TCurve>* last = work; |
| 847 work = work->fNext; |
| 848 SkASSERT(work); |
| 849 if (!work->fHasPerp) { |
| 850 work->fCoinStart = last->fCoinEnd; |
| 851 } |
| 852 } while (true); |
| 853 } |
| 854 |
| 855 template<typename TCurve> |
| 856 const SkTSpan<TCurve>* SkTSect<TCurve>::tail() const { |
| 857 const SkTSpan<TCurve>* result = fHead; |
| 858 const SkTSpan<TCurve>* next = fHead; |
| 859 while ((next = next->fNext)) { |
| 860 if (next->fEndT > result->fEndT) { |
| 861 result = next; |
| 862 } |
| 863 } |
| 864 return result; |
| 865 } |
| 866 |
| 867 /* Each span has a range of opposite spans it intersects. After the span is spli
t in two, |
| 868 adjust the range to its new size */ |
| 869 template<typename TCurve> |
| 870 void SkTSect<TCurve>::trim(SkTSpan<TCurve>* span, SkTSect* opp) { |
| 871 span->initBounds(fCurve); |
| 872 int count = span->fBounded.count(); |
| 873 for (int index = 0; index < count; ) { |
| 874 SkTSpan<TCurve>* test = span->fBounded[index]; |
| 875 bool sects = intersects(span, opp, test); |
| 876 if (sects) { |
| 877 ++index; |
| 878 } else { |
| 879 removeOne(test, span); |
| 880 opp->removeOne(span, test); |
| 881 --count; |
| 882 } |
| 883 } |
| 884 } |
| 885 |
| 886 #if DEBUG_T_SECT |
| 887 template<typename TCurve> |
| 888 void SkTSect<TCurve>::validate() const { |
| 889 int count = 0; |
| 890 if (fHead) { |
| 891 const SkTSpan<TCurve>* span = fHead; |
| 892 SkASSERT(!span->fPrev); |
| 893 double last = 0; |
| 894 do { |
| 895 span->validate(); |
| 896 SkASSERT(span->fStartT >= last); |
| 897 last = span->fEndT; |
| 898 ++count; |
| 899 } while ((span = span->fNext) != NULL); |
| 900 } |
| 901 SkASSERT(count == fActiveCount); |
| 902 SkASSERT(fActiveCount <= fDebugAllocatedCount); |
| 903 int deletedCount = 0; |
| 904 const SkTSpan<TCurve>* deleted = fDeleted; |
| 905 while (deleted) { |
| 906 ++deletedCount; |
| 907 deleted = deleted->fNext; |
| 908 } |
| 909 SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount); |
| 910 } |
| 911 #endif |
| 912 |
| 913 template<typename TCurve> |
| 914 int SkTSect<TCurve>::EndsEqual(const SkTSect* sect1, const SkTSect* sect2, |
| 915 SkIntersections* intersections) { |
| 916 int zeroOneSet = 0; |
| 917 // check for zero |
| 918 if (sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) { |
| 919 zeroOneSet |= kZeroS1Set | kZeroS2Set; |
| 920 if (sect1->fCurve[0] != sect2->fCurve[0]) { |
| 921 intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]); |
| 922 } else { |
| 923 intersections->insert(0, 0, sect1->fCurve[0]); |
| 924 } |
| 925 } |
| 926 if (sect1->fCurve[0].approximatelyEqual(sect2->fCurve[TCurve::kPointLast]))
{ |
| 927 zeroOneSet |= kZeroS1Set | kOneS2Set; |
| 928 if (sect1->fCurve[0] != sect2->fCurve[TCurve::kPointLast]) { |
| 929 intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[TCur
ve::kPointLast]); |
| 930 } else { |
| 931 intersections->insert(0, 1, sect1->fCurve[0]); |
| 932 } |
| 933 } |
| 934 // check for one |
| 935 if (sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0]))
{ |
| 936 zeroOneSet |= kOneS1Set | kZeroS2Set; |
| 937 if (sect1->fCurve[TCurve::kPointLast] != sect2->fCurve[0]) { |
| 938 intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], s
ect2->fCurve[0]); |
| 939 } else { |
| 940 intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]); |
| 941 } |
| 942 } |
| 943 if (sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[TCurv
e::kPointLast])) { |
| 944 zeroOneSet |= kOneS1Set | kOneS2Set; |
| 945 if (sect1->fCurve[TCurve::kPointLast] != sect2->fCurve[TCurve::kPointLas
t]) { |
| 946 intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast], |
| 947 sect2->fCurve[TCurve::kPointLast]); |
| 948 } else { |
| 949 intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]); |
| 950 } |
| 951 } |
| 952 return zeroOneSet; |
| 953 } |
| 954 |
| 955 template<typename TCurve> |
| 956 struct SkClosestRecord { |
| 957 void addIntersection(SkIntersections* intersections) const { |
| 958 double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT(); |
| 959 double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT(); |
| 960 intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]); |
| 961 } |
| 962 |
| 963 void findEnd(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2, |
| 964 int c1Index, int c2Index) { |
| 965 const TCurve& c1 = span1->part(); |
| 966 const TCurve& c2 = span2->part(); |
| 967 if (!c1[c1Index].approximatelyEqual(c2[c2Index])) { |
| 968 return; |
| 969 } |
| 970 double dist = c1[c1Index].distanceSquared(c2[c2Index]); |
| 971 if (fClosest < dist) { |
| 972 return; |
| 973 } |
| 974 fC1Span = span1; |
| 975 fC2Span = span2; |
| 976 fC1StartT = span1->startT(); |
| 977 fC1EndT = span1->endT(); |
| 978 fC2StartT = span2->startT(); |
| 979 fC2EndT = span2->endT(); |
| 980 fC1Index = c1Index; |
| 981 fC2Index = c2Index; |
| 982 fClosest = dist; |
| 983 } |
| 984 |
| 985 bool matesWith(const SkClosestRecord& mate) const { |
| 986 SkASSERT(fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->sta
rtT() |
| 987 || mate.fC1Span->endT() <= fC1Span->startT()); |
| 988 SkASSERT(fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->sta
rtT() |
| 989 || mate.fC2Span->endT() <= fC2Span->startT()); |
| 990 return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->start
T() |
| 991 || fC1Span->startT() == mate.fC1Span->endT() |
| 992 || fC2Span == mate.fC2Span |
| 993 || fC2Span->endT() == mate.fC2Span->startT() |
| 994 || fC2Span->startT() == mate.fC2Span->endT(); |
| 995 } |
| 996 |
| 997 void merge(const SkClosestRecord& mate) { |
| 998 fC1Span = mate.fC1Span; |
| 999 fC2Span = mate.fC2Span; |
| 1000 fClosest = mate.fClosest; |
| 1001 fC1Index = mate.fC1Index; |
| 1002 fC2Index = mate.fC2Index; |
| 1003 } |
| 1004 |
| 1005 void reset() { |
| 1006 fClosest = FLT_MAX; |
| 1007 SkDEBUGCODE(fC1Span = fC2Span = NULL); |
| 1008 SkDEBUGCODE(fC1Index = fC2Index = -1); |
| 1009 } |
| 1010 |
| 1011 void update(const SkClosestRecord& mate) { |
| 1012 fC1StartT = SkTMin(fC1StartT, mate.fC1StartT); |
| 1013 fC1EndT = SkTMax(fC1EndT, mate.fC1EndT); |
| 1014 fC2StartT = SkTMin(fC2StartT, mate.fC2StartT); |
| 1015 fC2EndT = SkTMax(fC2EndT, mate.fC2EndT); |
| 1016 } |
| 1017 |
| 1018 const SkTSpan<TCurve>* fC1Span; |
| 1019 const SkTSpan<TCurve>* fC2Span; |
| 1020 double fC1StartT; |
| 1021 double fC1EndT; |
| 1022 double fC2StartT; |
| 1023 double fC2EndT; |
| 1024 double fClosest; |
| 1025 int fC1Index; |
| 1026 int fC2Index; |
| 1027 }; |
| 1028 |
| 1029 template<typename TCurve> |
| 1030 struct SkClosestSect { |
| 1031 SkClosestSect() |
| 1032 : fUsed(0) { |
| 1033 fClosest.push_back().reset(); |
| 1034 } |
| 1035 |
| 1036 void find(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2) { |
| 1037 SkClosestRecord<TCurve>* record = &fClosest[fUsed]; |
| 1038 record->findEnd(span1, span2, 0, 0); |
| 1039 record->findEnd(span1, span2, 0, TCurve::kPointLast); |
| 1040 record->findEnd(span1, span2, TCurve::kPointLast, 0); |
| 1041 record->findEnd(span1, span2, TCurve::kPointLast, TCurve::kPointLast); |
| 1042 if (record->fClosest == FLT_MAX) { |
| 1043 return; |
| 1044 } |
| 1045 for (int index = 0; index < fUsed; ++index) { |
| 1046 SkClosestRecord<TCurve>* test = &fClosest[index]; |
| 1047 if (test->matesWith(*record)) { |
| 1048 if (test->fClosest > record->fClosest) { |
| 1049 test->merge(*record); |
| 1050 } |
| 1051 test->update(*record); |
| 1052 record->reset(); |
| 1053 return; |
| 1054 } |
| 1055 } |
| 1056 ++fUsed; |
| 1057 fClosest.push_back().reset(); |
| 1058 } |
| 1059 |
| 1060 void finish(SkIntersections* intersections) const { |
| 1061 for (int index = 0; index < fUsed; ++index) { |
| 1062 const SkClosestRecord<TCurve>& test = fClosest[index]; |
| 1063 test.addIntersection(intersections); |
| 1064 } |
| 1065 } |
| 1066 |
| 1067 // this is oversized by one so that an extra record can merge into final one |
| 1068 SkSTArray<TCurve::kMaxIntersections + 1, SkClosestRecord<TCurve>, true> fClo
sest; |
| 1069 int fUsed; |
| 1070 }; |
| 1071 |
| 1072 // returns true if the rect is too small to consider |
| 1073 template<typename TCurve> |
| 1074 void SkTSect<TCurve>::BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersectio
ns* intersections) { |
| 1075 intersections->reset(); |
| 1076 intersections->setMax(TCurve::kMaxIntersections); |
| 1077 SkTSpan<TCurve>* span1 = sect1->fHead; |
| 1078 SkTSpan<TCurve>* span2 = sect2->fHead; |
| 1079 bool check; |
| 1080 if (!span1->intersects(span2, &check)) { |
| 1081 return; |
| 1082 } |
| 1083 if (check) { |
| 1084 (void) EndsEqual(sect1, sect2, intersections); |
| 1085 return; |
| 1086 } |
| 1087 span1->fBounded.push_back() = span2; |
| 1088 span2->fBounded.push_back() = span1; |
| 1089 do { |
| 1090 // find the largest bounds |
| 1091 SkTSpan<TCurve>* largest1 = sect1->boundsMax(); |
| 1092 if (!largest1) { |
| 1093 break; |
| 1094 } |
| 1095 SkTSpan<TCurve>* largest2 = sect2->boundsMax(); |
| 1096 bool split1 = !largest2 || (largest1 && (largest1->fBoundsMax > largest2
->fBoundsMax |
| 1097 || (!largest1->fCollapsed && largest2->fCollapsed))); |
| 1098 // split it |
| 1099 SkTSect* splitSect = split1 ? sect1 : sect2; |
| 1100 SkTSpan<TCurve>* half1 = split1 ? largest1 : largest2; |
| 1101 SkASSERT(half1); |
| 1102 if (half1->fCollapsed) { |
| 1103 break; |
| 1104 } |
| 1105 // trim parts that don't intersect the opposite |
| 1106 SkTSpan<TCurve>* half2 = splitSect->addOne(); |
| 1107 SkTSect* unsplitSect = split1 ? sect2 : sect1; |
| 1108 if (!half2->split(half1)) { |
| 1109 break; |
| 1110 } |
| 1111 splitSect->trim(half1, unsplitSect); |
| 1112 splitSect->trim(half2, unsplitSect); |
| 1113 // if there are 9 or more continuous spans on both sects, suspect coinci
dence |
| 1114 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT |
| 1115 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { |
| 1116 sect1->coincidentCheck(sect2); |
| 1117 } |
| 1118 #if DEBUG_T_SECT |
| 1119 sect1->validate(); |
| 1120 sect2->validate(); |
| 1121 #endif |
| 1122 #if DEBUG_T_SECT_DUMP > 1 |
| 1123 sect1->dumpBoth(*sect2); |
| 1124 #endif |
| 1125 if (!sect1->fHead || !sect2->fHead) { |
| 1126 return; |
| 1127 } |
| 1128 } while (true); |
| 1129 if (sect1->fActiveCount >= 2 && sect2->fActiveCount >= 2) { |
| 1130 // check for coincidence |
| 1131 SkTSpan<TCurve>* first = sect1->fHead; |
| 1132 do { |
| 1133 if (!first->fCoinStart.isCoincident()) { |
| 1134 continue; |
| 1135 } |
| 1136 int spanCount = 1; |
| 1137 SkTSpan<TCurve>* last = first; |
| 1138 while (last->fCoinEnd.isCoincident()) { |
| 1139 SkTSpan<TCurve>* next = last->fNext; |
| 1140 if (!next || !next->fCoinEnd.isCoincident()) { |
| 1141 break; |
| 1142 } |
| 1143 last = next; |
| 1144 ++spanCount; |
| 1145 } |
| 1146 if (spanCount < 2) { |
| 1147 first = last; |
| 1148 continue; |
| 1149 } |
| 1150 int index = intersections->insertCoincident(first->fStartT, first->f
CoinStart.perpT(), |
| 1151 first->fPart[0]); |
| 1152 if (intersections->insertCoincident(last->fEndT, last->fCoinEnd.perp
T(), |
| 1153 last->fPart[TCurve::kPointLast]) < 0) { |
| 1154 intersections->clearCoincidence(index); |
| 1155 } |
| 1156 } while ((first = first->fNext)); |
| 1157 } |
| 1158 int zeroOneSet = EndsEqual(sect1, sect2, intersections); |
| 1159 sect1->recoverCollapsed(); |
| 1160 sect2->recoverCollapsed(); |
| 1161 SkTSpan<TCurve>* result1 = sect1->fHead; |
| 1162 // check heads and tails for zero and ones and insert them if we haven't alr
eady done so |
| 1163 const SkTSpan<TCurve>* head1 = result1; |
| 1164 if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStart
T)) { |
| 1165 const SkDPoint& start1 = sect1->fCurve[0]; |
| 1166 double t = head1->closestBoundedT(start1); |
| 1167 if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) { |
| 1168 intersections->insert(0, t, start1); |
| 1169 } |
| 1170 } |
| 1171 const SkTSpan<TCurve>* head2 = sect2->fHead; |
| 1172 if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStart
T)) { |
| 1173 const SkDPoint& start2 = sect2->fCurve[0]; |
| 1174 double t = head2->closestBoundedT(start2); |
| 1175 if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) { |
| 1176 intersections->insert(t, 0, start2); |
| 1177 } |
| 1178 } |
| 1179 const SkTSpan<TCurve>* tail1 = sect1->tail(); |
| 1180 if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT
)) { |
| 1181 const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast]; |
| 1182 double t = tail1->closestBoundedT(end1); |
| 1183 if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) { |
| 1184 intersections->insert(1, t, end1); |
| 1185 } |
| 1186 } |
| 1187 const SkTSpan<TCurve>* tail2 = sect2->tail(); |
| 1188 if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT
)) { |
| 1189 const SkDPoint& end2 = sect2->fCurve[TCurve::kPointLast]; |
| 1190 double t = tail2->closestBoundedT(end2); |
| 1191 if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) { |
| 1192 intersections->insert(t, 1, end2); |
| 1193 } |
| 1194 } |
| 1195 SkClosestSect<TCurve> closest; |
| 1196 do { |
| 1197 while (result1 && result1->fCoinStart.isCoincident() && result1->fCoinEn
d.isCoincident()) { |
| 1198 result1 = result1->fNext; |
| 1199 } |
| 1200 if (!result1) { |
| 1201 break; |
| 1202 } |
| 1203 SkTSpan<TCurve>* result2 = sect2->fHead; |
| 1204 while (result2) { |
| 1205 closest.find(result1, result2); |
| 1206 result2 = result2->fNext; |
| 1207 } |
| 1208 |
| 1209 } while ((result1 = result1->fNext)); |
| 1210 closest.finish(intersections); |
| 1211 } |
OLD | NEW |