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