C++程序  |  270行  |  10.49 KB

#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<Quadratic> 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<Quadratic> 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<Quadratic> 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<Quadratic> 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<Quadratic> 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<Quadratic> 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("<div id=\"cubic%dx%d%s\">\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<Quadratic> 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("</div>\n\n");
#if TEST_AVERAGE_END_POINTS
            }
#endif
        }
    }
    SkDebugf("</div>\n\n");
    SkDebugf("<script type=\"text/javascript\">\n\n");
    SkDebugf("var testDivs = [\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) {
#else
            int w = 0;
#endif
                SkDebugf("    cubic%dx%d%s,\n", x + 1, y, w ? "x" : "");
#if TEST_AVERAGE_END_POINTS
            }
#endif
        }
    }
    SkDebugf("\n\n\n");
    SkDebugf("%s end\n", __FUNCTION__);
}