SkAddIntersections.cpp revision 65f553182ab7069378ef863d30094d0327f178d0
1/* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7#include "SkAddIntersections.h" 8#include "SkPathOpsBounds.h" 9 10#if DEBUG_ADD_INTERSECTING_TS 11 12static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt, 13 const SkIntersectionHelper& wn, const SkIntersections& i) { 14 SkASSERT(i.used() == pts); 15 if (!pts) { 16 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n", 17 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); 18 return; 19 } 20 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 21 i[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 22 if (pts == 2) { 23 SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i[0][1], PT_DEBUG_DATA(i, 1)); 24 } 25 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts())); 26 if (pts == 2) { 27 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i[1][1]); 28 } 29 SkDebugf("\n"); 30} 31 32static void debugShowQuadLineIntersection(int pts, const SkIntersectionHelper& wt, 33 const SkIntersectionHelper& wn, 34 const SkIntersections& i) { 35 SkASSERT(i.used() == pts); 36 if (!pts) { 37 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n", 38 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); 39 return; 40 } 41 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 42 i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 43 for (int n = 1; n < pts; ++n) { 44 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); 45 } 46 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts())); 47 for (int n = 1; n < pts; ++n) { 48 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); 49 } 50 SkDebugf("\n"); 51} 52 53static void debugShowQuadIntersection(int pts, const SkIntersectionHelper& wt, 54 const SkIntersectionHelper& wn, const SkIntersections& i) { 55 SkASSERT(i.used() == pts); 56 if (!pts) { 57 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n", 58 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts())); 59 return; 60 } 61 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 62 i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 63 for (int n = 1; n < pts; ++n) { 64 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); 65 } 66 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts())); 67 for (int n = 1; n < pts; ++n) { 68 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); 69 } 70 SkDebugf("\n"); 71} 72 73static void debugShowCubicLineIntersection(int pts, const SkIntersectionHelper& wt, 74 const SkIntersectionHelper& wn, const SkIntersections& i) { 75 SkASSERT(i.used() == pts); 76 if (!pts) { 77 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n", 78 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); 79 return; 80 } 81 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 82 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 83 for (int n = 1; n < pts; ++n) { 84 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); 85 } 86 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts())); 87 for (int n = 1; n < pts; ++n) { 88 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); 89 } 90 SkDebugf("\n"); 91} 92 93static void debugShowCubicQuadIntersection(int pts, const SkIntersectionHelper& wt, 94 const SkIntersectionHelper& wn, const SkIntersections& i) { 95 SkASSERT(i.used() == pts); 96 if (!pts) { 97 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n", 98 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts())); 99 return; 100 } 101 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 102 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 103 for (int n = 1; n < pts; ++n) { 104 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); 105 } 106 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts())); 107 for (int n = 1; n < pts; ++n) { 108 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); 109 } 110 SkDebugf("\n"); 111} 112 113static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt, 114 const SkIntersectionHelper& wn, const SkIntersections& i) { 115 SkASSERT(i.used() == pts); 116 if (!pts) { 117 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n", 118 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts())); 119 return; 120 } 121 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 122 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 123 for (int n = 1; n < pts; ++n) { 124 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n)); 125 } 126 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts())); 127 for (int n = 1; n < pts; ++n) { 128 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); 129 } 130 SkDebugf("\n"); 131} 132 133static 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 148static void debugShowLineIntersection(int , const SkIntersectionHelper& , 149 const SkIntersectionHelper& , const SkIntersections& ) { 150} 151 152static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& , 153 const SkIntersectionHelper& , const SkIntersections& ) { 154} 155 156static void debugShowQuadIntersection(int , const SkIntersectionHelper& , 157 const SkIntersectionHelper& , const SkIntersections& ) { 158} 159 160static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& , 161 const SkIntersectionHelper& , const SkIntersections& ) { 162} 163 164static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& , 165 const SkIntersectionHelper& , const SkIntersections& ) { 166} 167 168static void debugShowCubicIntersection(int , const SkIntersectionHelper& , 169 const SkIntersectionHelper& , const SkIntersections& ) { 170} 171 172static void debugShowCubicIntersection(int , const SkIntersectionHelper& , 173 const SkIntersections& ) { 174} 175#endif 176 177bool AddIntersectTs(SkOpContour* test, SkOpContour* next) { 178 if (test != next) { 179 if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) { 180 return false; 181 } 182 // OPTIMIZATION: outset contour bounds a smidgen instead? 183 if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) { 184 return true; 185 } 186 } 187 SkIntersectionHelper wt; 188 wt.init(test); 189 bool foundCommonContour = test == next; 190 do { 191 SkIntersectionHelper wn; 192 wn.init(next); 193 if (test == next && !wn.startAfter(wt)) { 194 continue; 195 } 196 do { 197 if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) { 198 continue; 199 } 200 int pts = 0; 201 SkIntersections ts; 202 bool swap = false; 203 switch (wt.segmentType()) { 204 case SkIntersectionHelper::kHorizontalLine_Segment: 205 swap = true; 206 switch (wn.segmentType()) { 207 case SkIntersectionHelper::kHorizontalLine_Segment: 208 case SkIntersectionHelper::kVerticalLine_Segment: 209 case SkIntersectionHelper::kLine_Segment: { 210 pts = ts.lineHorizontal(wn.pts(), wt.left(), 211 wt.right(), wt.y(), wt.xFlipped()); 212 debugShowLineIntersection(pts, wn, wt, ts); 213 break; 214 } 215 case SkIntersectionHelper::kQuad_Segment: { 216 pts = ts.quadHorizontal(wn.pts(), wt.left(), 217 wt.right(), wt.y(), wt.xFlipped()); 218 debugShowQuadLineIntersection(pts, wn, wt, ts); 219 break; 220 } 221 case SkIntersectionHelper::kCubic_Segment: { 222 pts = ts.cubicHorizontal(wn.pts(), wt.left(), 223 wt.right(), wt.y(), wt.xFlipped()); 224 debugShowCubicLineIntersection(pts, wn, wt, ts); 225 break; 226 } 227 default: 228 SkASSERT(0); 229 } 230 break; 231 case SkIntersectionHelper::kVerticalLine_Segment: 232 swap = true; 233 switch (wn.segmentType()) { 234 case SkIntersectionHelper::kHorizontalLine_Segment: 235 case SkIntersectionHelper::kVerticalLine_Segment: 236 case SkIntersectionHelper::kLine_Segment: { 237 pts = ts.lineVertical(wn.pts(), wt.top(), 238 wt.bottom(), wt.x(), wt.yFlipped()); 239 debugShowLineIntersection(pts, wn, wt, ts); 240 break; 241 } 242 case SkIntersectionHelper::kQuad_Segment: { 243 pts = ts.quadVertical(wn.pts(), wt.top(), 244 wt.bottom(), wt.x(), wt.yFlipped()); 245 debugShowQuadLineIntersection(pts, wn, wt, ts); 246 break; 247 } 248 case SkIntersectionHelper::kCubic_Segment: { 249 pts = ts.cubicVertical(wn.pts(), wt.top(), 250 wt.bottom(), wt.x(), wt.yFlipped()); 251 debugShowCubicLineIntersection(pts, wn, wt, ts); 252 break; 253 } 254 default: 255 SkASSERT(0); 256 } 257 break; 258 case SkIntersectionHelper::kLine_Segment: 259 switch (wn.segmentType()) { 260 case SkIntersectionHelper::kHorizontalLine_Segment: 261 pts = ts.lineHorizontal(wt.pts(), wn.left(), 262 wn.right(), wn.y(), wn.xFlipped()); 263 debugShowLineIntersection(pts, wt, wn, ts); 264 break; 265 case SkIntersectionHelper::kVerticalLine_Segment: 266 pts = ts.lineVertical(wt.pts(), wn.top(), 267 wn.bottom(), wn.x(), wn.yFlipped()); 268 debugShowLineIntersection(pts, wt, wn, ts); 269 break; 270 case SkIntersectionHelper::kLine_Segment: { 271 pts = ts.lineLine(wt.pts(), wn.pts()); 272 debugShowLineIntersection(pts, wt, wn, ts); 273 break; 274 } 275 case SkIntersectionHelper::kQuad_Segment: { 276 swap = true; 277 pts = ts.quadLine(wn.pts(), wt.pts()); 278 debugShowQuadLineIntersection(pts, wn, wt, ts); 279 break; 280 } 281 case SkIntersectionHelper::kCubic_Segment: { 282 swap = true; 283 pts = ts.cubicLine(wn.pts(), wt.pts()); 284 debugShowCubicLineIntersection(pts, wn, wt, ts); 285 break; 286 } 287 default: 288 SkASSERT(0); 289 } 290 break; 291 case SkIntersectionHelper::kQuad_Segment: 292 switch (wn.segmentType()) { 293 case SkIntersectionHelper::kHorizontalLine_Segment: 294 pts = ts.quadHorizontal(wt.pts(), wn.left(), 295 wn.right(), wn.y(), wn.xFlipped()); 296 debugShowQuadLineIntersection(pts, wt, wn, ts); 297 break; 298 case SkIntersectionHelper::kVerticalLine_Segment: 299 pts = ts.quadVertical(wt.pts(), wn.top(), 300 wn.bottom(), wn.x(), wn.yFlipped()); 301 debugShowQuadLineIntersection(pts, wt, wn, ts); 302 break; 303 case SkIntersectionHelper::kLine_Segment: { 304 pts = ts.quadLine(wt.pts(), wn.pts()); 305 debugShowQuadLineIntersection(pts, wt, wn, ts); 306 break; 307 } 308 case SkIntersectionHelper::kQuad_Segment: { 309 pts = ts.quadQuad(wt.pts(), wn.pts()); 310 ts.alignQuadPts(wt.pts(), wn.pts()); 311 debugShowQuadIntersection(pts, wt, wn, ts); 312 break; 313 } 314 case SkIntersectionHelper::kCubic_Segment: { 315 swap = true; 316 pts = ts.cubicQuad(wn.pts(), wt.pts()); 317 debugShowCubicQuadIntersection(pts, wn, wt, ts); 318 break; 319 } 320 default: 321 SkASSERT(0); 322 } 323 break; 324 case SkIntersectionHelper::kCubic_Segment: 325 switch (wn.segmentType()) { 326 case SkIntersectionHelper::kHorizontalLine_Segment: 327 pts = ts.cubicHorizontal(wt.pts(), wn.left(), 328 wn.right(), wn.y(), wn.xFlipped()); 329 debugShowCubicLineIntersection(pts, wt, wn, ts); 330 break; 331 case SkIntersectionHelper::kVerticalLine_Segment: 332 pts = ts.cubicVertical(wt.pts(), wn.top(), 333 wn.bottom(), wn.x(), wn.yFlipped()); 334 debugShowCubicLineIntersection(pts, wt, wn, ts); 335 break; 336 case SkIntersectionHelper::kLine_Segment: { 337 pts = ts.cubicLine(wt.pts(), wn.pts()); 338 debugShowCubicLineIntersection(pts, wt, wn, ts); 339 break; 340 } 341 case SkIntersectionHelper::kQuad_Segment: { 342 pts = ts.cubicQuad(wt.pts(), wn.pts()); 343 debugShowCubicQuadIntersection(pts, wt, wn, ts); 344 break; 345 } 346 case SkIntersectionHelper::kCubic_Segment: { 347 pts = ts.cubicCubic(wt.pts(), wn.pts()); 348 debugShowCubicIntersection(pts, wt, wn, ts); 349 break; 350 } 351 default: 352 SkASSERT(0); 353 } 354 break; 355 default: 356 SkASSERT(0); 357 } 358 if (!foundCommonContour && pts > 0) { 359 test->addCross(next); 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_Segment) { 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_Segment 372 && wt.segmentType() >= SkIntersectionHelper::kQuad_Segment 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], point, next)) { 387 if (!wt.addPartialCoincident(wn, ts, pt, swap)) { 388 // remove extra point if two map to same float values 389 pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) 390 } 391 } 392 } 393 } 394 for (int pt = 0; pt < pts; ++pt) { 395 SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1); 396 SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1); 397 SkPoint point = ts.pt(pt).asSkPoint(); 398 wt.alignTPt(wn, swap, pt, &ts, &point); 399 int testTAt = wt.addT(wn, point, ts[swap][pt]); 400 int nextTAt = wn.addT(wt, point, ts[!swap][pt]); 401 wt.addOtherT(testTAt, ts[!swap][pt], nextTAt); 402 wn.addOtherT(nextTAt, ts[swap][pt], testTAt); 403 } 404 } while (wn.advance()); 405 } while (wt.advance()); 406 return true; 407} 408 409void 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 435bool 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} 457