C++程序  |  343行  |  11.84 KB

/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Simplify.h"

namespace SimplifyAngleTest {

#include "Simplify.cpp"

} // end of SimplifyAngleTest namespace

#include "Intersection_Tests.h"

static const SkPoint lines[][2] = {
    { { 10,  10}, { 10,  20} },
    { { 10,  10}, { 20,  10} },
    { { 10,  10}, {-20,  10} },
    { { 10,  10}, { 10, -20} },
    { { 10,  10}, { 20,  20} },
    { { 10,  10}, {-20, -20} },
    { { 10,  10}, {-20,  40} },
    { { 10,  10}, { 40, -20} }
};

static const size_t lineCount = sizeof(lines) / sizeof(lines[0]);

static const SkPoint quads[][3] = {
    {{ 1,  1}, { 2,  2}, { 1,  3}}, // 0
    {{ 1,  1}, { 3,  3}, { 1,  5}}, // 1
    {{ 1,  1}, { 4,  4}, { 1,  7}}, // 2
    {{ 1,  1}, { 5,  5}, { 9,  9}}, // 3
    {{ 1,  1}, { 4,  4}, { 7,  1}}, // 4
    {{ 1,  1}, { 3,  3}, { 5,  1}}, // 5
    {{ 1,  1}, { 2,  2}, { 3,  1}}, // 6
};

static const size_t quadCount = sizeof(quads) / sizeof(quads[0]);

static const SkPoint cubics[][4] = {
    {{ 1,  1}, { 2,  2}, { 2,  3}, { 1,  4}},
    {{ 1,  1}, { 3,  3}, { 3,  5}, { 1,  7}},
    {{ 1,  1}, { 4,  4}, { 4,  7}, { 1,  10}},
    {{ 1,  1}, { 5,  5}, { 8,  8}, { 9,  9}},
    {{ 1,  1}, { 4,  4}, { 7,  4}, { 10, 1}},
    {{ 1,  1}, { 3,  3}, { 5,  3}, { 7,  1}},
    {{ 1,  1}, { 2,  2}, { 3,  2}, { 4,  1}},
};

static const size_t cubicCount = sizeof(cubics) / sizeof(cubics[0]);

struct segment {
    SkPath::Verb verb;
    SkPoint pts[4];
};

static const segment segmentTest1[] = {
    {SkPath::kLine_Verb, {{2, 1}, {1, 0}        }},
    {SkPath::kQuad_Verb, {{2, 1}, {1, 0}, {0, 0}}},
    {SkPath::kQuad_Verb, {{2, 1}, {3, 2}, {2, 3}}},
    {SkPath::kLine_Verb, {{2, 1}, {3, 2}        }},
    {SkPath::kMove_Verb                          }
};

static const segment segmentTest2[] = {
    {SkPath::kLine_Verb, {{1, 0}, {0, 0}        }},
    {SkPath::kQuad_Verb, {{1, 0}, {1.89897954f, 0.898979485f}, {2.39387703f, 1.59591794f}}},
    {SkPath::kLine_Verb, {{1, 0}, {3, 2}        }},
    {SkPath::kMove_Verb                          }
};

static const segment segmentTest3[] = {
    {SkPath::kQuad_Verb, {{0, 0}, {2, 0}, {0, 1}}},
    {SkPath::kQuad_Verb, {{0, 0}, {1, 0}, {0, 1}}},
    {SkPath::kMove_Verb                          }
};

static const segment* segmentTests[] = {
    segmentTest3,
    segmentTest2,
    segmentTest1,
};

static const size_t segmentTestCount = sizeof(segmentTests) / sizeof(segmentTests[0]);

static void testSegments(bool testFlat) {
    for (size_t testIndex = 0; testIndex < segmentTestCount; ++testIndex) {
        const segment* segPtr = segmentTests[testIndex];
        SimplifyAngleTest::Angle lesser, greater;
        int index = 0;
        do {
            int next = index + 1;
            SkTDArray<SimplifyAngleTest::Span> dummy;
            lesser.set(segPtr[index].pts, segPtr[index].verb, NULL, index, next, dummy);
            if (segPtr[next].verb == SkPath::kMove_Verb) {
                break;
            }
            greater.set(segPtr[next].pts, segPtr[next].verb, NULL, index, next, dummy);
            bool result = lesser < greater;
            SkASSERT(result);
            index = next;
        } while (true);
    }
}

static void testLines(bool testFlat) {
    // create angles in a circle
    SkTDArray<SimplifyAngleTest::Angle> angles;
    SkTDArray<SimplifyAngleTest::Angle* > angleList;
    SkTDArray<double> arcTans;
    size_t x;
    for (x = 0; x < lineCount; ++x) {
        SimplifyAngleTest::Angle* angle = angles.append();
        SkTDArray<SimplifyAngleTest::Span> dummy;
        angle->set(lines[x], SkPath::kLine_Verb, 0, x, x + 1, dummy);
        double arcTan = atan2(lines[x][0].fX - lines[x][1].fX,
                lines[x][0].fY - lines[x][1].fY);
        arcTans.push(arcTan);
    }
    for (x = 0; x < lineCount; ++x) {
        angleList.push(&angles[x]);
    }
    QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
    bool first = true;
    bool wrap = false;
    double base, last;
    for (size_t x = 0; x < lineCount; ++x) {
        const SimplifyAngleTest::Angle* angle = angleList[x];
        int span = angle->start();
//        SkDebugf("%s [%d] %1.9g (%1.9g,%1.9g %1.9g,%1.9g)\n", __FUNCTION__,
//                span, arcTans[span], lines[span][0].fX, lines[span][0].fY,
//                lines[span][1].fX, lines[span][1].fY);
        if (first) {
            base = last = arcTans[span];
            first = false;
            continue;
        }
        if (last < arcTans[span]) {
            last = arcTans[span];
            continue;
        }
        if (!wrap) {
            if (base < arcTans[span]) {
                SkDebugf("%s !wrap [%d] %g\n", __FUNCTION__, span, arcTans[span]);
                SkASSERT(0);
            }
            last = arcTans[span];
            wrap = true;
            continue;
        }
        SkDebugf("%s wrap [%d] %g\n", __FUNCTION__, span, arcTans[span]);
        SkASSERT(0);
    }
}

static void testQuads(bool testFlat) {
    SkTDArray<SimplifyAngleTest::Angle> angles;
    SkTDArray<SimplifyAngleTest::Angle* > angleList;
    size_t x;
    for (x = 0; x < quadCount; ++x) {
        SimplifyAngleTest::Angle* angle = angles.append();
        SkTDArray<SimplifyAngleTest::Span> dummy;
        angle->set(quads[x], SkPath::kQuad_Verb, 0, x, x + 1, dummy);
   }
    for (x = 0; x < quadCount; ++x) {
        angleList.push(&angles[x]);
    }
    QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
    for (size_t x = 0; x < quadCount; ++x) {
        *angleList[x] < *angleList[x + 1];
        SkASSERT(x == quadCount - 1 || *angleList[x] < *angleList[x + 1]);
        const SimplifyAngleTest::Angle* angle = angleList[x];
        if ((int) x != angle->start()) {
            SkDebugf("%s [%d] [%d]\n", __FUNCTION__, x, angle->start());
            SkASSERT(0);
        }
    }
}

static void testCubics(bool testFlat) {
    SkTDArray<SimplifyAngleTest::Angle> angles;
    SkTDArray<SimplifyAngleTest::Angle* > angleList;
    for (size_t x = 0; x < cubicCount; ++x) {
        SimplifyAngleTest::Angle* angle = angles.append();
            SkTDArray<SimplifyAngleTest::Span> dummy;
        angle->set(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1, dummy);
        angleList.push(angle);
    }
    QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
    for (size_t x = 0; x < cubicCount; ++x) {
        const SimplifyAngleTest::Angle* angle = angleList[x];
        if ((int) x != angle->start()) {
            SkDebugf("%s [%d] [%d]\n", __FUNCTION__, x, angle->start());
            SkASSERT(0);
        }
    }
}

struct segmentWithT {
    SkPath::Verb verb;
    SkPoint pts[4];
    double ts[2];
};


static const segmentWithT oneOffTest1[] = {
    {SkPath::kQuad_Verb, {{391.653534f, 183.286819f}, {391.653534f, 157.724487f}, {405.469604f, 141.372879f}},
        {0.62346946335026932, 0.62344389027237135}},
    {SkPath::kQuad_Verb, {{399.365234f, 171.695801f}, {399.365234f, 140.337967f}, {375.976227f, 140.337967f}},
        {0.31638302676995866, 0.31637992418411398}},
    {SkPath::kMove_Verb }
};

static const segmentWithT oneOffTest2[] = {
    {SkPath::kQuad_Verb, {{399.070374f, 151.722f}, {391.101532f, 163.002533f}, {391.101532f, 182.665863f}},
        {0.13793711854916513, 0.13790171160614006}},
    {SkPath::kQuad_Verb, {{391.653534f, 183.286819f}, {391.653534f, 157.724487f}, {405.469604f, 141.372879f}},
        {0.62344389027237135, 0.62346946335026932}},
    {SkPath::kMove_Verb }
};

static const segmentWithT oneOffTest3[] = {
    {SkPath::kQuad_Verb, {{399.365234f, 171.695801f}, {399.365234f, 140.337967f}, {375.976227f, 140.337967f}},
        {0.31637992418411398, 0.31638302676995866, }},
    {SkPath::kQuad_Verb, {{399.070374f, 151.722f}, {391.101532f, 163.002533f}, {391.101532f, 182.665863f}},
        {0.13790171160614006, 0.13793711854916513}},
    {SkPath::kMove_Verb }
};

static const segmentWithT oneOffTest4[] = {
    {SkPath::kCubic_Verb, {{1,2}, {1,3}, {1,0}, {5,3}}, {0.134792, 0}},
    {SkPath::kCubic_Verb, {{0,1}, {3,5}, {2,1}, {3,1}}, {0.134792094, 0}},
    {SkPath::kCubic_Verb, {{0,1}, {3,5}, {2,1}, {3,1}}, {0.134792094, 0.551812363}},
    {SkPath::kCubic_Verb, {{1,2}, {1,3}, {1,0}, {5,3}}, {0.134792, 0.333333333}},
    {SkPath::kMove_Verb }
};

static const segmentWithT* oneOffTests[] = {
    oneOffTest1,
    oneOffTest2,
    oneOffTest3,
    oneOffTest4,
};

static const size_t oneOffTestCount = sizeof(oneOffTests) / sizeof(oneOffTests[0]);

static void oneOffTest(bool testFlat) {
    for (size_t testIndex = 0; testIndex < oneOffTestCount; ++testIndex) {
        const segmentWithT* segPtr = oneOffTests[testIndex];
        SimplifyAngleTest::Angle lesser, greater;
        int index = 0;
        do {
            int next = index + 1;
            SkTDArray<SimplifyAngleTest::Span> dummy; // FIXME
            lesser.set(segPtr[index].pts, segPtr[index].verb, 0, index, next, dummy); // FIXME: segPtr[index].ts[0], segPtr[index].ts[1]);
            if (segPtr[next].verb == SkPath::kMove_Verb) {
                break;
            }
            greater.set(segPtr[next].pts, segPtr[next].verb, 0, index, next, dummy); // FIXME: segPtr[next].ts[0], segPtr[next].ts[1]);
            bool result = lesser < greater;
            SkASSERT(result);
            index = next;
        } while (true);
    }
    SkDebugf("%s finished\n", __FUNCTION__);
}

#if 0 // seems too complicated for this to be useful (didn't finish writing/debugging this)
// this (trys to) take a pair of curves, construct segments/spans, and verify that they sort correctly
static void oneOffTestNew() {
    const segmentWithT* segPtr = oneOffTest4;
    SimplifyAngleTest::Segment segOne, segTwo;
    segOne.init(segPtr[0].pts, segPtr[0].verb, false, false);
    segTwo.init(segPtr[1].pts, segPtr[1].verb, false, false);
    int index = 0;
    do {
        int next = index + 1;
        if (segPtr[index].verb == SkPath::kMove_Verb) {
            break;
        }
        SkPoint sub[4];
        (*SegmentSubDivide[segPtr[index].verb])(segPtr[index].pts, segPtr[index].ts[0],
                segPtr[index].ts[1], sub);
        if (memcmp(segPtr[index].pts, segPtr[0].pts, sizeof(SkPoint) * (segPtr[index].verb + 1) == 0) {
            segOne.addT(&segTwo, sub[0], segPtr[index].ts[0]);
            segOne.addT(&segTwo, sub[segPtr[index].verb], segPtr[index].ts[1]);
        } else {
            segTwo.addT(&segOne, sub[0], segPtr[index].ts[0]);
            segTwo.addT(&v, sub[segPtr[index].verb], segPtr[index].ts[1]);
        }
    } while (true);
    SimplifyAngleTest::Angle lesser, greater;
    do {
        int next = index + 1;
        if (segPtr[next].verb == SkPath::kMove_Verb) {
            break;
        }
        SkPoint one[4], two[4];
        bool use1 = memcmp(segPtr[index].pts, segPtr[0].pts, sizeof(SkPoint) * (segPtr[index].verb + 1) == 0;
        lesser.set(segPtr[index].pts, segPtr[index].verb, use1 ? &segOne : &segTwo, index, next, dummy);
        use1 = memcmp(segPtr[next].pts, segPtr[0].pts, sizeof(SkPoint) * (segPtr[next].verb + 1) == 0;
        greater.set(segPtr[next].pts, segPtr[next].verb, use1 ? &segOne : &segTwo, index, next, dummy);
        bool result = lesser < greater;
        SkASSERT(result);
        index = next;
    } while (true);
    SkDebugf("%s finished\n", __FUNCTION__);
}
#endif

static void (*tests[])(bool) = {
    oneOffTest,
    testSegments,
    testLines,
    testQuads,
    testCubics
};

static const size_t testCount = sizeof(tests) / sizeof(tests[0]);

static void (*firstTest)(bool) = 0;
static bool skipAll = false;

void SimplifyAngle_Test() {
    if (skipAll) {
        return;
    }
    size_t index = 0;
    if (firstTest) {
        while (index < testCount && tests[index] != firstTest) {
            ++index;
        }
    }
    bool firstTestComplete = false;
    for ( ; index < testCount; ++index) {
        (*tests[index])(false); // set to true to exercise setFlat
        firstTestComplete = true;
    }
}