Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: src/pathops/SkAddIntersections.cpp

Issue 1002693002: pathops version two (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix arm 64 inspired coincident handling Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pathops/SkAddIntersections.h ('k') | src/pathops/SkDCubicIntersection.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « src/pathops/SkAddIntersections.h ('k') | src/pathops/SkDCubicIntersection.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698