caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 1 | #include "CubicIntersection_TestData.h" |
| 2 | #include "CubicUtilities.h" |
| 3 | #include "Intersection_Tests.h" |
| 4 | #include "QuadraticIntersection_TestData.h" |
| 5 | #include "TestUtilities.h" |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 6 | #include "SkGeometry.h" |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 7 | |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 8 | static void test(const Cubic* cubics, const char* name, int firstTest, size_t testCount) { |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 9 | SkTDArray<Quadratic> quads; |
| 10 | for (size_t index = firstTest; index < testCount; ++index) { |
| 11 | const Cubic& cubic = cubics[index]; |
| 12 | double precision = calcPrecision(cubic); |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 13 | (void) cubic_to_quadratics(cubic, precision, quads); |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 14 | if (quads.count() != 1) { |
| 15 | printf("%s [%d] cubic to quadratics failed count=%d\n", name, (int) index, |
| 16 | quads.count()); |
| 17 | } |
| 18 | } |
| 19 | } |
| 20 | |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 21 | static void test(const Quadratic* quadTests, const char* name, int firstTest, size_t testCount) { |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 22 | SkTDArray<Quadratic> quads; |
| 23 | for (size_t index = firstTest; index < testCount; ++index) { |
| 24 | const Quadratic& quad = quadTests[index]; |
| 25 | Cubic cubic; |
| 26 | quad_to_cubic(quad, cubic); |
| 27 | double precision = calcPrecision(cubic); |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 28 | (void) cubic_to_quadratics(cubic, precision, quads); |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 29 | if (quads.count() != 1) { |
| 30 | printf("%s [%d] cubic to quadratics failed count=%d\n", name, (int) index, |
| 31 | quads.count()); |
| 32 | } |
| 33 | } |
| 34 | } |
| 35 | |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 36 | static void testC(const Cubic* cubics, const char* name, int firstTest, size_t testCount) { |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 37 | SkTDArray<Quadratic> quads; |
| 38 | // test if computed line end points are valid |
| 39 | for (size_t index = firstTest; index < testCount; ++index) { |
| 40 | const Cubic& cubic = cubics[index]; |
| 41 | double precision = calcPrecision(cubic); |
| 42 | int order = cubic_to_quadratics(cubic, precision, quads); |
| 43 | assert(order != 4); |
| 44 | if (order < 3) { |
| 45 | continue; |
| 46 | } |
| 47 | if (!AlmostEqualUlps(cubic[0].x, quads[0][0].x) |
| 48 | || !AlmostEqualUlps(cubic[0].y, quads[0][0].y)) { |
| 49 | printf("[%d] unmatched start\n", (int) index); |
| 50 | } |
| 51 | int last = quads.count() - 1; |
| 52 | if (!AlmostEqualUlps(cubic[3].x, quads[last][2].x) |
| 53 | || !AlmostEqualUlps(cubic[3].y, quads[last][2].y)) { |
| 54 | printf("[%d] unmatched end\n", (int) index); |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 59 | static void testC(const Cubic(* cubics)[2], const char* name, int firstTest, size_t testCount) { |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 60 | SkTDArray<Quadratic> quads; |
| 61 | for (size_t index = firstTest; index < testCount; ++index) { |
| 62 | for (int idx2 = 0; idx2 < 2; ++idx2) { |
| 63 | const Cubic& cubic = cubics[index][idx2]; |
| 64 | double precision = calcPrecision(cubic); |
| 65 | int order = cubic_to_quadratics(cubic, precision, quads); |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 66 | assert(order != 4); |
| 67 | if (order < 3) { |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 68 | continue; |
| 69 | } |
| 70 | if (!AlmostEqualUlps(cubic[0].x, quads[0][0].x) |
| 71 | || !AlmostEqualUlps(cubic[0].y, quads[0][0].y)) { |
| 72 | printf("[%d][%d] unmatched start\n", (int) index, idx2); |
| 73 | } |
| 74 | int last = quads.count() - 1; |
| 75 | if (!AlmostEqualUlps(cubic[3].x, quads[last][2].x) |
| 76 | || !AlmostEqualUlps(cubic[3].y, quads[last][2].y)) { |
| 77 | printf("[%d][%d] unmatched end\n", (int) index, idx2); |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 83 | void CubicToQuadratics_Test() { |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 84 | enum { |
| 85 | RunAll, |
| 86 | RunPointDegenerates, |
| 87 | RunNotPointDegenerates, |
| 88 | RunLines, |
| 89 | RunNotLines, |
| 90 | RunModEpsilonLines, |
| 91 | RunLessEpsilonLines, |
| 92 | RunNegEpsilonLines, |
| 93 | RunQuadraticLines, |
| 94 | RunQuadraticModLines, |
| 95 | RunComputedLines, |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 96 | RunComputedTests, |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 97 | RunNone |
| 98 | } run = RunAll; |
| 99 | int firstTestIndex = 0; |
| 100 | #if 0 |
| 101 | run = RunComputedLines; |
| 102 | firstTestIndex = 18; |
| 103 | #endif |
| 104 | int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates ? firstTestIndex : INT_MAX; |
| 105 | int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates ? firstTestIndex : INT_MAX; |
| 106 | int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : INT_MAX; |
| 107 | int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : INT_MAX; |
| 108 | int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines ? firstTestIndex : INT_MAX; |
| 109 | int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines ? firstTestIndex : INT_MAX; |
| 110 | int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines ? firstTestIndex : INT_MAX; |
| 111 | int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines ? firstTestIndex : INT_MAX; |
| 112 | int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines ? firstTestIndex : INT_MAX; |
| 113 | int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines ? firstTestIndex : INT_MAX; |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 114 | int firstComputedCubicsTest = run == RunAll ? 0 : run == RunComputedTests ? firstTestIndex : INT_MAX; |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 115 | |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 116 | test(pointDegenerates, "pointDegenerates", firstPointDegeneratesTest, pointDegenerates_count); |
| 117 | test(notPointDegenerates, "notPointDegenerates", firstNotPointDegeneratesTest, notPointDegenerates_count); |
| 118 | test(lines, "lines", firstLinesTest, lines_count); |
| 119 | test(notLines, "notLines", firstNotLinesTest, notLines_count); |
| 120 | test(modEpsilonLines, "modEpsilonLines", firstModEpsilonTest, modEpsilonLines_count); |
| 121 | test(lessEpsilonLines, "lessEpsilonLines", firstLessEpsilonTest, lessEpsilonLines_count); |
| 122 | test(negEpsilonLines, "negEpsilonLines", firstNegEpsilonTest, negEpsilonLines_count); |
| 123 | test(quadraticLines, "quadraticLines", firstQuadraticLineTest, quadraticLines_count); |
| 124 | test(quadraticModEpsilonLines, "quadraticModEpsilonLines", firstQuadraticModLineTest, |
| 125 | quadraticModEpsilonLines_count); |
| 126 | testC(lines, "computed lines", firstComputedLinesTest, lines_count); |
| 127 | testC(tests, "computed tests", firstComputedCubicsTest, tests_count); |
| 128 | printf("%s end\n", __FUNCTION__); |
| 129 | } |
| 130 | |
| 131 | static Cubic locals[] = { |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 132 | {{14.5975863, 41.632436}, {16.3518929, 26.2639684}, {18.5165519, 7.68775139}, {8.03767257, 89.1628526}}, |
| 133 | {{69.7292014, 38.6877352}, {24.7648688, 23.1501713}, {84.9283191, 90.2588441}, {80.392774, 61.3533852}}, |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 134 | {{ |
| 135 | 60.776536520932126, |
| 136 | 71.249307306133829 |
| 137 | }, { |
skia.committer@gmail.com | 4e8ef33 | 2013-01-08 02:01:29 +0000 | [diff] [blame] | 138 | 87.107894191103014, |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 139 | 22.377669868235323 |
| 140 | }, { |
skia.committer@gmail.com | 4e8ef33 | 2013-01-08 02:01:29 +0000 | [diff] [blame] | 141 | 1.4974754310666936, |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 142 | 68.069569937917208 |
| 143 | }, { |
skia.committer@gmail.com | 4e8ef33 | 2013-01-08 02:01:29 +0000 | [diff] [blame] | 144 | 45.261946574441133, |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 145 | 17.536076632112298 |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 146 | }}, |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 147 | }; |
| 148 | |
| 149 | static size_t localsCount = sizeof(locals) / sizeof(locals[0]); |
| 150 | |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 151 | #define DEBUG_CRASH 0 |
| 152 | #define TEST_AVERAGE_END_POINTS 0 // must take const off to test |
| 153 | extern const bool AVERAGE_END_POINTS; |
| 154 | |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 155 | void CubicsToQuadratics_RandTest() { |
| 156 | for (size_t x = 0; x < localsCount; ++x) { |
| 157 | const Cubic& cubic = locals[x]; |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 158 | const SkPoint skcubic[4] = {{(float) cubic[0].x, (float) cubic[0].y}, |
| 159 | {(float) cubic[1].x, (float) cubic[1].y}, {(float) cubic[2].x, (float) cubic[2].y}, |
| 160 | {(float) cubic[3].x, (float) cubic[3].y}}; |
| 161 | SkScalar skinflect[2]; |
| 162 | int skin = SkFindCubicInflections(skcubic, skinflect); |
| 163 | SkDebugf("%s %d %1.9g\n", __FUNCTION__, skin, skinflect[0]); |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 164 | SkTDArray<Quadratic> quads; |
| 165 | double precision = calcPrecision(cubic); |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 166 | (void) cubic_to_quadratics(cubic, precision, quads); |
| 167 | SkDebugf("%s quads=%d\n", __FUNCTION__, quads.count()); |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 168 | } |
| 169 | srand(0); |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 170 | const int arrayMax = 8; |
| 171 | const int sampleMax = 10; |
| 172 | const int tests = 1000000; // 10000000; |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 173 | int quadDist[arrayMax]; |
| 174 | bzero(quadDist, sizeof(quadDist)); |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 175 | Cubic samples[arrayMax][sampleMax]; |
| 176 | int sampleCount[arrayMax]; |
| 177 | bzero(sampleCount, sizeof(sampleCount)); |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 178 | for (int x = 0; x < tests; ++x) { |
| 179 | Cubic cubic; |
| 180 | for (int i = 0; i < 4; ++i) { |
| 181 | cubic[i].x = (double) rand() / RAND_MAX * 100; |
| 182 | cubic[i].y = (double) rand() / RAND_MAX * 100; |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 183 | } |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 184 | #if DEBUG_CRASH |
| 185 | char str[1024]; |
| 186 | sprintf(str, "{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}},\n", |
| 187 | cubic[0].x, cubic[0].y, cubic[1].x, cubic[1].y, cubic[2].x, cubic[2].y, |
| 188 | cubic[3].x, cubic[3].y); |
| 189 | #endif |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 190 | SkTDArray<Quadratic> quads; |
| 191 | double precision = calcPrecision(cubic); |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 192 | (void) cubic_to_quadratics(cubic, precision, quads); |
| 193 | int count = quads.count(); |
| 194 | assert(count > 0); |
| 195 | assert(--count < arrayMax); |
| 196 | quadDist[count]++; |
| 197 | int sCount = sampleCount[count]; |
| 198 | if (sCount < sampleMax) { |
| 199 | memcpy(samples[count][sCount], cubic, sizeof(Cubic)); |
| 200 | sampleCount[count]++; |
| 201 | } |
caryclark@google.com | d68bc30 | 2013-01-07 13:17:18 +0000 | [diff] [blame] | 202 | } |
| 203 | for (int x = 0; x < arrayMax; ++x) { |
| 204 | if (!quadDist[x]) { |
| 205 | continue; |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 206 | } |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 207 | SkDebugf("%d %1.9g%%\n", x + 1, (double) quadDist[x] / tests * 100); |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 208 | } |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 209 | SkDebugf("\n"); |
| 210 | for (int x = 0; x < arrayMax; ++x) { |
| 211 | for (int y = 0; y < sampleCount[x]; ++y) { |
| 212 | #if TEST_AVERAGE_END_POINTS |
| 213 | for (int w = 0; w < 2; ++w) { |
| 214 | AVERAGE_END_POINTS = w; |
| 215 | #else |
| 216 | int w = 0; |
| 217 | #endif |
| 218 | SkDebugf("<div id=\"cubic%dx%d%s\">\n", x + 1, y, w ? "x" : ""); |
| 219 | const Cubic& cubic = samples[x][y]; |
| 220 | SkDebugf("{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}},\n", |
| 221 | cubic[0].x, cubic[0].y, cubic[1].x, cubic[1].y, cubic[2].x, cubic[2].y, |
| 222 | cubic[3].x, cubic[3].y); |
| 223 | SkTDArray<Quadratic> quads; |
| 224 | double precision = calcPrecision(cubic); |
| 225 | (void) cubic_to_quadratics(cubic, precision, quads); |
| 226 | for (int z = 0; z < quads.count(); ++z) { |
| 227 | const Quadratic& quad = quads[z]; |
| 228 | SkDebugf("{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}},\n", |
| 229 | quad[0].x, quad[0].y, quad[1].x, quad[1].y, quad[2].x, quad[2].y); |
| 230 | } |
| 231 | SkDebugf("</div>\n\n"); |
| 232 | #if TEST_AVERAGE_END_POINTS |
| 233 | } |
| 234 | #endif |
| 235 | } |
| 236 | } |
| 237 | SkDebugf("</div>\n\n"); |
| 238 | SkDebugf("<script type=\"text/javascript\">\n\n"); |
| 239 | SkDebugf("var testDivs = [\n"); |
| 240 | for (int x = 0; x < arrayMax; ++x) { |
| 241 | for (int y = 0; y < sampleCount[x]; ++y) { |
| 242 | #if TEST_AVERAGE_END_POINTS |
| 243 | for (int w = 0; w < 2; ++w) { |
| 244 | #else |
| 245 | int w = 0; |
| 246 | #endif |
| 247 | SkDebugf(" cubic%dx%d%s,\n", x + 1, y, w ? "x" : ""); |
| 248 | #if TEST_AVERAGE_END_POINTS |
| 249 | } |
| 250 | #endif |
| 251 | } |
| 252 | } |
| 253 | SkDebugf("\n\n\n"); |
| 254 | SkDebugf("%s end\n", __FUNCTION__); |
caryclark@google.com | 6d0032a | 2013-01-04 19:41:13 +0000 | [diff] [blame] | 255 | } |