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...) 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...) 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...) 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...) 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...) 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...) 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...) 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...) 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...) 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...) 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 |