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 "SkAddIntersections.h" | 7 #include "SkAddIntersections.h" |
| 8 #include "SkOpCoincidence.h" |
8 #include "SkPathOpsBounds.h" | 9 #include "SkPathOpsBounds.h" |
9 | 10 |
10 #if DEBUG_ADD_INTERSECTING_TS | 11 #if DEBUG_ADD_INTERSECTING_TS |
11 | 12 |
12 static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt, | 13 static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt, |
13 const SkIntersectionHelper& wn, const SkIn
tersections& i) { | 14 const SkIntersectionHelper& wn, const SkIn
tersections& i) { |
14 SkASSERT(i.used() == pts); | 15 SkASSERT(i.used() == pts); |
15 if (!pts) { | 16 if (!pts) { |
16 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n", | 17 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n", |
17 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts(
))); | 18 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts(
))); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 for (int n = 1; n < pts; ++n) { | 124 for (int n = 1; n < pts; ++n) { |
124 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_D
ATA(i, n)); | 125 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_D
ATA(i, n)); |
125 } | 126 } |
126 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts())
); | 127 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts())
); |
127 for (int n = 1; n < pts; ++n) { | 128 for (int n = 1; n < pts; ++n) { |
128 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); | 129 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); |
129 } | 130 } |
130 SkDebugf("\n"); | 131 SkDebugf("\n"); |
131 } | 132 } |
132 | 133 |
133 static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt, | |
134 const SkIntersections& i) { | |
135 SkASSERT(i.used() == pts); | |
136 if (!pts) { | |
137 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__, | |
138 CUBIC_DEBUG_DATA(wt.pts())); | |
139 return; | |
140 } | |
141 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __
FUNCTION__, | |
142 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); | |
143 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i[1][0]); | |
144 SkDebugf("\n"); | |
145 } | |
146 | |
147 #else | 134 #else |
148 static void debugShowLineIntersection(int , const SkIntersectionHelper& , | 135 static void debugShowLineIntersection(int , const SkIntersectionHelper& , |
149 const SkIntersectionHelper& , const SkIntersections& ) { | 136 const SkIntersectionHelper& , const SkIntersections& ) { |
150 } | 137 } |
151 | 138 |
152 static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& , | 139 static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& , |
153 const SkIntersectionHelper& , const SkIntersections& ) { | 140 const SkIntersectionHelper& , const SkIntersections& ) { |
154 } | 141 } |
155 | 142 |
156 static void debugShowQuadIntersection(int , const SkIntersectionHelper& , | 143 static void debugShowQuadIntersection(int , const SkIntersectionHelper& , |
157 const SkIntersectionHelper& , const SkIntersections& ) { | 144 const SkIntersectionHelper& , const SkIntersections& ) { |
158 } | 145 } |
159 | 146 |
160 static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& , | 147 static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& , |
161 const SkIntersectionHelper& , const SkIntersections& ) { | 148 const SkIntersectionHelper& , const SkIntersections& ) { |
162 } | 149 } |
163 | 150 |
164 static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& , | 151 static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& , |
165 const SkIntersectionHelper& , const SkIntersections& ) { | 152 const SkIntersectionHelper& , const SkIntersections& ) { |
166 } | 153 } |
167 | 154 |
168 static void debugShowCubicIntersection(int , const SkIntersectionHelper& , | 155 static void debugShowCubicIntersection(int , const SkIntersectionHelper& , |
169 const SkIntersectionHelper& , const SkIntersections& ) { | 156 const SkIntersectionHelper& , const SkIntersections& ) { |
170 } | 157 } |
171 | |
172 static void debugShowCubicIntersection(int , const SkIntersectionHelper& , | |
173 const SkIntersections& ) { | |
174 } | |
175 #endif | 158 #endif |
176 | 159 |
177 bool AddIntersectTs(SkOpContour* test, SkOpContour* next) { | 160 bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc
idence, |
| 161 SkChunkAlloc* allocator) { |
178 if (test != next) { | 162 if (test != next) { |
179 if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) { | 163 if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) { |
180 return false; | 164 return false; |
181 } | 165 } |
182 // OPTIMIZATION: outset contour bounds a smidgen instead? | 166 // OPTIMIZATION: outset contour bounds a smidgen instead? |
183 if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) { | 167 if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) { |
184 return true; | 168 return true; |
185 } | 169 } |
186 } | 170 } |
187 SkIntersectionHelper wt; | 171 SkIntersectionHelper wt; |
188 wt.init(test); | 172 wt.init(test); |
189 bool foundCommonContour = test == next; | |
190 do { | 173 do { |
191 SkIntersectionHelper wn; | 174 SkIntersectionHelper wn; |
192 wn.init(next); | 175 wn.init(next); |
| 176 test->debugValidate(); |
| 177 next->debugValidate(); |
193 if (test == next && !wn.startAfter(wt)) { | 178 if (test == next && !wn.startAfter(wt)) { |
194 continue; | 179 continue; |
195 } | 180 } |
196 do { | 181 do { |
197 if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) { | 182 if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) { |
198 continue; | 183 continue; |
199 } | 184 } |
200 int pts = 0; | 185 int pts = 0; |
201 SkIntersections ts; | 186 SkIntersections ts; |
202 bool swap = false; | 187 bool swap = false; |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 pts = ts.quadVertical(wt.pts(), wn.top(), | 284 pts = ts.quadVertical(wt.pts(), wn.top(), |
300 wn.bottom(), wn.x(), wn.yFlipped()); | 285 wn.bottom(), wn.x(), wn.yFlipped()); |
301 debugShowQuadLineIntersection(pts, wt, wn, ts); | 286 debugShowQuadLineIntersection(pts, wt, wn, ts); |
302 break; | 287 break; |
303 case SkIntersectionHelper::kLine_Segment: { | 288 case SkIntersectionHelper::kLine_Segment: { |
304 pts = ts.quadLine(wt.pts(), wn.pts()); | 289 pts = ts.quadLine(wt.pts(), wn.pts()); |
305 debugShowQuadLineIntersection(pts, wt, wn, ts); | 290 debugShowQuadLineIntersection(pts, wt, wn, ts); |
306 break; | 291 break; |
307 } | 292 } |
308 case SkIntersectionHelper::kQuad_Segment: { | 293 case SkIntersectionHelper::kQuad_Segment: { |
309 pts = ts.quadQuad(wt.pts(), wn.pts()); | 294 SkDQuad quad1; |
310 ts.alignQuadPts(wt.pts(), wn.pts()); | 295 quad1.set(wt.pts()); |
| 296 SkDQuad quad2; |
| 297 quad2.set(wn.pts()); |
| 298 pts = ts.intersect(quad1, quad2); |
311 debugShowQuadIntersection(pts, wt, wn, ts); | 299 debugShowQuadIntersection(pts, wt, wn, ts); |
312 break; | 300 break; |
313 } | 301 } |
314 case SkIntersectionHelper::kCubic_Segment: { | 302 case SkIntersectionHelper::kCubic_Segment: { |
315 swap = true; | 303 swap = true; |
316 pts = ts.cubicQuad(wn.pts(), wt.pts()); | 304 SkDQuad quad1; |
| 305 quad1.set(wt.pts()); |
| 306 SkDCubic cubic1 = quad1.toCubic(); |
| 307 SkDCubic cubic2; |
| 308 cubic2.set(wn.pts()); |
| 309 pts = ts.intersect(cubic2, cubic1); |
317 debugShowCubicQuadIntersection(pts, wn, wt, ts); | 310 debugShowCubicQuadIntersection(pts, wn, wt, ts); |
318 break; | 311 break; |
319 } | 312 } |
320 default: | 313 default: |
321 SkASSERT(0); | 314 SkASSERT(0); |
322 } | 315 } |
323 break; | 316 break; |
324 case SkIntersectionHelper::kCubic_Segment: | 317 case SkIntersectionHelper::kCubic_Segment: |
325 switch (wn.segmentType()) { | 318 switch (wn.segmentType()) { |
326 case SkIntersectionHelper::kHorizontalLine_Segment: | 319 case SkIntersectionHelper::kHorizontalLine_Segment: |
327 pts = ts.cubicHorizontal(wt.pts(), wn.left(), | 320 pts = ts.cubicHorizontal(wt.pts(), wn.left(), |
328 wn.right(), wn.y(), wn.xFlipped()); | 321 wn.right(), wn.y(), wn.xFlipped()); |
329 debugShowCubicLineIntersection(pts, wt, wn, ts); | 322 debugShowCubicLineIntersection(pts, wt, wn, ts); |
330 break; | 323 break; |
331 case SkIntersectionHelper::kVerticalLine_Segment: | 324 case SkIntersectionHelper::kVerticalLine_Segment: |
332 pts = ts.cubicVertical(wt.pts(), wn.top(), | 325 pts = ts.cubicVertical(wt.pts(), wn.top(), |
333 wn.bottom(), wn.x(), wn.yFlipped()); | 326 wn.bottom(), wn.x(), wn.yFlipped()); |
334 debugShowCubicLineIntersection(pts, wt, wn, ts); | 327 debugShowCubicLineIntersection(pts, wt, wn, ts); |
335 break; | 328 break; |
336 case SkIntersectionHelper::kLine_Segment: { | 329 case SkIntersectionHelper::kLine_Segment: { |
337 pts = ts.cubicLine(wt.pts(), wn.pts()); | 330 pts = ts.cubicLine(wt.pts(), wn.pts()); |
338 debugShowCubicLineIntersection(pts, wt, wn, ts); | 331 debugShowCubicLineIntersection(pts, wt, wn, ts); |
339 break; | 332 break; |
340 } | 333 } |
341 case SkIntersectionHelper::kQuad_Segment: { | 334 case SkIntersectionHelper::kQuad_Segment: { |
342 pts = ts.cubicQuad(wt.pts(), wn.pts()); | 335 SkDCubic cubic1; |
| 336 cubic1.set(wt.pts()); |
| 337 SkDQuad quad2; |
| 338 quad2.set(wn.pts()); |
| 339 SkDCubic cubic2 = quad2.toCubic(); |
| 340 pts = ts.intersect(cubic1, cubic2); |
343 debugShowCubicQuadIntersection(pts, wt, wn, ts); | 341 debugShowCubicQuadIntersection(pts, wt, wn, ts); |
344 break; | 342 break; |
345 } | 343 } |
346 case SkIntersectionHelper::kCubic_Segment: { | 344 case SkIntersectionHelper::kCubic_Segment: { |
347 pts = ts.cubicCubic(wt.pts(), wn.pts()); | 345 SkDCubic cubic1; |
| 346 cubic1.set(wt.pts()); |
| 347 SkDCubic cubic2; |
| 348 cubic2.set(wn.pts()); |
| 349 pts = ts.intersect(cubic1, cubic2); |
348 debugShowCubicIntersection(pts, wt, wn, ts); | 350 debugShowCubicIntersection(pts, wt, wn, ts); |
349 break; | 351 break; |
350 } | 352 } |
351 default: | 353 default: |
352 SkASSERT(0); | 354 SkASSERT(0); |
353 } | 355 } |
354 break; | 356 break; |
355 default: | 357 default: |
356 SkASSERT(0); | 358 SkASSERT(0); |
357 } | 359 } |
358 if (!foundCommonContour && pts > 0) { | 360 int coinIndex = -1; |
359 test->addCross(next); | 361 SkOpPtT* coinPtT[2]; |
360 next->addCross(test); | |
361 foundCommonContour = true; | |
362 } | |
363 // in addition to recording T values, record matching segment | |
364 if (pts == 2) { | |
365 if (wn.segmentType() <= SkIntersectionHelper::kLine_Segment | |
366 && wt.segmentType() <= SkIntersectionHelper::kLine_Segme
nt) { | |
367 if (wt.addCoincident(wn, ts, swap)) { | |
368 continue; | |
369 } | |
370 pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) | |
371 } else if (wn.segmentType() >= SkIntersectionHelper::kQuad_Segme
nt | |
372 && wt.segmentType() >= SkIntersectionHelper::kQuad_Segme
nt | |
373 && ts.isCoincident(0)) { | |
374 SkASSERT(ts.coincidentUsed() == 2); | |
375 if (wt.addCoincident(wn, ts, swap)) { | |
376 continue; | |
377 } | |
378 pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) | |
379 } | |
380 } | |
381 if (pts >= 2) { | |
382 for (int pt = 0; pt < pts - 1; ++pt) { | |
383 const SkDPoint& point = ts.pt(pt); | |
384 const SkDPoint& next = ts.pt(pt + 1); | |
385 if (wt.isPartial(ts[swap][pt], ts[swap][pt + 1], point, next
) | |
386 && wn.isPartial(ts[!swap][pt], ts[!swap][pt + 1], po
int, next)) { | |
387 if (!wt.addPartialCoincident(wn, ts, pt, swap)) { | |
388 // remove extra point if two map to same float value
s | |
389 pts = ts.cleanUpCoincidence(); // prefer (t == 0 or
t == 1) | |
390 } | |
391 } | |
392 } | |
393 } | |
394 for (int pt = 0; pt < pts; ++pt) { | 362 for (int pt = 0; pt < pts; ++pt) { |
395 SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1); | 363 SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1); |
396 SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1); | 364 SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1); |
397 SkPoint point = ts.pt(pt).asSkPoint(); | 365 wt.segment()->debugValidate(); |
398 wt.alignTPt(wn, swap, pt, &ts, &point); | 366 SkOpPtT* testTAt = wt.segment()->addT(ts[swap][pt], SkOpSegment:
:kAllowAlias, |
399 int testTAt = wt.addT(wn, point, ts[swap][pt]); | 367 allocator); |
400 int nextTAt = wn.addT(wt, point, ts[!swap][pt]); | 368 wn.segment()->debugValidate(); |
401 wt.addOtherT(testTAt, ts[!swap][pt], nextTAt); | 369 SkOpPtT* nextTAt = wn.segment()->addT(ts[!swap][pt], SkOpSegment
::kAllowAlias, |
402 wn.addOtherT(nextTAt, ts[swap][pt], testTAt); | 370 allocator); |
| 371 testTAt->addOpp(nextTAt); |
| 372 if (testTAt->fPt != nextTAt->fPt) { |
| 373 testTAt->span()->unaligned(); |
| 374 nextTAt->span()->unaligned(); |
| 375 } |
| 376 wt.segment()->debugValidate(); |
| 377 wn.segment()->debugValidate(); |
| 378 if (!ts.isCoincident(pt)) { |
| 379 continue; |
| 380 } |
| 381 if (coinIndex < 0) { |
| 382 coinPtT[0] = testTAt; |
| 383 coinPtT[1] = nextTAt; |
| 384 coinIndex = pt; |
| 385 continue; |
| 386 } |
| 387 if (coinPtT[0]->span() == testTAt->span()) { |
| 388 coinIndex = -1; |
| 389 continue; |
| 390 } |
| 391 if (coinPtT[1]->span() == nextTAt->span()) { |
| 392 coinIndex = -1; // coincidence span collapsed |
| 393 continue; |
| 394 } |
| 395 if (swap) { |
| 396 SkTSwap(coinPtT[0], coinPtT[1]); |
| 397 SkTSwap(testTAt, nextTAt); |
| 398 } |
| 399 SkASSERT(coinPtT[0]->span()->t() < testTAt->span()->t()); |
| 400 coincidence->add(coinPtT[0], testTAt, coinPtT[1], nextTAt, alloc
ator); |
| 401 wt.segment()->debugValidate(); |
| 402 wn.segment()->debugValidate(); |
| 403 coinIndex = -1; |
403 } | 404 } |
| 405 SkASSERT(coinIndex < 0); // expect coincidence to be paired |
404 } while (wn.advance()); | 406 } while (wn.advance()); |
405 } while (wt.advance()); | 407 } while (wt.advance()); |
406 return true; | 408 return true; |
407 } | 409 } |
408 | |
409 void AddSelfIntersectTs(SkOpContour* test) { | |
410 SkIntersectionHelper wt; | |
411 wt.init(test); | |
412 do { | |
413 if (wt.segmentType() != SkIntersectionHelper::kCubic_Segment) { | |
414 continue; | |
415 } | |
416 SkIntersections ts; | |
417 int pts = ts.cubic(wt.pts()); | |
418 debugShowCubicIntersection(pts, wt, ts); | |
419 if (!pts) { | |
420 continue; | |
421 } | |
422 SkASSERT(pts == 1); | |
423 SkASSERT(ts[0][0] >= 0 && ts[0][0] <= 1); | |
424 SkASSERT(ts[1][0] >= 0 && ts[1][0] <= 1); | |
425 SkPoint point = ts.pt(0).asSkPoint(); | |
426 int testTAt = wt.addSelfT(point, ts[0][0]); | |
427 int nextTAt = wt.addSelfT(point, ts[1][0]); | |
428 wt.addOtherT(testTAt, ts[1][0], nextTAt); | |
429 wt.addOtherT(nextTAt, ts[0][0], testTAt); | |
430 } while (wt.advance()); | |
431 } | |
432 | |
433 // resolve any coincident pairs found while intersecting, and | |
434 // see if coincidence is formed by clipping non-concident segments | |
435 bool CoincidenceCheck(SkTArray<SkOpContour*, true>* contourList, int total) { | |
436 int contourCount = (*contourList).count(); | |
437 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
438 SkOpContour* contour = (*contourList)[cIndex]; | |
439 contour->resolveNearCoincidence(); | |
440 } | |
441 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
442 SkOpContour* contour = (*contourList)[cIndex]; | |
443 contour->addCoincidentPoints(); | |
444 } | |
445 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
446 SkOpContour* contour = (*contourList)[cIndex]; | |
447 if (!contour->calcCoincidentWinding()) { | |
448 return false; | |
449 } | |
450 } | |
451 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
452 SkOpContour* contour = (*contourList)[cIndex]; | |
453 contour->calcPartialCoincidentWinding(); | |
454 } | |
455 return true; | |
456 } | |
OLD | NEW |