OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "PathOpsTestCommon.h" | 7 #include "PathOpsTestCommon.h" |
8 #include "SkIntersections.h" | 8 #include "SkIntersections.h" |
9 #include "SkOpContour.h" | |
10 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
| 10 #include "SkPathOpsTriangle.h" |
11 #include "SkRandom.h" | 11 #include "SkRandom.h" |
| 12 #include "SkTArray.h" |
12 #include "SkTSort.h" | 13 #include "SkTSort.h" |
13 #include "Test.h" | 14 #include "Test.h" |
14 | 15 |
15 static bool gDisableAngleTests = true; | 16 static bool gDisableAngleTests = true; |
16 | 17 |
17 static float next(float f) | 18 static float next(float f) |
18 { | 19 { |
19 int fBits = SkFloatAs2sCompliment(f); | 20 int fBits = SkFloatAs2sCompliment(f); |
20 ++fBits; | 21 ++fBits; |
21 float fNext = Sk2sComplimentAsFloat(fBits); | 22 float fNext = Sk2sComplimentAsFloat(fBits); |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 double angle = diamond_angle(y, x); | 184 double angle = diamond_angle(y, x); |
184 double rAngle = diamond_angle(ry, rx); | 185 double rAngle = diamond_angle(ry, rx); |
185 double diff = fabs(angle - rAngle); | 186 double diff = fabs(angle - rAngle); |
186 SkDebugf("%s diamond xy=%1.9g rxy=%1.9g diff=%1.9g factor=%d\n", __FUNCT
ION__, | 187 SkDebugf("%s diamond xy=%1.9g rxy=%1.9g diff=%1.9g factor=%d\n", __FUNCT
ION__, |
187 angle, rAngle, diff, (int) (diff / FLT_EPSILON)); | 188 angle, rAngle, diff, (int) (diff / FLT_EPSILON)); |
188 } | 189 } |
189 } | 190 } |
190 | 191 |
191 class PathOpsAngleTester { | 192 class PathOpsAngleTester { |
192 public: | 193 public: |
193 static int After(SkOpAngle& lh, SkOpAngle& rh) { | 194 static int After(const SkOpAngle& lh, const SkOpAngle& rh) { |
194 return lh.after(&rh); | 195 return lh.after(&rh); |
195 } | 196 } |
196 | 197 |
197 static int ConvexHullOverlaps(SkOpAngle& lh, SkOpAngle& rh) { | 198 static int ConvexHullOverlaps(const SkOpAngle& lh, const SkOpAngle& rh) { |
198 return lh.convexHullOverlaps(&rh); | 199 return lh.convexHullOverlaps(rh); |
199 } | 200 } |
200 | 201 |
201 static int Orderable(SkOpAngle& lh, SkOpAngle& rh) { | 202 static int Orderable(const SkOpAngle& lh, const SkOpAngle& rh) { |
202 return lh.orderable(&rh); | 203 return lh.orderable(rh); |
203 } | 204 } |
204 | 205 |
205 static int EndsIntersect(SkOpAngle& lh, SkOpAngle& rh) { | 206 static int EndsIntersect(const SkOpAngle& lh, const SkOpAngle& rh) { |
206 return lh.endsIntersect(&rh); | 207 return lh.endsIntersect(rh); |
207 } | 208 } |
208 | 209 |
209 static void SetNext(SkOpAngle& lh, SkOpAngle& rh) { | 210 static void SetNext(SkOpAngle& lh, SkOpAngle& rh) { |
210 lh.fNext = &rh; | 211 lh.fNext = &rh; |
211 } | 212 } |
212 }; | 213 }; |
213 | 214 |
214 class PathOpsSegmentTester { | 215 class PathOpsSegmentTester { |
215 public: | 216 public: |
| 217 static void ConstructCubic(SkOpSegment* segment, SkPoint shortCubic[4]) { |
| 218 segment->debugConstructCubic(shortCubic); |
| 219 } |
| 220 |
| 221 static void ConstructLine(SkOpSegment* segment, SkPoint shortLine[2]) { |
| 222 segment->debugConstructLine(shortLine); |
| 223 } |
| 224 |
| 225 static void ConstructQuad(SkOpSegment* segment, SkPoint shortQuad[3]) { |
| 226 segment->debugConstructQuad(shortQuad); |
| 227 } |
| 228 |
216 static void DebugReset(SkOpSegment* segment) { | 229 static void DebugReset(SkOpSegment* segment) { |
217 segment->debugReset(); | 230 segment->debugReset(); |
218 } | 231 } |
219 }; | 232 }; |
220 | 233 |
221 struct CircleData { | 234 struct CircleData { |
222 const SkDCubic fPts; | 235 const SkDCubic fPts; |
223 const int fPtCount; | 236 const int fPtCount; |
224 SkPoint fShortPts[4]; | 237 SkPoint fShortPts[4]; |
225 }; | 238 }; |
226 | 239 |
227 static CircleData circleDataSet[] = { | 240 static CircleData circleDataSet[] = { |
228 { {{{313.0155029296875, 207.90290832519531}, {320.05078125, 227.587432861328
12}}}, 2, {} }, | 241 { {{{313.0155029296875, 207.90290832519531}, {320.05078125, 227.587432861328
12}}}, 2, {} }, |
229 { {{{313.0155029296875, 207.90290832519531}, {313.98246891063195, 219.336152
03830394}, | 242 { {{{313.0155029296875, 207.90290832519531}, {313.98246891063195, 219.336152
03830394}, |
230 {320.05078125, 227.58743286132812}}}, 3, {} }, | 243 {320.05078125, 227.58743286132812}}}, 3, {} }, |
231 }; | 244 }; |
232 | 245 |
233 static const int circleDataSetSize = (int) SK_ARRAY_COUNT(circleDataSet); | 246 static const int circleDataSetSize = (int) SK_ARRAY_COUNT(circleDataSet); |
234 | 247 |
235 DEF_TEST(PathOpsAngleCircle, reporter) { | 248 DEF_TEST(PathOpsAngleCircle, reporter) { |
236 SkOpContour contour; | 249 SkOpSegment segment[2]; |
237 SkOpGlobalState state(NULL PATH_OPS_DEBUG_PARAMS(&contour)); | |
238 contour.init(&state, false, false); | |
239 SkChunkAlloc allocator(4096); | |
240 for (int index = 0; index < circleDataSetSize; ++index) { | 250 for (int index = 0; index < circleDataSetSize; ++index) { |
241 CircleData& data = circleDataSet[index]; | 251 CircleData& data = circleDataSet[index]; |
242 for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) { | 252 for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) { |
243 data.fShortPts[idx2] = data.fPts.fPts[idx2].asSkPoint(); | 253 data.fShortPts[idx2] = data.fPts.fPts[idx2].asSkPoint(); |
244 } | 254 } |
245 switch (data.fPtCount) { | 255 switch (data.fPtCount) { |
246 case 2: | 256 case 2: |
247 contour.addLine(data.fShortPts, &allocator); | 257 PathOpsSegmentTester::ConstructLine(&segment[index], data.fShort
Pts); |
248 break; | 258 break; |
249 case 3: | 259 case 3: |
250 contour.addQuad(data.fShortPts, &allocator); | 260 PathOpsSegmentTester::ConstructQuad(&segment[index], data.fShort
Pts); |
251 break; | 261 break; |
252 case 4: | 262 case 4: |
253 contour.addCubic(data.fShortPts, &allocator); | 263 PathOpsSegmentTester::ConstructCubic(&segment[index], data.fShor
tPts); |
254 break; | 264 break; |
255 } | 265 } |
256 } | 266 } |
257 SkOpSegment* first = contour.first(); | 267 PathOpsAngleTester::Orderable(*segment[0].debugLastAngle(), *segment[1].debu
gLastAngle()); |
258 first->debugAddAngle(0, 1, &allocator); | |
259 SkOpSegment* next = first->next(); | |
260 next->debugAddAngle(0, 1, &allocator); | |
261 PathOpsAngleTester::Orderable(*first->debugLastAngle(), *next->debugLastAngl
e()); | |
262 } | 268 } |
263 | 269 |
264 struct IntersectData { | 270 struct IntersectData { |
265 const SkDCubic fPts; | 271 const SkDCubic fPts; |
266 const int fPtCount; | 272 const int fPtCount; |
267 double fTStart; | 273 double fTStart; |
268 double fTEnd; | 274 double fTEnd; |
269 SkPoint fShortPts[4]; | 275 SkPoint fShortPts[4]; |
270 }; | 276 }; |
271 | 277 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 { {{{447.967,894.438}, {448.007,894.424}, {448.014,894.422}}}, 3, 0, 1, {} }
, // pathops_visualizer.htm:6538 | 372 { {{{447.967,894.438}, {448.007,894.424}, {448.014,894.422}}}, 3, 0, 1, {} }
, // pathops_visualizer.htm:6538 |
367 { {{{490.435,879.407}, {405.593,909.436}}}, 2, 0.500554405, 0.500000273, {}
}, // pathops_visualizer.htm:6538 | 373 { {{{490.435,879.407}, {405.593,909.436}}}, 2, 0.500554405, 0.500000273, {}
}, // pathops_visualizer.htm:6538 |
368 }; // | 374 }; // |
369 | 375 |
370 static IntersectData intersectDataSet16[] = { // pathops_visualizer.htm:7419 | 376 static IntersectData intersectDataSet16[] = { // pathops_visualizer.htm:7419 |
371 { {{{1.000,4.000}, {4.000,5.000}, {3.000,2.000}, {6.000,3.000}}}, 4, 0.5, 0,
{} }, // pathops_visualizer.htm:7377 | 377 { {{{1.000,4.000}, {4.000,5.000}, {3.000,2.000}, {6.000,3.000}}}, 4, 0.5, 0,
{} }, // pathops_visualizer.htm:7377 |
372 { {{{2.000,3.000}, {3.000,6.000}, {4.000,1.000}, {5.000,4.000}}}, 4, 0.5, 0.
112701665, {} }, // pathops_visualizer.htm:7377 | 378 { {{{2.000,3.000}, {3.000,6.000}, {4.000,1.000}, {5.000,4.000}}}, 4, 0.5, 0.
112701665, {} }, // pathops_visualizer.htm:7377 |
373 { {{{5.000,4.000}, {2.000,3.000}}}, 2, 0.5, 0, {} }, // pathops_visualizer.h
tm:7377 | 379 { {{{5.000,4.000}, {2.000,3.000}}}, 2, 0.5, 0, {} }, // pathops_visualizer.h
tm:7377 |
374 }; // | 380 }; // |
375 | 381 |
376 // from skpi_gino_com_16 | |
377 static IntersectData intersectDataSet17[] = { | |
378 { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}} | |
379 , 3, 0.74590454, 0.547660352, {} }, | |
380 { /*seg=8*/ {{{185, 734}, {252.93103f, 734}, {308, 789.06897f}, {308, 857}}} | |
381 , 4, 0.12052623, 0, {} }, | |
382 { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}} | |
383 , 3, 0.74590454, 1, {} }, | |
384 }; | |
385 | |
386 static IntersectData intersectDataSet18[] = { | |
387 { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}} | |
388 , 3, 0.74590454, 1, {} }, | |
389 { /*seg=8*/ {{{185, 734}, {252.93103f, 734}, {308, 789.06897f}, {308, 857}}} | |
390 , 4, 0.12052623, 0.217351928, {} }, | |
391 { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}} | |
392 , 3, 0.74590454, 0.547660352, {} }, | |
393 }; | |
394 | |
395 static IntersectData intersectDataSet19[] = { | |
396 { /*seg=1*/ {{{0, 1}, {3, 5}, {2, 1}, {3, 1}}} | |
397 , 4, 0.135148995, 0.134791946, {} }, | |
398 { /*seg=3*/ {{{1, 2}, {1, 2.15061641f}, {1, 2.21049166f}, {1.01366711f, 2.21
379328f}}} | |
399 , 4, 0.956740456, 0.894913214, {} }, | |
400 { /*seg=1*/ {{{0, 1}, {3, 5}, {2, 1}, {3, 1}}} | |
401 , 4, 0.135148995, 0.551812363, {} }, | |
402 }; | |
403 | |
404 #define I(x) intersectDataSet##x | 382 #define I(x) intersectDataSet##x |
405 | 383 |
406 static IntersectData* intersectDataSets[] = { | 384 static IntersectData* intersectDataSets[] = { |
407 I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10), | 385 I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10), |
408 I(11), I(12), I(13), I(14), I(15), I(16), I(17), I(18), I(19), | 386 I(11), I(12), I(13), I(14), I(15), I(16), |
409 }; | 387 }; |
410 | 388 |
411 #undef I | 389 #undef I |
412 #define I(x) (int) SK_ARRAY_COUNT(intersectDataSet##x) | 390 #define I(x) (int) SK_ARRAY_COUNT(intersectDataSet##x) |
413 | 391 |
414 static const int intersectDataSetSizes[] = { | 392 static const int intersectDataSetSizes[] = { |
415 I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10), | 393 I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10), |
416 I(11), I(12), I(13), I(14), I(15), I(16), I(17), I(18), I(19), | 394 I(11), I(12), I(13), I(14), I(15), I(16), |
417 }; | 395 }; |
418 | 396 |
419 #undef I | 397 #undef I |
420 | 398 |
421 static const int intersectDataSetsSize = (int) SK_ARRAY_COUNT(intersectDataSetSi
zes); | 399 static const int intersectDataSetsSize = (int) SK_ARRAY_COUNT(intersectDataSetSi
zes); |
422 | 400 |
423 struct FourPoints { | |
424 SkPoint pts[4]; | |
425 }; | |
426 | |
427 DEF_TEST(PathOpsAngleAfter, reporter) { | 401 DEF_TEST(PathOpsAngleAfter, reporter) { |
428 SkChunkAlloc allocator(4096); | |
429 SkOpContour contour; | |
430 SkOpGlobalState state(NULL PATH_OPS_DEBUG_PARAMS(&contour)); | |
431 contour.init(&state, false, false); | |
432 for (int index = intersectDataSetsSize - 1; index >= 0; --index) { | 402 for (int index = intersectDataSetsSize - 1; index >= 0; --index) { |
433 IntersectData* dataArray = intersectDataSets[index]; | 403 IntersectData* dataArray = intersectDataSets[index]; |
434 const int dataSize = intersectDataSetSizes[index]; | 404 const int dataSize = intersectDataSetSizes[index]; |
| 405 SkOpSegment segment[3]; |
435 for (int index2 = 0; index2 < dataSize - 2; ++index2) { | 406 for (int index2 = 0; index2 < dataSize - 2; ++index2) { |
436 allocator.reset(); | 407 for (int temp = 0; temp < (int) SK_ARRAY_COUNT(segment); ++temp) { |
437 contour.reset(); | 408 PathOpsSegmentTester::DebugReset(&segment[temp]); |
438 for (int index3 = 0; index3 < 3; ++index3) { | 409 } |
| 410 for (int index3 = 0; index3 < (int) SK_ARRAY_COUNT(segment); ++index
3) { |
439 IntersectData& data = dataArray[index2 + index3]; | 411 IntersectData& data = dataArray[index2 + index3]; |
440 SkPoint* temp = (SkPoint*) SkOpTAllocator<FourPoints>::Allocate(
&allocator); | 412 SkPoint temp[4]; |
441 for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) { | 413 for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) { |
442 temp[idx2] = data.fPts.fPts[idx2].asSkPoint(); | 414 temp[idx2] = data.fPts.fPts[idx2].asSkPoint(); |
443 } | 415 } |
444 switch (data.fPtCount) { | 416 switch (data.fPtCount) { |
445 case 2: { | 417 case 2: { |
446 contour.addLine(temp, &allocator); | 418 SkDLine seg = SkDLine::SubDivide(temp, data.fTStart, |
| 419 data.fTStart < data.fTEnd ? 1 : 0); |
| 420 data.fShortPts[0] = seg[0].asSkPoint(); |
| 421 data.fShortPts[1] = seg[1].asSkPoint(); |
| 422 PathOpsSegmentTester::ConstructLine(&segment[index3], da
ta.fShortPts); |
447 } break; | 423 } break; |
448 case 3: { | 424 case 3: { |
449 contour.addQuad(temp, &allocator); | 425 SkDQuad seg = SkDQuad::SubDivide(temp, data.fTStart, dat
a.fTEnd); |
| 426 data.fShortPts[0] = seg[0].asSkPoint(); |
| 427 data.fShortPts[1] = seg[1].asSkPoint(); |
| 428 data.fShortPts[2] = seg[2].asSkPoint(); |
| 429 PathOpsSegmentTester::ConstructQuad(&segment[index3], da
ta.fShortPts); |
450 } break; | 430 } break; |
451 case 4: { | 431 case 4: { |
452 contour.addCubic(temp, &allocator); | 432 SkDCubic seg = SkDCubic::SubDivide(temp, data.fTStart, d
ata.fTEnd); |
| 433 data.fShortPts[0] = seg[0].asSkPoint(); |
| 434 data.fShortPts[1] = seg[1].asSkPoint(); |
| 435 data.fShortPts[2] = seg[2].asSkPoint(); |
| 436 data.fShortPts[3] = seg[3].asSkPoint(); |
| 437 PathOpsSegmentTester::ConstructCubic(&segment[index3], d
ata.fShortPts); |
453 } break; | 438 } break; |
454 } | 439 } |
455 } | 440 } |
456 SkOpSegment* seg1 = contour.first(); | 441 SkOpAngle& angle1 = *const_cast<SkOpAngle*>(segment[0].debugLastAngl
e()); |
457 seg1->debugAddAngle(dataArray[index2 + 0].fTStart, dataArray[index2
+ 0].fTEnd, &allocator); | 442 SkOpAngle& angle2 = *const_cast<SkOpAngle*>(segment[1].debugLastAngl
e()); |
458 SkOpSegment* seg2 = seg1->next(); | 443 SkOpAngle& angle3 = *const_cast<SkOpAngle*>(segment[2].debugLastAngl
e()); |
459 seg2->debugAddAngle(dataArray[index2 + 1].fTStart, dataArray[index2
+ 1].fTEnd, &allocator); | |
460 SkOpSegment* seg3 = seg2->next(); | |
461 seg3->debugAddAngle(dataArray[index2 + 2].fTStart, dataArray[index2
+ 2].fTEnd, &allocator); | |
462 SkOpAngle& angle1 = *seg1->debugLastAngle(); | |
463 SkOpAngle& angle2 = *seg2->debugLastAngle(); | |
464 SkOpAngle& angle3 = *seg3->debugLastAngle(); | |
465 PathOpsAngleTester::SetNext(angle1, angle3); | 444 PathOpsAngleTester::SetNext(angle1, angle3); |
466 // These data sets are seeded when the set itself fails, so likely the da
taset does not | 445 // These data sets are seeded when the set itself fails, so likely the da
taset does not |
467 // match the expected result. The tests above return 1 when first added,
but | 446 // match the expected result. The tests above return 1 when first added,
but |
468 // return 0 after the bug is fixed. | 447 // return 0 after the bug is fixed. |
469 SkDEBUGCODE(int result =) PathOpsAngleTester::After(angle2, angle1); | 448 SkDEBUGCODE(int result =) PathOpsAngleTester::After(angle2, angle1); |
470 SkASSERT(result == 0 || result == 1); | 449 SkASSERT(result == 0 || result == 1); |
471 } | 450 } |
472 } | 451 } |
473 } | 452 } |
474 | 453 |
475 void SkOpSegment::debugAddAngle(double startT, double endT, SkChunkAlloc* alloca
tor) { | 454 void SkOpSegment::debugConstruct() { |
476 SkOpPtT* startPtT = startT == 0 ? fHead.ptT() : startT == 1 ? fTail.ptT() | 455 addStartSpan(1); |
477 : this->addT(startT, kNoAlias, allocator); | 456 addEndSpan(1); |
478 SkOpPtT* endPtT = endT == 0 ? fHead.ptT() : endT == 1 ? fTail.ptT() | 457 debugAddAngle(0, 1); |
479 : this->addT(endT, kNoAlias, allocator); | |
480 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); | |
481 SkOpSpanBase* startSpan = &fHead; | |
482 while (startSpan->ptT() != startPtT) { | |
483 startSpan = startSpan->upCast()->next(); | |
484 } | |
485 SkOpSpanBase* endSpan = &fHead; | |
486 while (endSpan->ptT() != endPtT) { | |
487 endSpan = endSpan->upCast()->next(); | |
488 } | |
489 angle->set(startSpan, endSpan); | |
490 if (startT < endT) { | |
491 startSpan->upCast()->setToAngle(angle); | |
492 endSpan->setFromAngle(angle); | |
493 } else { | |
494 endSpan->upCast()->setToAngle(angle); | |
495 startSpan->setFromAngle(angle); | |
496 } | |
497 } | 458 } |
| 459 |
| 460 void SkOpSegment::debugAddAngle(int start, int end) { |
| 461 SkASSERT(start != end); |
| 462 SkOpAngle& angle = fAngles.push_back(); |
| 463 angle.set(this, start, end); |
| 464 } |
| 465 |
| 466 void SkOpSegment::debugConstructCubic(SkPoint shortQuad[4]) { |
| 467 addCubic(shortQuad, false, false); |
| 468 addT(NULL, shortQuad[0], 0); |
| 469 addT(NULL, shortQuad[3], 1); |
| 470 debugConstruct(); |
| 471 } |
| 472 |
| 473 void SkOpSegment::debugConstructLine(SkPoint shortQuad[2]) { |
| 474 addLine(shortQuad, false, false); |
| 475 addT(NULL, shortQuad[0], 0); |
| 476 addT(NULL, shortQuad[1], 1); |
| 477 debugConstruct(); |
| 478 } |
| 479 |
| 480 void SkOpSegment::debugConstructQuad(SkPoint shortQuad[3]) { |
| 481 addQuad(shortQuad, false, false); |
| 482 addT(NULL, shortQuad[0], 0); |
| 483 addT(NULL, shortQuad[2], 1); |
| 484 debugConstruct(); |
| 485 } |
OLD | NEW |