#include "CubicIntersection_TestData.h" #include "CubicUtilities.h" #include "Intersection_Tests.h" #include "QuadraticIntersection_TestData.h" #include "TestUtilities.h" #include "SkGeometry.h" static void test(const Cubic* cubics, const char* name, int firstTest, size_t testCount) { SkTDArray quads; for (size_t index = firstTest; index < testCount; ++index) { const Cubic& cubic = cubics[index]; double precision = calcPrecision(cubic); (void) cubic_to_quadratics(cubic, precision, quads); if (quads.count() != 1) { printf("%s [%d] cubic to quadratics failed count=%d\n", name, (int) index, quads.count()); } } } static void test(const Quadratic* quadTests, const char* name, int firstTest, size_t testCount) { SkTDArray quads; for (size_t index = firstTest; index < testCount; ++index) { const Quadratic& quad = quadTests[index]; Cubic cubic; quad_to_cubic(quad, cubic); double precision = calcPrecision(cubic); (void) cubic_to_quadratics(cubic, precision, quads); if (quads.count() != 1) { printf("%s [%d] cubic to quadratics failed count=%d\n", name, (int) index, quads.count()); } } } static void testC(const Cubic* cubics, const char* name, int firstTest, size_t testCount) { SkTDArray quads; // test if computed line end points are valid for (size_t index = firstTest; index < testCount; ++index) { const Cubic& cubic = cubics[index]; double precision = calcPrecision(cubic); int order = cubic_to_quadratics(cubic, precision, quads); SkASSERT(order != 4); if (order < 3) { continue; } if (!AlmostEqualUlps(cubic[0].x, quads[0][0].x) || !AlmostEqualUlps(cubic[0].y, quads[0][0].y)) { printf("[%d] unmatched start\n", (int) index); } int last = quads.count() - 1; if (!AlmostEqualUlps(cubic[3].x, quads[last][2].x) || !AlmostEqualUlps(cubic[3].y, quads[last][2].y)) { printf("[%d] unmatched end\n", (int) index); } } } static void testC(const Cubic(* cubics)[2], const char* name, int firstTest, size_t testCount) { SkTDArray quads; for (size_t index = firstTest; index < testCount; ++index) { for (int idx2 = 0; idx2 < 2; ++idx2) { const Cubic& cubic = cubics[index][idx2]; double precision = calcPrecision(cubic); int order = cubic_to_quadratics(cubic, precision, quads); SkASSERT(order != 4); if (order < 3) { continue; } if (!AlmostEqualUlps(cubic[0].x, quads[0][0].x) || !AlmostEqualUlps(cubic[0].y, quads[0][0].y)) { printf("[%d][%d] unmatched start\n", (int) index, idx2); } int last = quads.count() - 1; if (!AlmostEqualUlps(cubic[3].x, quads[last][2].x) || !AlmostEqualUlps(cubic[3].y, quads[last][2].y)) { printf("[%d][%d] unmatched end\n", (int) index, idx2); } } } } void CubicToQuadratics_Test() { enum { RunAll, RunPointDegenerates, RunNotPointDegenerates, RunLines, RunNotLines, RunModEpsilonLines, RunLessEpsilonLines, RunNegEpsilonLines, RunQuadraticLines, RunQuadraticModLines, RunComputedLines, RunComputedTests, RunNone } run = RunAll; int firstTestIndex = 0; #if 0 run = RunComputedLines; firstTestIndex = 18; #endif int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates ? firstTestIndex : SK_MaxS32; int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates ? firstTestIndex : SK_MaxS32; int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : SK_MaxS32; int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : SK_MaxS32; int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines ? firstTestIndex : SK_MaxS32; int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines ? firstTestIndex : SK_MaxS32; int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines ? firstTestIndex : SK_MaxS32; int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines ? firstTestIndex : SK_MaxS32; int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines ? firstTestIndex : SK_MaxS32; int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines ? firstTestIndex : SK_MaxS32; int firstComputedCubicsTest = run == RunAll ? 0 : run == RunComputedTests ? firstTestIndex : SK_MaxS32; test(pointDegenerates, "pointDegenerates", firstPointDegeneratesTest, pointDegenerates_count); test(notPointDegenerates, "notPointDegenerates", firstNotPointDegeneratesTest, notPointDegenerates_count); test(lines, "lines", firstLinesTest, lines_count); test(notLines, "notLines", firstNotLinesTest, notLines_count); test(modEpsilonLines, "modEpsilonLines", firstModEpsilonTest, modEpsilonLines_count); test(lessEpsilonLines, "lessEpsilonLines", firstLessEpsilonTest, lessEpsilonLines_count); test(negEpsilonLines, "negEpsilonLines", firstNegEpsilonTest, negEpsilonLines_count); test(quadraticLines, "quadraticLines", firstQuadraticLineTest, quadraticLines_count); test(quadraticModEpsilonLines, "quadraticModEpsilonLines", firstQuadraticModLineTest, quadraticModEpsilonLines_count); testC(lines, "computed lines", firstComputedLinesTest, lines_count); testC(tests, "computed tests", firstComputedCubicsTest, tests_count); printf("%s end\n", __FUNCTION__); } static Cubic locals[] = { {{0, 1}, {1.9274705288631189e-19, 1.0000000000000002}, {0.0017190297609673323, 0.99828097023903239}, {0.0053709083094631276, 0.99505672974365911}}, {{14.5975863, 41.632436}, {16.3518929, 26.2639684}, {18.5165519, 7.68775139}, {8.03767257, 89.1628526}}, {{69.7292014, 38.6877352}, {24.7648688, 23.1501713}, {84.9283191, 90.2588441}, {80.392774, 61.3533852}}, {{ 60.776536520932126, 71.249307306133829 }, { 87.107894191103014, 22.377669868235323 }, { 1.4974754310666936, 68.069569937917208 }, { 45.261946574441133, 17.536076632112298 }}, }; static size_t localsCount = sizeof(locals) / sizeof(locals[0]); #define DEBUG_CRASH 0 #define TEST_AVERAGE_END_POINTS 0 // must take const off to test extern const bool AVERAGE_END_POINTS; static void oneOff(size_t x) { const Cubic& cubic = locals[x]; const SkPoint skcubic[4] = {{(float) cubic[0].x, (float) cubic[0].y}, {(float) cubic[1].x, (float) cubic[1].y}, {(float) cubic[2].x, (float) cubic[2].y}, {(float) cubic[3].x, (float) cubic[3].y}}; SkScalar skinflect[2]; int skin = SkFindCubicInflections(skcubic, skinflect); SkDebugf("%s %d %1.9g\n", __FUNCTION__, skin, skinflect[0]); SkTDArray quads; double precision = calcPrecision(cubic); (void) cubic_to_quadratics(cubic, precision, quads); SkDebugf("%s quads=%d\n", __FUNCTION__, quads.count()); } void CubicsToQuadratics_OneOffTests() { for (size_t x = 0; x < localsCount; ++x) { oneOff(x); } } void CubicsToQuadratics_OneOffTest() { oneOff(0); } void CubicsToQuadratics_RandTest() { srand(0); const int arrayMax = 8; const int sampleMax = 10; const int tests = 1000000; // 10000000; int quadDist[arrayMax]; bzero(quadDist, sizeof(quadDist)); Cubic samples[arrayMax][sampleMax]; int sampleCount[arrayMax]; bzero(sampleCount, sizeof(sampleCount)); for (int x = 0; x < tests; ++x) { Cubic cubic; for (int i = 0; i < 4; ++i) { cubic[i].x = (double) rand() / RAND_MAX * 100; cubic[i].y = (double) rand() / RAND_MAX * 100; } #if DEBUG_CRASH char str[1024]; sprintf(str, "{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}},\n", cubic[0].x, cubic[0].y, cubic[1].x, cubic[1].y, cubic[2].x, cubic[2].y, cubic[3].x, cubic[3].y); #endif SkTDArray quads; double precision = calcPrecision(cubic); (void) cubic_to_quadratics(cubic, precision, quads); int count = quads.count(); SkASSERT(count > 0); SkASSERT(--count < arrayMax); quadDist[count]++; int sCount = sampleCount[count]; if (sCount < sampleMax) { memcpy(samples[count][sCount], cubic, sizeof(Cubic)); sampleCount[count]++; } } for (int x = 0; x < arrayMax; ++x) { if (!quadDist[x]) { continue; } SkDebugf("%d %1.9g%%\n", x + 1, (double) quadDist[x] / tests * 100); } SkDebugf("\n"); for (int x = 0; x < arrayMax; ++x) { for (int y = 0; y < sampleCount[x]; ++y) { #if TEST_AVERAGE_END_POINTS for (int w = 0; w < 2; ++w) { AVERAGE_END_POINTS = w; #else int w = 0; #endif SkDebugf("
\n", x + 1, y, w ? "x" : ""); const Cubic& cubic = samples[x][y]; SkDebugf("{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}},\n", cubic[0].x, cubic[0].y, cubic[1].x, cubic[1].y, cubic[2].x, cubic[2].y, cubic[3].x, cubic[3].y); SkTDArray quads; double precision = calcPrecision(cubic); (void) cubic_to_quadratics(cubic, precision, quads); for (int z = 0; z < quads.count(); ++z) { const Quadratic& quad = quads[z]; SkDebugf("{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}},\n", quad[0].x, quad[0].y, quad[1].x, quad[1].y, quad[2].x, quad[2].y); } SkDebugf("
\n\n"); #if TEST_AVERAGE_END_POINTS } #endif } } SkDebugf("\n\n"); SkDebugf("