| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkOpCoincidence.h" | 7 #include "SkOpCoincidence.h" |
| 8 #include "SkOpContour.h" | 8 #include "SkOpContour.h" |
| 9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
| 10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
| 11 | 11 |
| 12 #define FAIL_IF(cond) do { if (cond) return false; } while (false) |
| 13 |
| 12 /* | 14 /* |
| 13 After computing raw intersections, post process all segments to: | 15 After computing raw intersections, post process all segments to: |
| 14 - find small collections of points that can be collapsed to a single point | 16 - find small collections of points that can be collapsed to a single point |
| 15 - find missing intersections to resolve differences caused by different algorith
ms | 17 - find missing intersections to resolve differences caused by different algorith
ms |
| 16 | 18 |
| 17 Consider segments containing tiny or small intervals. Consider coincident segmen
ts | 19 Consider segments containing tiny or small intervals. Consider coincident segmen
ts |
| 18 because coincidence finds intersections through distance measurement that non-co
incident | 20 because coincidence finds intersections through distance measurement that non-co
incident |
| 19 intersection tests cannot. | 21 intersection tests cannot. |
| 20 */ | 22 */ |
| 21 | 23 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 | 154 |
| 153 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
Winding) { | 155 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
Winding) { |
| 154 int maxWinding; | 156 int maxWinding; |
| 155 setUpWinding(start, end, &maxWinding, sumWinding); | 157 setUpWinding(start, end, &maxWinding, sumWinding); |
| 156 bool from = maxWinding != 0; | 158 bool from = maxWinding != 0; |
| 157 bool to = *sumWinding != 0; | 159 bool to = *sumWinding != 0; |
| 158 bool result = gUnaryActiveEdge[from][to]; | 160 bool result = gUnaryActiveEdge[from][to]; |
| 159 return result; | 161 return result; |
| 160 } | 162 } |
| 161 | 163 |
| 162 void SkOpSegment::addAlignIntersection(SkOpPtT& endPtT, SkPoint& oldPt, | |
| 163 SkOpContourHead* contourList, SkChunkAlloc* allocator) { | |
| 164 const SkPoint& newPt = endPtT.fPt; | |
| 165 if (newPt == oldPt) { | |
| 166 return; | |
| 167 } | |
| 168 SkPoint line[2] = { newPt, oldPt }; | |
| 169 SkPathOpsBounds lineBounds; | |
| 170 lineBounds.setBounds(line, 2); | |
| 171 SkDLine aLine; | |
| 172 aLine.set(line); | |
| 173 SkOpContour* current = contourList; | |
| 174 do { | |
| 175 if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) { | |
| 176 continue; | |
| 177 } | |
| 178 SkOpSegment* segment = current->first(); | |
| 179 do { | |
| 180 if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) { | |
| 181 continue; | |
| 182 } | |
| 183 if (newPt == segment->fPts[0]) { | |
| 184 continue; | |
| 185 } | |
| 186 if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { | |
| 187 continue; | |
| 188 } | |
| 189 if (oldPt == segment->fPts[0]) { | |
| 190 continue; | |
| 191 } | |
| 192 if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { | |
| 193 continue; | |
| 194 } | |
| 195 if (endPtT.contains(segment)) { | |
| 196 continue; | |
| 197 } | |
| 198 SkIntersections i; | |
| 199 switch (segment->fVerb) { | |
| 200 case SkPath::kLine_Verb: { | |
| 201 SkDLine bLine; | |
| 202 bLine.set(segment->fPts); | |
| 203 i.intersect(bLine, aLine); | |
| 204 } break; | |
| 205 case SkPath::kQuad_Verb: { | |
| 206 SkDQuad bQuad; | |
| 207 bQuad.set(segment->fPts); | |
| 208 i.intersect(bQuad, aLine); | |
| 209 } break; | |
| 210 case SkPath::kConic_Verb: { | |
| 211 SkDConic bConic; | |
| 212 bConic.set(segment->fPts, segment->fWeight); | |
| 213 i.intersect(bConic, aLine); | |
| 214 } break; | |
| 215 case SkPath::kCubic_Verb: { | |
| 216 SkDCubic bCubic; | |
| 217 bCubic.set(segment->fPts); | |
| 218 i.intersect(bCubic, aLine); | |
| 219 } break; | |
| 220 default: | |
| 221 SkASSERT(0); | |
| 222 } | |
| 223 if (i.used()) { | |
| 224 SkASSERT(i.used() == 1); | |
| 225 SkASSERT(!zero_or_one(i[0][0])); | |
| 226 SkOpSpanBase* checkSpan = fHead.next(); | |
| 227 while (!checkSpan->final()) { | |
| 228 if (checkSpan->contains(segment)) { | |
| 229 goto nextSegment; | |
| 230 } | |
| 231 checkSpan = checkSpan->upCast()->next(); | |
| 232 } | |
| 233 SkOpPtT* ptT = segment->addT(i[0][0], SkOpSegment::kAllowAlias,
allocator); | |
| 234 ptT->fPt = newPt; | |
| 235 endPtT.addOpp(ptT); | |
| 236 } | |
| 237 nextSegment: | |
| 238 ; | |
| 239 } while ((segment = segment->next())); | |
| 240 } while ((current = current->next())); | |
| 241 } | |
| 242 | |
| 243 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, | 164 bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 244 SkPathWriter* path) const { | 165 SkPathWriter* path) const { |
| 245 if (start->starter(end)->alreadyAdded()) { | 166 if (start->starter(end)->alreadyAdded()) { |
| 167 SkDEBUGF(("same curve added twice aborted pathops\n")); |
| 246 return false; | 168 return false; |
| 247 } | 169 } |
| 248 SkOpCurve edge; | 170 SkOpCurve edge; |
| 249 const SkPoint* ePtr; | 171 const SkPoint* ePtr; |
| 250 SkScalar eWeight; | 172 SkScalar eWeight; |
| 251 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)
) { | 173 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)
) { |
| 252 ePtr = fPts; | 174 ePtr = fPts; |
| 253 eWeight = fWeight; | 175 eWeight = fWeight; |
| 254 } else { | 176 } else { |
| 255 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) | 177 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 case SkPath::kCubic_Verb: | 213 case SkPath::kCubic_Verb: |
| 292 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); | 214 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); |
| 293 break; | 215 break; |
| 294 default: | 216 default: |
| 295 SkASSERT(0); | 217 SkASSERT(0); |
| 296 } | 218 } |
| 297 } | 219 } |
| 298 return true; | 220 return true; |
| 299 } | 221 } |
| 300 | 222 |
| 301 SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* alloc
ator) { | 223 const SkOpPtT* SkOpSegment::existing(double t, const SkOpSegment* opp) const { |
| 302 SkOpSpanBase* existing = nullptr; | 224 const SkOpSpanBase* test = &fHead; |
| 303 SkOpSpanBase* test = &fHead; | 225 const SkOpPtT* testPtT; |
| 304 double testT; | 226 SkPoint pt = this->ptAtT(t); |
| 305 do { | 227 do { |
| 306 if ((testT = test->ptT()->fT) >= t) { | 228 testPtT = test->ptT(); |
| 307 if (testT == t) { | 229 if (testPtT->fT == t) { |
| 308 existing = test; | |
| 309 } | |
| 310 break; | 230 break; |
| 311 } | 231 } |
| 232 if (!this->match(testPtT, this, t, pt, opp ? kAllowAliasMatch : kNoAlias
Match)) { |
| 233 if (t < testPtT->fT) { |
| 234 return nullptr; |
| 235 } |
| 236 continue; |
| 237 } |
| 238 if (!opp) { |
| 239 return testPtT; |
| 240 } |
| 241 const SkOpPtT* loop = testPtT->next(); |
| 242 while (loop != testPtT) { |
| 243 if (loop->segment() == this && loop->fT == t && loop->fPt == pt) { |
| 244 goto foundMatch; |
| 245 } |
| 246 loop = loop->next(); |
| 247 } |
| 248 return nullptr; |
| 312 } while ((test = test->upCast()->next())); | 249 } while ((test = test->upCast()->next())); |
| 313 SkOpPtT* result; | 250 foundMatch: |
| 314 if (existing && existing->contains(opp)) { | 251 return opp && !test->contains(opp) ? nullptr : testPtT; |
| 315 result = existing->ptT(); | |
| 316 } else { | |
| 317 result = this->addT(t, SkOpSegment::kNoAlias, allocator); | |
| 318 } | |
| 319 SkASSERT(result); | |
| 320 return result; | |
| 321 } | 252 } |
| 322 | 253 |
| 323 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca
tor) { | 254 // break the span so that the coincident part does not change the angle of the r
emainder |
| 255 bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* start
Over) { |
| 256 if (this->contains(newT)) { |
| 257 return true; |
| 258 } |
| 259 SkOpPtT* newPtT = this->addT(newT, kAllowAliasMatch, startOver); |
| 260 if (!newPtT) { |
| 261 return false; |
| 262 } |
| 263 newPtT->fPt = this->ptAtT(newT); |
| 264 // const cast away to change linked list; pt/t values stays unchanged |
| 265 SkOpSpanBase* writableTest = const_cast<SkOpSpanBase*>(test); |
| 266 if (writableTest->ptT()->addOpp(newPtT)) { |
| 267 writableTest->checkForCollapsedCoincidence(); |
| 268 } |
| 269 return true; |
| 270 } |
| 271 |
| 272 // Please keep this in sync with debugAddT() |
| 273 SkOpPtT* SkOpSegment::addT(double t, AliasMatch allowAlias, bool* allocated) { |
| 324 debugValidate(); | 274 debugValidate(); |
| 325 SkPoint pt = this->ptAtT(t); | 275 SkPoint pt = this->ptAtT(t); |
| 326 SkOpSpanBase* span = &fHead; | 276 SkOpSpanBase* span = &fHead; |
| 327 do { | 277 do { |
| 328 SkOpPtT* result = span->ptT(); | 278 SkOpPtT* result = span->ptT(); |
| 329 SkOpPtT* loop; | 279 SkOpPtT* loop; |
| 330 bool duplicatePt; | 280 bool duplicatePt; |
| 331 if (t == result->fT) { | 281 if (t == result->fT) { |
| 332 goto bumpSpan; | 282 goto bumpSpan; |
| 333 } | 283 } |
| 334 if (this->match(result, this, t, pt)) { | 284 if (this->match(result, this, t, pt, allowAlias)) { |
| 335 // see if any existing alias matches segment, pt, and t | 285 // see if any existing alias matches segment, pt, and t |
| 336 loop = result->next(); | 286 loop = result->next(); |
| 337 duplicatePt = false; | 287 duplicatePt = false; |
| 338 while (loop != result) { | 288 while (loop != result) { |
| 339 bool ptMatch = loop->fPt == pt; | 289 bool ptMatch = loop->fPt == pt; |
| 340 if (loop->segment() == this && loop->fT == t && ptMatch) { | 290 if (loop->segment() == this && loop->fT == t && ptMatch) { |
| 341 goto bumpSpan; | 291 goto bumpSpan; |
| 342 } | 292 } |
| 343 duplicatePt |= ptMatch; | 293 duplicatePt |= ptMatch; |
| 344 loop = loop->next(); | 294 loop = loop->next(); |
| 345 } | 295 } |
| 346 if (kNoAlias == allowAlias) { | 296 if (kNoAliasMatch == allowAlias) { |
| 347 bumpSpan: | 297 bumpSpan: |
| 348 span->bumpSpanAdds(); | 298 span->bumpSpanAdds(); |
| 349 return result; | 299 return result; |
| 350 } | 300 } |
| 351 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator); | 301 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(this->globalState
()->allocator()); |
| 352 alias->init(result->span(), t, pt, duplicatePt); | 302 alias->init(result->span(), t, pt, duplicatePt); |
| 353 result->insert(alias); | 303 result->insert(alias); |
| 354 result->span()->unaligned(); | 304 result->span()->unaligned(); |
| 355 this->debugValidate(); | 305 this->debugValidate(); |
| 356 #if DEBUG_ADD_T | 306 #if DEBUG_ADD_T |
| 357 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, | 307 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, |
| 358 alias->segment()->debugID(), alias->span()->debugID()); | 308 alias->segment()->debugID(), alias->span()->debugID()); |
| 359 #endif | 309 #endif |
| 360 span->bumpSpanAdds(); | 310 span->bumpSpanAdds(); |
| 311 if (allocated) { |
| 312 *allocated = true; |
| 313 } |
| 361 return alias; | 314 return alias; |
| 362 } | 315 } |
| 363 if (t < result->fT) { | 316 if (t < result->fT) { |
| 364 SkOpSpan* prev = result->span()->prev(); | 317 SkOpSpan* prev = result->span()->prev(); |
| 365 if (!prev) { | 318 if (!prev) { |
| 366 return nullptr; | 319 return nullptr; |
| 367 } | 320 } |
| 368 SkOpSpan* span = insert(prev, allocator); | 321 SkOpSpan* span = insert(prev); |
| 369 span->init(this, prev, t, pt); | 322 span->init(this, prev, t, pt); |
| 370 this->debugValidate(); | 323 this->debugValidate(); |
| 371 #if DEBUG_ADD_T | 324 #if DEBUG_ADD_T |
| 372 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, | 325 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, |
| 373 span->segment()->debugID(), span->debugID()); | 326 span->segment()->debugID(), span->debugID()); |
| 374 #endif | 327 #endif |
| 375 span->bumpSpanAdds(); | 328 span->bumpSpanAdds(); |
| 329 if (allocated) { |
| 330 *allocated = true; |
| 331 } |
| 376 return span->ptT(); | 332 return span->ptT(); |
| 377 } | 333 } |
| 378 SkASSERT(span != &fTail); | 334 SkASSERT(span != &fTail); |
| 379 } while ((span = span->upCast()->next())); | 335 } while ((span = span->upCast()->next())); |
| 380 SkASSERT(0); | 336 SkASSERT(0); |
| 381 return nullptr; | 337 return nullptr; |
| 382 } | 338 } |
| 383 | 339 |
| 384 // choose a solitary t and pt value; remove aliases; align the opposite ends | 340 void SkOpSegment::calcAngles() { |
| 385 void SkOpSegment::align() { | |
| 386 debugValidate(); | |
| 387 SkOpSpanBase* span = &fHead; | |
| 388 if (!span->aligned()) { | |
| 389 span->alignEnd(0, fPts[0]); | |
| 390 } | |
| 391 while ((span = span->upCast()->next())) { | |
| 392 if (span == &fTail) { | |
| 393 break; | |
| 394 } | |
| 395 span->align(); | |
| 396 } | |
| 397 if (!span->aligned()) { | |
| 398 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); | |
| 399 } | |
| 400 if (this->collapsed()) { | |
| 401 SkOpSpan* span = &fHead; | |
| 402 do { | |
| 403 span->setWindValue(0); | |
| 404 span->setOppValue(0); | |
| 405 this->markDone(span); | |
| 406 } while ((span = span->next()->upCastable())); | |
| 407 } | |
| 408 debugValidate(); | |
| 409 } | |
| 410 | |
| 411 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) { | |
| 412 bool activePrior = !fHead.isCanceled(); | 341 bool activePrior = !fHead.isCanceled(); |
| 413 if (activePrior && !fHead.simple()) { | 342 if (activePrior && !fHead.simple()) { |
| 414 addStartSpan(allocator); | 343 addStartSpan(); |
| 415 } | 344 } |
| 416 SkOpSpan* prior = &fHead; | 345 SkOpSpan* prior = &fHead; |
| 417 SkOpSpanBase* spanBase = fHead.next(); | 346 SkOpSpanBase* spanBase = fHead.next(); |
| 418 while (spanBase != &fTail) { | 347 while (spanBase != &fTail) { |
| 419 if (activePrior) { | 348 if (activePrior) { |
| 420 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato
r); | 349 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate( |
| 350 this->globalState()->allocator()); |
| 421 priorAngle->set(spanBase, prior); | 351 priorAngle->set(spanBase, prior); |
| 422 spanBase->setFromAngle(priorAngle); | 352 spanBase->setFromAngle(priorAngle); |
| 423 } | 353 } |
| 424 SkOpSpan* span = spanBase->upCast(); | 354 SkOpSpan* span = spanBase->upCast(); |
| 425 bool active = !span->isCanceled(); | 355 bool active = !span->isCanceled(); |
| 426 SkOpSpanBase* next = span->next(); | 356 SkOpSpanBase* next = span->next(); |
| 427 if (active) { | 357 if (active) { |
| 428 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); | 358 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate( |
| 359 this->globalState()->allocator()); |
| 429 angle->set(span, next); | 360 angle->set(span, next); |
| 430 span->setToAngle(angle); | 361 span->setToAngle(angle); |
| 431 } | 362 } |
| 432 activePrior = active; | 363 activePrior = active; |
| 433 prior = span; | 364 prior = span; |
| 434 spanBase = next; | 365 spanBase = next; |
| 435 } | 366 } |
| 436 if (activePrior && !fTail.simple()) { | 367 if (activePrior && !fTail.simple()) { |
| 437 addEndSpan(allocator); | 368 addEndSpan(); |
| 438 } | 369 } |
| 439 } | 370 } |
| 440 | 371 |
| 372 // Please keep this in sync with debugClearAll() |
| 373 void SkOpSegment::clearAll() { |
| 374 SkOpSpan* span = &fHead; |
| 375 do { |
| 376 this->clearOne(span); |
| 377 } while ((span = span->next()->upCastable())); |
| 378 this->globalState()->coincidence()->release(this); |
| 379 } |
| 380 |
| 381 // Please keep this in sync with debugClearOne() |
| 382 void SkOpSegment::clearOne(SkOpSpan* span) { |
| 383 span->setWindValue(0); |
| 384 span->setOppValue(0); |
| 385 this->markDone(span); |
| 386 } |
| 387 |
| 388 // Quads and conics collapse if the end points are the same, because |
| 389 // the curve doesn't enclose an area. |
| 441 bool SkOpSegment::collapsed() const { | 390 bool SkOpSegment::collapsed() const { |
| 442 return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt(); | 391 // FIXME: cubics can have also collapsed -- need to check if the |
| 392 // control points are on a line with the end points |
| 393 return fVerb < SkPath::kCubic_Verb && fHead.pt() == fTail.pt(); |
| 443 } | 394 } |
| 444 | 395 |
| 445 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, | 396 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, |
| 446 SkOpAngle::IncludeType includeType) { | 397 SkOpAngle::IncludeType includeType) { |
| 447 SkOpSegment* baseSegment = baseAngle->segment(); | 398 SkOpSegment* baseSegment = baseAngle->segment(); |
| 448 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | 399 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); |
| 449 int sumSuWinding; | 400 int sumSuWinding; |
| 450 bool binary = includeType >= SkOpAngle::kBinarySingle; | 401 bool binary = includeType >= SkOpAngle::kBinarySingle; |
| 451 if (binary) { | 402 if (binary) { |
| 452 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); | 403 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 } | 515 } |
| 565 if (baseAngle) { | 516 if (baseAngle) { |
| 566 ComputeOneSumReverse(baseAngle, angle, includeType); | 517 ComputeOneSumReverse(baseAngle, angle, includeType); |
| 567 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : n
ullptr; | 518 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : n
ullptr; |
| 568 } | 519 } |
| 569 } while (prior != firstAngle); | 520 } while (prior != firstAngle); |
| 570 } | 521 } |
| 571 return start->starter(end)->windSum(); | 522 return start->starter(end)->windSum(); |
| 572 } | 523 } |
| 573 | 524 |
| 525 bool SkOpSegment::contains(double newT) const { |
| 526 const SkOpSpanBase* spanBase = &fHead; |
| 527 do { |
| 528 if (spanBase->ptT()->contains(this, newT)) { |
| 529 return true; |
| 530 } |
| 531 if (spanBase == &fTail) { |
| 532 break; |
| 533 } |
| 534 spanBase = spanBase->upCast()->next(); |
| 535 } while (true); |
| 536 return false; |
| 537 } |
| 538 |
| 574 void SkOpSegment::release(const SkOpSpan* span) { | 539 void SkOpSegment::release(const SkOpSpan* span) { |
| 575 if (span->done()) { | 540 if (span->done()) { |
| 576 --fDoneCount; | 541 --fDoneCount; |
| 577 } | 542 } |
| 578 --fCount; | 543 --fCount; |
| 579 SkASSERT(fCount >= fDoneCount); | 544 SkASSERT(this->globalState()->debugSkipAssert() || fCount >= fDoneCount); |
| 580 } | 545 } |
| 581 | 546 |
| 582 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const { | 547 double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const { |
| 583 SkDPoint testPt = this->dPtAtT(t); | 548 SkDPoint testPt = this->dPtAtT(t); |
| 584 SkDLine testPerp = {{ testPt, testPt }}; | 549 SkDLine testPerp = {{ testPt, testPt }}; |
| 585 SkDVector slope = this->dSlopeAtT(t); | 550 SkDVector slope = this->dSlopeAtT(t); |
| 586 testPerp[1].fX += slope.fY; | 551 testPerp[1].fX += slope.fY; |
| 587 testPerp[1].fY -= slope.fX; | 552 testPerp[1].fY -= slope.fX; |
| 588 SkIntersections i; | 553 SkIntersections i; |
| 589 const SkOpSegment* oppSegment = oppAngle->segment(); | 554 const SkOpSegment* oppSegment = oppAngle->segment(); |
| 590 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weig
ht(), testPerp, &i); | 555 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weig
ht(), testPerp, &i); |
| 591 double closestDistSq = SK_ScalarInfinity; | 556 double closestDistSq = SK_ScalarInfinity; |
| 592 for (int index = 0; index < i.used(); ++index) { | 557 for (int index = 0; index < i.used(); ++index) { |
| 593 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t()))
{ | 558 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t()))
{ |
| 594 continue; | 559 continue; |
| 595 } | 560 } |
| 596 double testDistSq = testPt.distanceSquared(i.pt(index)); | 561 double testDistSq = testPt.distanceSquared(i.pt(index)); |
| 597 if (closestDistSq > testDistSq) { | 562 if (closestDistSq > testDistSq) { |
| 598 closestDistSq = testDistSq; | 563 closestDistSq = testDistSq; |
| 599 } | 564 } |
| 600 } | 565 } |
| 601 return closestDistSq; | 566 return closestDistSq; |
| 602 } | 567 } |
| 603 | 568 |
| 604 void SkOpSegment::findCollapsed() { | |
| 605 if (fHead.contains(&fTail)) { | |
| 606 markAllDone(); | |
| 607 // move start and end to the same point | |
| 608 fHead.alignEnd(0, fHead.pt()); | |
| 609 fTail.setAligned(); | |
| 610 } | |
| 611 } | |
| 612 | |
| 613 /* | 569 /* |
| 614 The M and S variable name parts stand for the operators. | 570 The M and S variable name parts stand for the operators. |
| 615 Mi stands for Minuend (see wiki subtraction, analogous to difference) | 571 Mi stands for Minuend (see wiki subtraction, analogous to difference) |
| 616 Su stands for Subtrahend | 572 Su stands for Subtrahend |
| 617 The Opp variable name part designates that the value is for the Opposite operat
or. | 573 The Opp variable name part designates that the value is for the Opposite operat
or. |
| 618 Opposite values result from combining coincident spans. | 574 Opposite values result from combining coincident spans. |
| 619 */ | 575 */ |
| 620 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa
se** nextStart, | 576 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa
se** nextStart, |
| 621 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in
t xorSuMask) { | 577 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in
t xorSuMask) { |
| 622 SkOpSpanBase* start = *nextStart; | 578 SkOpSpanBase* start = *nextStart; |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 880 *nextEnd = foundAngle->end(); | 836 *nextEnd = foundAngle->end(); |
| 881 nextSegment = foundAngle->segment(); | 837 nextSegment = foundAngle->segment(); |
| 882 #if DEBUG_WINDING | 838 #if DEBUG_WINDING |
| 883 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 839 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
| 884 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 840 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
| 885 #endif | 841 #endif |
| 886 return nextSegment; | 842 return nextSegment; |
| 887 } | 843 } |
| 888 | 844 |
| 889 SkOpGlobalState* SkOpSegment::globalState() const { | 845 SkOpGlobalState* SkOpSegment::globalState() const { |
| 890 return contour()->globalState(); | 846 return contour()->globalState(); |
| 891 } | 847 } |
| 892 | 848 |
| 893 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
ath::Verb verb) { | 849 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
ath::Verb verb) { |
| 894 fContour = contour; | 850 fContour = contour; |
| 895 fNext = nullptr; | 851 fNext = nullptr; |
| 896 fOriginal[0] = pts[0]; | |
| 897 fOriginal[1] = pts[SkPathOpsVerbToPoints(verb)]; | |
| 898 fPts = pts; | 852 fPts = pts; |
| 899 fWeight = weight; | 853 fWeight = weight; |
| 900 fVerb = verb; | 854 fVerb = verb; |
| 901 fCount = 0; | 855 fCount = 0; |
| 902 fDoneCount = 0; | 856 fDoneCount = 0; |
| 903 fVisited = false; | 857 fVisited = false; |
| 904 SkOpSpan* zeroSpan = &fHead; | 858 SkOpSpan* zeroSpan = &fHead; |
| 905 zeroSpan->init(this, nullptr, 0, fPts[0]); | 859 zeroSpan->init(this, nullptr, 0, fPts[0]); |
| 906 SkOpSpanBase* oneSpan = &fTail; | 860 SkOpSpanBase* oneSpan = &fTail; |
| 907 zeroSpan->setNext(oneSpan); | 861 zeroSpan->setNext(oneSpan); |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1088 #if DEBUG_MARK_DONE | 1042 #if DEBUG_MARK_DONE |
| 1089 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); | 1043 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); |
| 1090 #endif | 1044 #endif |
| 1091 span->setWindSum(winding); | 1045 span->setWindSum(winding); |
| 1092 span->setOppSum(oppWinding); | 1046 span->setOppSum(oppWinding); |
| 1093 debugValidate(); | 1047 debugValidate(); |
| 1094 return true; | 1048 return true; |
| 1095 } | 1049 } |
| 1096 | 1050 |
| 1097 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub
le testT, | 1051 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub
le testT, |
| 1098 const SkPoint& testPt) const { | 1052 const SkPoint& testPt, AliasMatch aliasMatch) const { |
| 1099 const SkOpSegment* baseParent = base->segment(); | 1053 SkASSERT(this == base->segment()); |
| 1100 if (this == baseParent && this == testParent && precisely_equal(base->fT, te
stT)) { | 1054 if (this == testParent) { |
| 1101 return true; | 1055 if (precisely_equal(base->fT, testT)) { |
| 1056 return true; |
| 1057 } |
| 1102 } | 1058 } |
| 1103 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { | 1059 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { |
| 1104 return false; | 1060 return false; |
| 1105 } | 1061 } |
| 1106 return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt); | 1062 return this != testParent || !this->ptsDisjoint(base->fT, base->fPt, testT,
testPt); |
| 1107 } | 1063 } |
| 1108 | 1064 |
| 1109 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { | 1065 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { |
| 1110 if (last) { | 1066 if (last) { |
| 1111 *last = endSpan; | 1067 *last = endSpan; |
| 1112 } | 1068 } |
| 1113 return nullptr; | 1069 return nullptr; |
| 1114 } | 1070 } |
| 1115 | 1071 |
| 1116 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
pan** minPtr, | 1072 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
pan** minPtr, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1171 return set_last(last, endSpan); | 1127 return set_last(last, endSpan); |
| 1172 } | 1128 } |
| 1173 *startPtr = foundSpan; | 1129 *startPtr = foundSpan; |
| 1174 *stepPtr = foundStep; | 1130 *stepPtr = foundStep; |
| 1175 if (minPtr) { | 1131 if (minPtr) { |
| 1176 *minPtr = foundMin; | 1132 *minPtr = foundMin; |
| 1177 } | 1133 } |
| 1178 return other; | 1134 return other; |
| 1179 } | 1135 } |
| 1180 | 1136 |
| 1181 static void clear_visited(SkOpSpanBase* span) { | 1137 // Please keep this in sync with DebugClearVisited() |
| 1138 void SkOpSegment::ClearVisited(SkOpSpanBase* span) { |
| 1182 // reset visited flag back to false | 1139 // reset visited flag back to false |
| 1183 do { | 1140 do { |
| 1184 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; | 1141 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; |
| 1185 while ((ptT = ptT->next()) != stopPtT) { | 1142 while ((ptT = ptT->next()) != stopPtT) { |
| 1186 SkOpSegment* opp = ptT->segment(); | 1143 SkOpSegment* opp = ptT->segment(); |
| 1187 opp->resetVisited(); | 1144 opp->resetVisited(); |
| 1188 } | 1145 } |
| 1189 } while (!span->final() && (span = span->upCast()->next())); | 1146 } while (!span->final() && (span = span->upCast()->next())); |
| 1190 } | 1147 } |
| 1191 | 1148 |
| 1149 // Please keep this in sync with debugMissingCoincidence() |
| 1192 // look for pairs of undetected coincident curves | 1150 // look for pairs of undetected coincident curves |
| 1193 // assumes that segments going in have visited flag clear | 1151 // assumes that segments going in have visited flag clear |
| 1194 // curve/curve intersection should now do a pretty good job of finding coinciden
t runs so | 1152 // Even though pairs of curves correct detect coincident runs, a run may be miss
ed |
| 1195 // this may be only be necessary for line/curve pairs -- so skip unless this is
a line and the | 1153 // if the coincidence is a product of multiple intersections. For instance, give
n |
| 1196 // the opp is not a line | 1154 // curves A, B, and C: |
| 1197 bool SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
* allocator) { | 1155 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near |
| 1198 if (this->verb() != SkPath::kLine_Verb) { | 1156 // the end of C that the intersection is replaced with the end of C. |
| 1199 return false; | 1157 // Even though A-B correctly do not detect an intersection at point 2, |
| 1200 } | 1158 // the resulting run from point 1 to point 2 is coincident on A and B. |
| 1159 bool SkOpSegment::missingCoincidence() { |
| 1201 if (this->done()) { | 1160 if (this->done()) { |
| 1202 return false; | 1161 return false; |
| 1203 } | 1162 } |
| 1204 SkOpSpan* prior = nullptr; | 1163 SkOpSpan* prior = nullptr; |
| 1205 SkOpSpanBase* spanBase = &fHead; | 1164 SkOpSpanBase* spanBase = &fHead; |
| 1165 bool result = false; |
| 1206 do { | 1166 do { |
| 1207 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; | 1167 SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; |
| 1208 SkASSERT(ptT->span() == spanBase); | 1168 SkASSERT(ptT->span() == spanBase); |
| 1209 while ((ptT = ptT->next()) != spanStopPtT) { | 1169 while ((ptT = ptT->next()) != spanStopPtT) { |
| 1210 if (ptT->deleted()) { | 1170 if (ptT->deleted()) { |
| 1211 continue; | 1171 continue; |
| 1212 } | 1172 } |
| 1213 SkOpSegment* opp = ptT->span()->segment(); | 1173 SkOpSegment* opp = ptT->span()->segment(); |
| 1214 // if (opp->verb() == SkPath::kLine_Verb) { | |
| 1215 // continue; | |
| 1216 // } | |
| 1217 if (opp->done()) { | 1174 if (opp->done()) { |
| 1218 continue; | 1175 continue; |
| 1219 } | 1176 } |
| 1220 // when opp is encounted the 1st time, continue; on 2nd encounter, l
ook for coincidence | 1177 // when opp is encounted the 1st time, continue; on 2nd encounter, l
ook for coincidence |
| 1221 if (!opp->visited()) { | 1178 if (!opp->visited()) { |
| 1222 continue; | 1179 continue; |
| 1223 } | 1180 } |
| 1224 if (spanBase == &fHead) { | 1181 if (spanBase == &fHead) { |
| 1225 continue; | 1182 continue; |
| 1226 } | 1183 } |
| 1184 if (ptT->segment() == this) { |
| 1185 continue; |
| 1186 } |
| 1227 SkOpSpan* span = spanBase->upCastable(); | 1187 SkOpSpan* span = spanBase->upCastable(); |
| 1228 // FIXME?: this assumes that if the opposite segment is coincident t
hen no more | 1188 // FIXME?: this assumes that if the opposite segment is coincident t
hen no more |
| 1229 // coincidence needs to be detected. This may not be true. | 1189 // coincidence needs to be detected. This may not be true. |
| 1230 if (span && span->containsCoincidence(opp)) { | 1190 if (span && span->containsCoincidence(opp)) { |
| 1231 continue; | |
| 1232 } | |
| 1233 if (spanBase->segment() == opp) { | |
| 1234 continue; | 1191 continue; |
| 1235 } | 1192 } |
| 1236 if (spanBase->containsCoinEnd(opp)) { | 1193 if (spanBase->containsCoinEnd(opp)) { |
| 1237 continue; | 1194 continue; |
| 1238 } | 1195 } |
| 1239 SkOpPtT* priorPtT = nullptr, * priorStopPtT; | 1196 SkOpPtT* priorPtT = nullptr, * priorStopPtT; |
| 1240 // find prior span containing opp segment | 1197 // find prior span containing opp segment |
| 1241 SkOpSegment* priorOpp = nullptr; | 1198 SkOpSegment* priorOpp = nullptr; |
| 1242 SkOpSpan* priorTest = spanBase->prev(); | 1199 SkOpSpan* priorTest = spanBase->prev(); |
| 1243 while (!priorOpp && priorTest) { | 1200 while (!priorOpp && priorTest) { |
| 1244 priorStopPtT = priorPtT = priorTest->ptT(); | 1201 priorStopPtT = priorPtT = priorTest->ptT(); |
| 1245 while ((priorPtT = priorPtT->next()) != priorStopPtT) { | 1202 while ((priorPtT = priorPtT->next()) != priorStopPtT) { |
| 1246 if (priorPtT->deleted()) { | 1203 if (priorPtT->deleted()) { |
| 1247 continue; | 1204 continue; |
| 1248 } | 1205 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1261 if (priorPtT == ptT) { | 1218 if (priorPtT == ptT) { |
| 1262 continue; | 1219 continue; |
| 1263 } | 1220 } |
| 1264 SkOpPtT* oppStart = prior->ptT(); | 1221 SkOpPtT* oppStart = prior->ptT(); |
| 1265 SkOpPtT* oppEnd = spanBase->ptT(); | 1222 SkOpPtT* oppEnd = spanBase->ptT(); |
| 1266 bool swapped = priorPtT->fT > ptT->fT; | 1223 bool swapped = priorPtT->fT > ptT->fT; |
| 1267 if (swapped) { | 1224 if (swapped) { |
| 1268 SkTSwap(priorPtT, ptT); | 1225 SkTSwap(priorPtT, ptT); |
| 1269 SkTSwap(oppStart, oppEnd); | 1226 SkTSwap(oppStart, oppEnd); |
| 1270 } | 1227 } |
| 1271 bool flipped = oppStart->fT > oppEnd->fT; | 1228 SkOpCoincidence* coincidences = this->globalState()->coincidence(); |
| 1272 bool coincident = false; | 1229 SkOpPtT* rootPriorPtT = priorPtT->span()->ptT(); |
| 1273 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)
) { | 1230 SkOpPtT* rootPtT = ptT->span()->ptT(); |
| 1231 SkOpPtT* rootOppStart = oppStart->span()->ptT(); |
| 1232 SkOpPtT* rootOppEnd = oppEnd->span()->ptT(); |
| 1233 if (coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, root
OppEnd)) { |
| 1274 goto swapBack; | 1234 goto swapBack; |
| 1275 } | 1235 } |
| 1276 if (opp->verb() == SkPath::kLine_Verb) { | 1236 if (this->testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase,
opp)) { |
| 1277 coincident = (SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppSta
rt->fPt) || | |
| 1278 SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppEnd->fPt)
) && | |
| 1279 (SkDPoint::ApproximatelyEqual(ptT->fPt, oppStart->fPt) |
| | |
| 1280 SkDPoint::ApproximatelyEqual(ptT->fPt, oppEnd->fPt)); | |
| 1281 } | |
| 1282 if (!coincident) { | |
| 1283 coincident = testForCoincidence(priorPtT, ptT, prior, spanBase,
opp, 5000); | |
| 1284 } | |
| 1285 if (coincident) { | |
| 1286 // mark coincidence | 1237 // mark coincidence |
| 1287 if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd) | 1238 #if DEBUG_COINCIDENCE_VERBOSE |
| 1288 && !coincidences->extend(oppStart, oppEnd, priorPtT, ptT
)) { | 1239 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n",
__FUNCTION__, |
| 1289 coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator
); | 1240 rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStar
t->debugID(), |
| 1241 rootOppEnd->debugID()); |
| 1242 #endif |
| 1243 if (!coincidences->extend(rootPriorPtT, rootPtT, rootOppStart, r
ootOppEnd)) { |
| 1244 coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootO
ppEnd); |
| 1290 } | 1245 } |
| 1291 clear_visited(&fHead); | 1246 #if DEBUG_COINCIDENCE |
| 1292 return true; | 1247 SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppSt
art, rootOppEnd)); |
| 1248 #endif |
| 1249 result = true; |
| 1293 } | 1250 } |
| 1294 swapBack: | 1251 swapBack: |
| 1295 if (swapped) { | 1252 if (swapped) { |
| 1296 SkTSwap(priorPtT, ptT); | 1253 SkTSwap(priorPtT, ptT); |
| 1297 } | 1254 } |
| 1298 } | 1255 } |
| 1299 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next(
))); | 1256 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next(
))); |
| 1300 clear_visited(&fHead); | 1257 ClearVisited(&fHead); |
| 1301 return false; | 1258 return result; |
| 1302 } | 1259 } |
| 1303 | 1260 |
| 1261 // please keep this in sync with debugMoveMultiples() |
| 1304 // if a span has more than one intersection, merge the other segments' span as n
eeded | 1262 // if a span has more than one intersection, merge the other segments' span as n
eeded |
| 1305 bool SkOpSegment::moveMultiples() { | 1263 bool SkOpSegment::moveMultiples() { |
| 1306 debugValidate(); | 1264 debugValidate(); |
| 1307 SkOpSpanBase* test = &fHead; | 1265 SkOpSpanBase* test = &fHead; |
| 1308 do { | 1266 do { |
| 1309 int addCount = test->spanAddsCount(); | 1267 int addCount = test->spanAddsCount(); |
| 1310 if (addCount < 1) { | 1268 FAIL_IF(addCount < 1); |
| 1311 return false; | |
| 1312 } | |
| 1313 if (addCount == 1) { | 1269 if (addCount == 1) { |
| 1314 continue; | 1270 continue; |
| 1315 } | 1271 } |
| 1316 SkOpPtT* startPtT = test->ptT(); | 1272 SkOpPtT* startPtT = test->ptT(); |
| 1317 SkOpPtT* testPtT = startPtT; | 1273 SkOpPtT* testPtT = startPtT; |
| 1318 do { // iterate through all spans associated with start | 1274 do { // iterate through all spans associated with start |
| 1319 SkOpSpanBase* oppSpan = testPtT->span(); | 1275 SkOpSpanBase* oppSpan = testPtT->span(); |
| 1320 if (oppSpan->spanAddsCount() == addCount) { | 1276 if (oppSpan->spanAddsCount() == addCount) { |
| 1321 continue; | 1277 continue; |
| 1322 } | 1278 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1385 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment-
>fHead) { | 1341 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment-
>fHead) { |
| 1386 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect
collapse | 1342 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect
collapse |
| 1387 SkASSERT(oppSpan != &oppSegment->fTail); | 1343 SkASSERT(oppSpan != &oppSegment->fTail); |
| 1388 oppTest->merge(oppSpan->upCast()); | 1344 oppTest->merge(oppSpan->upCast()); |
| 1389 } else { | 1345 } else { |
| 1390 oppSpan->merge(oppTest->upCast()); | 1346 oppSpan->merge(oppTest->upCast()); |
| 1391 } | 1347 } |
| 1392 oppSegment->debugValidate(); | 1348 oppSegment->debugValidate(); |
| 1393 goto checkNextSpan; | 1349 goto checkNextSpan; |
| 1394 } | 1350 } |
| 1395 tryNextSpan: | 1351 tryNextSpan: |
| 1396 ; | 1352 ; |
| 1397 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next())
); | 1353 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next())
); |
| 1398 } while ((testPtT = testPtT->next()) != startPtT); | 1354 } while ((testPtT = testPtT->next()) != startPtT); |
| 1399 checkNextSpan: | 1355 checkNextSpan: |
| 1400 ; | 1356 ; |
| 1401 } while ((test = test->final() ? nullptr : test->upCast()->next())); | 1357 } while ((test = test->final() ? nullptr : test->upCast()->next())); |
| 1402 debugValidate(); | 1358 debugValidate(); |
| 1403 return true; | 1359 return true; |
| 1404 } | 1360 } |
| 1405 | 1361 |
| 1362 // adjacent spans may have points close by |
| 1363 bool SkOpSegment::spansNearby(const SkOpSpanBase* refSpan, const SkOpSpanBase* c
heckSpan) const { |
| 1364 const SkOpPtT* refHead = refSpan->ptT(); |
| 1365 const SkOpPtT* checkHead = checkSpan->ptT(); |
| 1366 // if the first pt pair from adjacent spans are far apart, assume that all are f
ar enough apart |
| 1367 if (!SkDPoint::RoughlyEqual(refHead->fPt, checkHead->fPt)) { |
| 1368 #if DEBUG_COINCIDENCE |
| 1369 // verify that no combination of points are close |
| 1370 const SkOpPtT* dBugRef = refHead; |
| 1371 do { |
| 1372 const SkOpPtT* dBugCheck = checkHead; |
| 1373 do { |
| 1374 SkASSERT(!SkDPoint::ApproximatelyEqual(dBugRef->fPt, dBugCheck->
fPt)); |
| 1375 dBugCheck = dBugCheck->next(); |
| 1376 } while (dBugCheck != checkHead); |
| 1377 dBugRef = dBugRef->next(); |
| 1378 } while (dBugRef != refHead); |
| 1379 #endif |
| 1380 return false; |
| 1381 } |
| 1382 // check only unique points |
| 1383 SkScalar distSqBest = SK_ScalarMax; |
| 1384 const SkOpPtT* refBest = nullptr; |
| 1385 const SkOpPtT* checkBest = nullptr; |
| 1386 const SkOpPtT* ref = refHead; |
| 1387 do { |
| 1388 if (ref->deleted()) { |
| 1389 continue; |
| 1390 } |
| 1391 while (ref->ptAlreadySeen(refHead)) { |
| 1392 ref = ref->next(); |
| 1393 if (ref == refHead) { |
| 1394 goto doneCheckingDistance; |
| 1395 } |
| 1396 } |
| 1397 const SkOpPtT* check = checkHead; |
| 1398 const SkOpSegment* refSeg = ref->segment(); |
| 1399 do { |
| 1400 if (check->deleted()) { |
| 1401 continue; |
| 1402 } |
| 1403 while (check->ptAlreadySeen(checkHead)) { |
| 1404 check = check->next(); |
| 1405 if (check == checkHead) { |
| 1406 goto nextRef; |
| 1407 } |
| 1408 } |
| 1409 SkScalar distSq = ref->fPt.distanceToSqd(check->fPt); |
| 1410 if (distSqBest > distSq && (refSeg != check->segment() |
| 1411 || !refSeg->ptsDisjoint(*ref, *check))) { |
| 1412 distSqBest = distSq; |
| 1413 refBest = ref; |
| 1414 checkBest = check; |
| 1415 } |
| 1416 } while ((check = check->next()) != checkHead); |
| 1417 nextRef: |
| 1418 ; |
| 1419 } while ((ref = ref->next()) != refHead); |
| 1420 doneCheckingDistance: |
| 1421 return checkBest && refBest->segment()->match(refBest, checkBest->segment(),
checkBest->fT, |
| 1422 checkBest->fPt, kAllowAliasMatch); |
| 1423 } |
| 1424 |
| 1425 // Please keep this function in sync with debugMoveNearby() |
| 1406 // Move nearby t values and pts so they all hang off the same span. Alignment ha
ppens later. | 1426 // Move nearby t values and pts so they all hang off the same span. Alignment ha
ppens later. |
| 1407 void SkOpSegment::moveNearby() { | 1427 void SkOpSegment::moveNearby() { |
| 1408 debugValidate(); | 1428 debugValidate(); |
| 1409 SkOpSpanBase* spanS = &fHead; | 1429 // release undeleted spans pointing to this seg that are linked to the prima
ry span |
| 1430 SkOpSpanBase* spanBase = &fHead; |
| 1410 do { | 1431 do { |
| 1411 SkOpSpanBase* test = spanS->upCast()->next(); | 1432 SkOpPtT* ptT = spanBase->ptT(); |
| 1412 SkOpSpanBase* next; | 1433 const SkOpPtT* headPtT = ptT; |
| 1413 if (spanS->contains(test)) { | 1434 while ((ptT = ptT->next()) != headPtT) { |
| 1414 if (!test->final()) { | 1435 SkOpSpanBase* test = ptT->span(); |
| 1415 test->upCast()->release(spanS->ptT()); | 1436 if (ptT->segment() == this && !ptT->deleted() && test != spanBase |
| 1416 continue; | 1437 && test->ptT() == ptT) { |
| 1417 } else if (spanS != &fHead) { | 1438 if (test->final()) { |
| 1418 spanS->upCast()->release(test->ptT()); | 1439 if (spanBase == &fHead) { |
| 1419 spanS = test; | 1440 this->clearAll(); |
| 1420 continue; | 1441 return; |
| 1442 } |
| 1443 spanBase->upCast()->release(ptT); |
| 1444 } else if (test->prev()) { |
| 1445 test->upCast()->release(headPtT); |
| 1446 } |
| 1447 break; |
| 1421 } | 1448 } |
| 1422 } | 1449 } |
| 1423 do { // iterate through all spans associated with start | 1450 spanBase = spanBase->upCast()->next(); |
| 1424 SkOpPtT* startBase = spanS->ptT(); | 1451 } while (!spanBase->final()); |
| 1425 next = test->final() ? nullptr : test->upCast()->next(); | 1452 |
| 1426 do { | 1453 // This loop looks for adjacent spans which are near by |
| 1427 SkOpPtT* testBase = test->ptT(); | 1454 spanBase = &fHead; |
| 1428 do { | 1455 do { // iterate through all spans associated with start |
| 1429 if (startBase == testBase) { | 1456 SkOpSpanBase* test = spanBase->upCast()->next(); |
| 1430 goto checkNextSpan; | 1457 if (this->spansNearby(spanBase, test)) { |
| 1431 } | 1458 if (test->final()) { |
| 1432 if (testBase->duplicate()) { | 1459 if (spanBase->prev()) { |
| 1433 continue; | 1460 test->merge(spanBase->upCast()); |
| 1434 } | 1461 } else { |
| 1435 if (this->match(startBase, testBase->segment(), testBase->fT
, testBase->fPt)) { | 1462 this->clearAll(); |
| 1436 if (test == &this->fTail) { | 1463 return; |
| 1437 if (spanS == &fHead) { | 1464 } |
| 1438 debugValidate(); | 1465 } else { |
| 1439 return; // if this span has collapsed, remove i
t from parent | 1466 spanBase->merge(test->upCast()); |
| 1440 } | 1467 } |
| 1441 this->fTail.merge(spanS->upCast()); | 1468 } |
| 1442 debugValidate(); | 1469 spanBase = test; |
| 1443 return; | 1470 } while (!spanBase->final()); |
| 1444 } | |
| 1445 spanS->merge(test->upCast()); | |
| 1446 goto checkNextSpan; | |
| 1447 } | |
| 1448 } while ((testBase = testBase->next()) != test->ptT()); | |
| 1449 } while ((startBase = startBase->next()) != spanS->ptT()); | |
| 1450 checkNextSpan: | |
| 1451 ; | |
| 1452 } while ((test = next)); | |
| 1453 spanS = spanS->upCast()->next(); | |
| 1454 } while (!spanS->final()); | |
| 1455 debugValidate(); | 1471 debugValidate(); |
| 1456 } | 1472 } |
| 1457 | 1473 |
| 1458 bool SkOpSegment::operand() const { | 1474 bool SkOpSegment::operand() const { |
| 1459 return fContour->operand(); | 1475 return fContour->operand(); |
| 1460 } | 1476 } |
| 1461 | 1477 |
| 1462 bool SkOpSegment::oppXor() const { | 1478 bool SkOpSegment::oppXor() const { |
| 1463 return fContour->oppXor(); | 1479 return fContour->oppXor(); |
| 1464 } | 1480 } |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1672 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg
e->fQuad[2], | 1688 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg
e->fQuad[2], |
| 1673 startT, endT, &edge->fConic.fWeight); | 1689 startT, endT, &edge->fConic.fWeight); |
| 1674 } else { | 1690 } else { |
| 1675 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1691 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 1676 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT
, &edge->fCubic[1]); | 1692 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT
, &edge->fCubic[1]); |
| 1677 } | 1693 } |
| 1678 return true; | 1694 return true; |
| 1679 } | 1695 } |
| 1680 | 1696 |
| 1681 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT
, | 1697 bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT
, |
| 1682 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegme
nt* opp, | 1698 const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegme
nt* opp) const { |
| 1683 SkScalar flatnessLimit) const { | |
| 1684 // average t, find mid pt | 1699 // average t, find mid pt |
| 1685 double midT = (prior->t() + spanBase->t()) / 2; | 1700 double midT = (prior->t() + spanBase->t()) / 2; |
| 1686 SkPoint midPt = this->ptAtT(midT); | 1701 SkPoint midPt = this->ptAtT(midT); |
| 1687 bool coincident = true; | 1702 bool coincident = true; |
| 1688 // if the mid pt is not near either end pt, project perpendicular through op
p seg | 1703 // if the mid pt is not near either end pt, project perpendicular through op
p seg |
| 1689 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) | 1704 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) |
| 1690 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { | 1705 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { |
| 1706 if (priorPtT->span() == ptT->span()) { |
| 1707 return false; |
| 1708 } |
| 1691 coincident = false; | 1709 coincident = false; |
| 1692 SkIntersections i; | 1710 SkIntersections i; |
| 1693 SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), mid
T); | 1711 SkDCurve curvePart; |
| 1694 SkDLine ray = {{{midPt.fX, midPt.fY}, | 1712 this->subDivide(prior, spanBase, &curvePart); |
| 1695 {(double) midPt.fX + dxdy.fY, (double) midPt.fY - dxdy.fX}}}; | 1713 SkDVector dxdy = (*CurveDDSlopeAtT[fVerb])(curvePart, 0.5f); |
| 1696 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i); | 1714 SkDPoint partMidPt = (*CurveDDPointAtT[fVerb])(curvePart, 0.5f); |
| 1715 SkDLine ray = {{{midPt.fX, midPt.fY}, {partMidPt.fX + dxdy.fY, partMidPt
.fY - dxdy.fX}}}; |
| 1716 SkDCurve oppPart; |
| 1717 opp->subDivide(priorPtT->span(), ptT->span(), &oppPart); |
| 1718 (*CurveDIntersectRay[opp->verb()])(oppPart, ray, &i); |
| 1697 // measure distance and see if it's small enough to denote coincidence | 1719 // measure distance and see if it's small enough to denote coincidence |
| 1698 for (int index = 0; index < i.used(); ++index) { | 1720 for (int index = 0; index < i.used(); ++index) { |
| 1721 if (!between(0, i[0][index], 1)) { |
| 1722 continue; |
| 1723 } |
| 1699 SkDPoint oppPt = i.pt(index); | 1724 SkDPoint oppPt = i.pt(index); |
| 1700 if (oppPt.approximatelyEqual(midPt)) { | 1725 if (oppPt.approximatelyEqual(midPt)) { |
| 1701 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(), | 1726 // the coincidence can occur at almost any angle |
| 1702 opp->weight(), i[index][0]); | 1727 coincident = true; |
| 1703 oppDxdy.normalize(); | |
| 1704 dxdy.normalize(); | |
| 1705 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILO
N); | |
| 1706 coincident |= flatness < flatnessLimit; | |
| 1707 } | 1728 } |
| 1708 } | 1729 } |
| 1709 } | 1730 } |
| 1710 return coincident; | 1731 return coincident; |
| 1711 } | 1732 } |
| 1712 | 1733 |
| 1713 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { | 1734 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { |
| 1714 SkOpSpan* span = this->head(); | 1735 SkOpSpan* span = this->head(); |
| 1715 do { | 1736 do { |
| 1716 if (!span->done()) { | 1737 if (!span->done()) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1783 int absOut = SkTAbs(outerWinding); | 1804 int absOut = SkTAbs(outerWinding); |
| 1784 int absIn = SkTAbs(innerWinding); | 1805 int absIn = SkTAbs(innerWinding); |
| 1785 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; | 1806 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; |
| 1786 return result; | 1807 return result; |
| 1787 } | 1808 } |
| 1788 | 1809 |
| 1789 int SkOpSegment::windSum(const SkOpAngle* angle) const { | 1810 int SkOpSegment::windSum(const SkOpAngle* angle) const { |
| 1790 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); | 1811 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); |
| 1791 return minSpan->windSum(); | 1812 return minSpan->windSum(); |
| 1792 } | 1813 } |
| OLD | NEW |