コード例 #1
0
DEF_TEST(PathOpsAngleFindQuadEpsilon, reporter) {
    if (gDisableAngleTests) {
        return;
    }
    SkRandom ran;
    int maxEpsilon = 0;
    double maxAngle = 0;
    for (int index = 0; index < 100000; ++index) {
        SkDLine line = {{{0, 0}, {ran.nextRangeF(0.0001f, 1000), ran.nextRangeF(0.0001f, 1000)}}};
        float t = ran.nextRangeF(0.0001f, 1);
        SkDPoint dPt = line.ptAtT(t);
        float t2 = ran.nextRangeF(0.0001f, 1);
        SkDPoint qPt = line.ptAtT(t2);
        float t3 = ran.nextRangeF(0.0001f, 1);
        SkDPoint qPt2 = line.ptAtT(t3);
        qPt.fX += qPt2.fY;
        qPt.fY -= qPt2.fX;
        QuadPts q = {{line[0], dPt, qPt}};
        SkDQuad quad;
        quad.debugSet(q.fPts);
        // binary search for maximum movement of quad[1] towards test that still has 1 intersection
        double moveT = 0.5f;
        double deltaT = moveT / 2;
        SkDPoint last;
        do {
            last = quad[1];
            quad[1].fX = dPt.fX - line[1].fY * moveT;
            quad[1].fY = dPt.fY + line[1].fX * moveT;
            SkIntersections i;
            i.intersect(quad, line);
            REPORTER_ASSERT(reporter, i.used() > 0);
            if (i.used() == 1) {
                moveT += deltaT;
            } else {
                moveT -= deltaT;
            }
            deltaT /= 2;
        } while (last.asSkPoint() != quad[1].asSkPoint());
        float p1 = SkDoubleToScalar(line[1].fX * last.fY);
        float p2 = SkDoubleToScalar(line[1].fY * last.fX);
        int p1Bits = SkFloatAs2sCompliment(p1);
        int p2Bits = SkFloatAs2sCompliment(p2);
        int epsilon = SkTAbs(p1Bits - p2Bits);
        if (maxEpsilon < epsilon) {
            SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g/%1.7g/%1.7g moveT=%1.7g"
                    " pt={%1.7g, %1.7g} epsilon=%d\n",
                    line[1].fX, line[1].fY, t, t2, t3, moveT, last.fX, last.fY, epsilon);
            maxEpsilon = epsilon;
        }
        double a1 = atan2(line[1].fY, line[1].fX);
        double a2 = atan2(last.fY, last.fX);
        double angle = fabs(a1 - a2);
        if (maxAngle < angle) {
            SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g/%1.7g/%1.7g moveT=%1.7g"
                    " pt={%1.7g, %1.7g} angle=%1.7g\n",
                    line[1].fX, line[1].fY, t, t2, t3, moveT, last.fX, last.fY, angle);
            maxAngle = angle;
        }
    }
}
コード例 #2
0
ファイル: SampleHT.cpp プロジェクト: 03050903/skia
 HTDrawable(SkRandom& rand) {
     fR = SkRect::MakeXYWH(rand.nextRangeF(0, 640), rand.nextRangeF(0, 480),
                           rand.nextRangeF(20, 200), rand.nextRangeF(20, 200));
     fColor = rand_opaque_color(rand.nextU());
     fInterp = nullptr;
     fTime = 0;
 }
コード例 #3
0
DEF_TEST(PathOpsAngleFindCrossEpsilon, reporter) {
    if (gDisableAngleTests) {
        return;
    }
    SkRandom ran;
    int maxEpsilon = 0;
    for (int index = 0; index < 10000000; ++index) {
        SkDLine line = {{{0, 0}, {ran.nextRangeF(0.0001f, 1000), ran.nextRangeF(0.0001f, 1000)}}};
        for (int inner = 0; inner < 10; ++inner) {
            float t = ran.nextRangeF(0.0001f, 1);
            SkDPoint dPt = line.ptAtT(t);
            SkPoint pt = dPt.asSkPoint();
            float xs[3] = { prev(pt.fX), pt.fX, next(pt.fX) };
            float ys[3] = { prev(pt.fY), pt.fY, next(pt.fY) };
            for (int xIdx = 0; xIdx < 3; ++xIdx) {
                for (int yIdx = 0; yIdx < 3; ++yIdx) {
                    SkPoint test = { xs[xIdx], ys[yIdx] };
                    float p1 = SkDoubleToScalar(line[1].fX * test.fY);
                    float p2 = SkDoubleToScalar(line[1].fY * test.fX);
                    int p1Bits = SkFloatAs2sCompliment(p1);
                    int p2Bits = SkFloatAs2sCompliment(p2);
                    int epsilon = SkTAbs(p1Bits - p2Bits);
                    if (maxEpsilon < epsilon) {
                        SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g pt={%1.7g, %1.7g}"
                            " epsilon=%d\n",
                            line[1].fX, line[1].fY, t, test.fX, test.fY, epsilon);
                        maxEpsilon = epsilon;
                    }
                }
            }
        }
    }
}
コード例 #4
0
ファイル: RTreeBench.cpp プロジェクト: 03050903/skia
static inline SkRect make_random_rects(SkRandom& rand, int index, int numRects) {
    SkRect out;
    out.fLeft   = rand.nextRangeF(0, GENERATE_EXTENTS);
    out.fTop    = rand.nextRangeF(0, GENERATE_EXTENTS);
    out.fRight  = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
    out.fBottom = out.fTop  + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
    return out;
}
コード例 #5
0
ファイル: BBoxHierarchyTest.cpp プロジェクト: fsy351/skia
static SkRect random_rect(SkRandom& rand) {
    SkRect rect = {0,0,0,0};
    while (rect.isEmpty()) {
        rect.fLeft   = rand.nextRangeF(0, MAX_SIZE);
        rect.fRight  = rand.nextRangeF(0, MAX_SIZE);
        rect.fTop    = rand.nextRangeF(0, MAX_SIZE);
        rect.fBottom = rand.nextRangeF(0, MAX_SIZE);
        rect.sort();
    }
    return rect;
}
コード例 #6
0
 bool onAnimate(const SkAnimTimer& timer) override {
     // We add noise to the scale and rotation animations to 
     // keep the font atlas from falling into a steady state
     fRotation += (1.0f + gRand.nextRangeF(-0.1f, 0.1f));
     fScale += (fScaleInc + gRand.nextRangeF(-0.025f, 0.025f));
     if (fScale >= 2.0f) {
         fScaleInc = -0.1f;
     } else if (fScale <= 1.0f) {
         fScaleInc = 0.1f;
     }
     return true;
 }
コード例 #7
0
ファイル: RTreeBench.cpp プロジェクト: 03050903/skia
 void onDraw(int loops, SkCanvas* canvas) override {
     SkRandom rand;
     for (int i = 0; i < loops; ++i) {
         SkTDArray<int> hits;
         SkRect query;
         query.fLeft   = rand.nextRangeF(0, GENERATE_EXTENTS);
         query.fTop    = rand.nextRangeF(0, GENERATE_EXTENTS);
         query.fRight  = query.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
         query.fBottom = query.fTop  + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
         fTree.search(query, &hits);
     }
 }
コード例 #8
0
ファイル: RTreeBench.cpp プロジェクト: 03050903/skia
static inline SkRect make_XYordered_rects(SkRandom& rand, int index, int numRects) {
    SkRect out;
    out.fLeft   = SkIntToScalar(index % GRID_WIDTH);
    out.fTop    = SkIntToScalar(index / GRID_WIDTH);
    out.fRight  = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
    out.fBottom = out.fTop  + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
    return out;
}
コード例 #9
0
ファイル: PathOpsTightBoundsTest.cpp プロジェクト: DXGL/skia
static void testTightBoundsLines(PathOpsThreadState* data) {
    SkRandom ran;
    for (int index = 0; index < 1000; ++index) {
        SkPath path;
        int contourCount = ran.nextRangeU(1, 10);
        for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
            int lineCount = ran.nextRangeU(1, 10);
            path.moveTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
            for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
                path.lineTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
            }
            if (ran.nextBool()) {
                path.close();
            }
        }
        SkRect classicBounds = path.getBounds();
        SkRect tightBounds;
        REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
        REPORTER_ASSERT(data->fReporter, classicBounds == tightBounds);
    }
}
コード例 #10
0
ファイル: HairlinePathBench.cpp プロジェクト: Arternis/skia
 void makePath(SkPath* path) override {
     SkRandom rand;
     SkRandom randWeight;
     int size = SK_ARRAY_COUNT(points);
     int hSize = size / 2;
     for (int i = 0; i < kMaxPathSize; ++i) {
         int xTrans = 10 + 40 * (i%(kMaxPathSize/2));
         int yTrans = 0;
         if (i > kMaxPathSize/2 - 1) {
             yTrans = 40;
         }
         int base1 = 2 * rand.nextULessThan(hSize);
         int base2 = 2 * rand.nextULessThan(hSize);
         int base3 = 2 * rand.nextULessThan(hSize);
         float weight = randWeight.nextRangeF(0.0f, 2.0f);
         path->moveTo(SkIntToScalar(points[base1] + xTrans),
                      SkIntToScalar(points[base1+1] + yTrans));
         path->conicTo(SkIntToScalar(points[base2] + xTrans),
                       SkIntToScalar(points[base2+1] + yTrans),
                      SkIntToScalar(points[base3] + xTrans),
                      SkIntToScalar(points[base3+1] + yTrans),
                      weight);
     }
 }
コード例 #11
0
ファイル: MatrixTest.cpp プロジェクト: Adenilson/skia
static void test_matrix_homogeneous(skiatest::Reporter* reporter) {
    SkMatrix mat;

    const float kRotation0 = 15.5f;
    const float kRotation1 = -50.f;
    const float kScale0 = 5000.f;

    const int kTripleCount = 1000;
    const int kMatrixCount = 1000;
    SkRandom rand;

    SkScalar randTriples[3*kTripleCount];
    for (int i = 0; i < 3*kTripleCount; ++i) {
        randTriples[i] = rand.nextRangeF(-3000.f, 3000.f);
    }

    SkMatrix mats[kMatrixCount];
    for (int i = 0; i < kMatrixCount; ++i) {
        for (int j = 0; j < 9; ++j) {
            mats[i].set(j, rand.nextRangeF(-3000.f, 3000.f));
        }
    }

    // identity
    {
    mat.reset();
    SkScalar dst[3*kTripleCount];
    mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
    REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(randTriples, dst, kTripleCount*3));
    }

    // zero matrix
    {
    mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
    SkScalar dst[3*kTripleCount];
    mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
    SkScalar zeros[3] = {0.f, 0.f, 0.f};
    for (int i = 0; i < kTripleCount; ++i) {
        REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(&dst[i*3], zeros, 3));
    }
    }

    // zero point
    {
    SkScalar zeros[3] = {0.f, 0.f, 0.f};
    for (int i = 0; i < kMatrixCount; ++i) {
        SkScalar dst[3];
        mats[i].mapHomogeneousPoints(dst, zeros, 1);
        REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(dst, zeros, 3));
    }
    }

    // doesn't crash with null dst, src, count == 0
    {
    mats[0].mapHomogeneousPoints(NULL, NULL, 0);
    }

    // uniform scale of point
    {
    mat.setScale(kScale0, kScale0);
    SkScalar dst[3];
    SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
    SkPoint pnt;
    pnt.set(src[0], src[1]);
    mat.mapHomogeneousPoints(dst, src, 1);
    mat.mapPoints(&pnt, &pnt, 1);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
    }

    // rotation of point
    {
    mat.setRotate(kRotation0);
    SkScalar dst[3];
    SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
    SkPoint pnt;
    pnt.set(src[0], src[1]);
    mat.mapHomogeneousPoints(dst, src, 1);
    mat.mapPoints(&pnt, &pnt, 1);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
    }

    // rotation, scale, rotation of point
    {
    mat.setRotate(kRotation1);
    mat.postScale(kScale0, kScale0);
    mat.postRotate(kRotation0);
    SkScalar dst[3];
    SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
    SkPoint pnt;
    pnt.set(src[0], src[1]);
    mat.mapHomogeneousPoints(dst, src, 1);
    mat.mapPoints(&pnt, &pnt, 1);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
    }

    // compare with naive approach
    {
    for (int i = 0; i < kMatrixCount; ++i) {
        for (int j = 0; j < kTripleCount; ++j) {
            SkScalar dst[3];
            mats[i].mapHomogeneousPoints(dst, &randTriples[j*3], 1);
            REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], &randTriples[j*3], dst));
        }
    }
    }

}
コード例 #12
0
ファイル: MatrixTest.cpp プロジェクト: Adenilson/skia
static void test_matrix_decomposition(skiatest::Reporter* reporter) {
    SkMatrix mat;
    SkPoint rotation1, scale, rotation2;

    const float kRotation0 = 15.5f;
    const float kRotation1 = -50.f;
    const float kScale0 = 5000.f;
    const float kScale1 = 0.001f;

    // identity
    mat.reset();
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
    // make sure it doesn't crash if we pass in NULLs
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, NULL, NULL, NULL));

    // rotation only
    mat.setRotate(kRotation0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // uniform scale only
    mat.setScale(kScale0, kScale0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // anisotropic scale only
    mat.setScale(kScale1, kScale0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // rotation then uniform scale
    mat.setRotate(kRotation1);
    mat.postScale(kScale0, kScale0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // uniform scale then rotation
    mat.setScale(kScale0, kScale0);
    mat.postRotate(kRotation1);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // rotation then uniform scale+reflection
    mat.setRotate(kRotation0);
    mat.postScale(kScale1, -kScale1);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // uniform scale+reflection, then rotate
    mat.setScale(kScale0, -kScale0);
    mat.postRotate(kRotation1);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // rotation then anisotropic scale
    mat.setRotate(kRotation1);
    mat.postScale(kScale1, kScale0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // rotation then anisotropic scale
    mat.setRotate(90);
    mat.postScale(kScale1, kScale0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // anisotropic scale then rotation
    mat.setScale(kScale1, kScale0);
    mat.postRotate(kRotation0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // anisotropic scale then rotation
    mat.setScale(kScale1, kScale0);
    mat.postRotate(90);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // rotation, uniform scale, then different rotation
    mat.setRotate(kRotation1);
    mat.postScale(kScale0, kScale0);
    mat.postRotate(kRotation0);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // rotation, anisotropic scale, then different rotation
    mat.setRotate(kRotation0);
    mat.postScale(kScale1, kScale0);
    mat.postRotate(kRotation1);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // rotation, anisotropic scale + reflection, then different rotation
    mat.setRotate(kRotation0);
    mat.postScale(-kScale1, kScale0);
    mat.postRotate(kRotation1);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // try some random matrices
    SkRandom rand;
    for (int m = 0; m < 1000; ++m) {
        SkScalar rot0 = rand.nextRangeF(-180, 180);
        SkScalar sx = rand.nextRangeF(-3000.f, 3000.f);
        SkScalar sy = rand.nextRangeF(-3000.f, 3000.f);
        SkScalar rot1 = rand.nextRangeF(-180, 180);
        mat.setRotate(rot0);
        mat.postScale(sx, sy);
        mat.postRotate(rot1);

        if (SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)) {
            REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
        } else {
            // if the matrix is degenerate, the basis vectors should be near-parallel or near-zero
            SkScalar perpdot = mat[SkMatrix::kMScaleX]*mat[SkMatrix::kMScaleY] -
                               mat[SkMatrix::kMSkewX]*mat[SkMatrix::kMSkewY];
            REPORTER_ASSERT(reporter, SkScalarNearlyZero(perpdot));
        }
    }

    // translation shouldn't affect this
    mat.postTranslate(-1000.f, 1000.f);
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // perspective shouldn't affect this
    mat[SkMatrix::kMPersp0] = 12.f;
    mat[SkMatrix::kMPersp1] = 4.f;
    mat[SkMatrix::kMPersp2] = 1872.f;
    REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));

    // degenerate matrices
    // mostly zero entries
    mat.reset();
    mat[SkMatrix::kMScaleX] = 0.f;
    REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    mat.reset();
    mat[SkMatrix::kMScaleY] = 0.f;
    REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
    mat.reset();
    // linearly dependent entries
    mat[SkMatrix::kMScaleX] = 1.f;
    mat[SkMatrix::kMSkewX] = 2.f;
    mat[SkMatrix::kMSkewY] = 4.f;
    mat[SkMatrix::kMScaleY] = 8.f;
    REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
}
コード例 #13
0
// determine that slop required after quad/quad finds a candidate intersection
// use the cross of the tangents plus the distance from 1 or 0 as knobs
DEF_TEST(PathOpsCubicQuadSlop, reporter) {
    // create a random non-selfintersecting cubic
    // break it into quadratics
    // offset the quadratic, measuring the slop required to find the intersection
    if (!gPathOpCubicQuadSlopVerbose) {  // takes a while to run -- so exclude it by default
        return;
    }
    int results[101];
    sk_bzero(results, sizeof(results));
    double minCross[101];
    sk_bzero(minCross, sizeof(minCross));
    double maxCross[101];
    sk_bzero(maxCross, sizeof(maxCross));
    double sumCross[101];
    sk_bzero(sumCross, sizeof(sumCross));
    int foundOne = 0;
    int slopCount = 1;
    SkRandom ran;
    for (int index = 0; index < 10000000; ++index) {
        if (index % 1000 == 999) SkDebugf(".");
        SkDCubic cubic = {{
                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
                {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}
        }};
        SkIntersections i;
        if (i.intersect(cubic)) {
            continue;
        }
        SkSTArray<kCubicToQuadSubdivisionDepth, double, true> ts;
        cubic.toQuadraticTs(cubic.calcPrecision(), &ts);
        double tStart = 0;
        int tsCount = ts.count();
        for (int i1 = 0; i1 <= tsCount; ++i1) {
            const double tEnd = i1 < tsCount ? ts[i1] : 1;
            SkDCubic part = cubic.subDivide(tStart, tEnd);
            SkDQuad quad = part.toQuad();
            SkReduceOrder reducer;
            int order = reducer.reduce(quad);
            if (order != 3) {
                continue;
            }
            for (int i2 = 0; i2 < 100; ++i2) {
                SkDPoint endDisplacement = {ran.nextRangeF(-100, 100), ran.nextRangeF(-100, 100)};
                SkDQuad nearby = {{
                        {quad[0].fX + endDisplacement.fX, quad[0].fY + endDisplacement.fY},
                        {quad[1].fX + ran.nextRangeF(-100, 100), quad[1].fY + ran.nextRangeF(-100, 100)},
                        {quad[2].fX - endDisplacement.fX, quad[2].fY - endDisplacement.fY}
                }};
                order = reducer.reduce(nearby);
                if (order != 3) {
                    continue;
                }
                SkIntersections locals;
                locals.allowNear(false);
                locals.intersect(quad, nearby);
                if (locals.used() != 1) {
                    continue;
                }
                // brute force find actual intersection
                SkDLine cubicLine = {{ {0, 0}, {cubic[0].fX, cubic[0].fY } }};
                SkIntersections liner;
                int i3;
                int found = -1;
                int foundErr = true;
                for (i3 = 1; i3 <= 1000; ++i3) {
                    cubicLine[0] = cubicLine[1];
                    cubicLine[1] = cubic.ptAtT(i3 / 1000.);
                    liner.reset();
                    liner.allowNear(false);
                    liner.intersect(nearby, cubicLine);
                    if (liner.used() == 0) {
                        continue;
                    }
                    if (liner.used() > 1) {
                        foundErr = true;
                        break;
                    }
                    if (found > 0) {
                        foundErr = true;
                        break;
                    }
                    foundErr = false;
                    found = i3;
                }
                if (foundErr) {
                    continue;
                }
                SkDVector dist = liner.pt(0) - locals.pt(0);
                SkDVector qV = nearby.dxdyAtT(locals[0][0]);
                double cubicT = (found - 1 + liner[1][0]) / 1000.;
                SkDVector cV = cubic.dxdyAtT(cubicT);
                double qxc = qV.crossCheck(cV);
                double qvLen = qV.length();
                double cvLen = cV.length();
                double maxLen = SkTMax(qvLen, cvLen);
                qxc /= maxLen;
                double quadT = tStart + (tEnd - tStart) * locals[0][0];
                double diffT = fabs(cubicT - quadT);
                int diffIdx = (int) (diffT * 100);
                results[diffIdx]++;
                double absQxc = fabs(qxc);
                if (sumCross[diffIdx] == 0) {
                    minCross[diffIdx] = maxCross[diffIdx] = sumCross[diffIdx] = absQxc;
                } else {
                    minCross[diffIdx] = SkTMin(minCross[diffIdx], absQxc);
                    maxCross[diffIdx] = SkTMax(maxCross[diffIdx], absQxc);
                    sumCross[diffIdx] +=  absQxc;
                }
                if (diffIdx >= 20) {
#if 01
                    SkDebugf("cubic={{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
                        " quad={{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
                        " {{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
                        " qT=%1.9g cT=%1.9g dist=%1.9g cross=%1.9g\n",
                        cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY,
                        cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY,
                        nearby[0].fX, nearby[0].fY, nearby[1].fX, nearby[1].fY,
                        nearby[2].fX, nearby[2].fY,
                        liner.pt(0).fX, liner.pt(0).fY,
                        locals.pt(0).fX, locals.pt(0).fY, quadT, cubicT, dist.length(), qxc);
#else
                    SkDebugf("qT=%1.9g cT=%1.9g dist=%1.9g cross=%1.9g\n",
                        quadT, cubicT, dist.length(), qxc);
                    SkDebugf("<div id=\"slop%d\">\n", ++slopCount);
                    SkDebugf("{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n"
                        "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n"
                        "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n",
                        cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY,
                        cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY,
                        nearby[0].fX, nearby[0].fY, nearby[1].fX, nearby[1].fY,
                        nearby[2].fX, nearby[2].fY,
                        liner.pt(0).fX, liner.pt(0).fY,
                        locals.pt(0).fX, locals.pt(0).fY);
                    SkDebugf("</div>\n\n");
#endif
                }
                ++foundOne;
            }
            tStart = tEnd;
        }
        if (++foundOne >= 100000) {
            break;
        }
    }
#if 01
    SkDebugf("slopCount=%d\n", slopCount);
    int max = 100;
    while (results[max] == 0) {
        --max;
    }
    for (int i = 0; i <= max; ++i) {
        if (i > 0 && i % 10 == 0) {
            SkDebugf("\n");
        }
        SkDebugf("%d ", results[i]);
    }
    SkDebugf("min\n");
    for (int i = 0; i <= max; ++i) {
        if (i > 0 && i % 10 == 0) {
            SkDebugf("\n");
        }
        SkDebugf("%1.9g ", minCross[i]);
    }
    SkDebugf("max\n");
    for (int i = 0; i <= max; ++i) {
        if (i > 0 && i % 10 == 0) {
            SkDebugf("\n");
        }
        SkDebugf("%1.9g ", maxCross[i]);
    }
    SkDebugf("avg\n");
    for (int i = 0; i <= max; ++i) {
        if (i > 0 && i % 10 == 0) {
            SkDebugf("\n");
        }
        SkDebugf("%1.9g ", sumCross[i] / results[i]);
    }
#else
    for (int i = 1; i < slopCount; ++i) {
        SkDebugf("        slop%d,\n", i);
    }
#endif
    SkDebugf("\n");
}
コード例 #14
0
ファイル: PathOpsTightBoundsTest.cpp プロジェクト: DXGL/skia
static void testTightBoundsQuads(PathOpsThreadState* data) {
    SkRandom ran;
    const int bitWidth = 32;
    const int bitHeight = 32;
    const float pathMin = 1;
    const float pathMax = (float) (bitHeight - 2);
    SkBitmap& bits = *data->fBitmap;
    if (bits.width() == 0) {
        bits.allocN32Pixels(bitWidth, bitHeight);
    }
    SkCanvas canvas(bits);
    SkPaint paint;
    for (int index = 0; index < 100; ++index) {
        SkPath path;
        int contourCount = ran.nextRangeU(1, 10);
        for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
            int lineCount = ran.nextRangeU(1, 10);
            path.moveTo(ran.nextRangeF(1, pathMax), ran.nextRangeF(pathMin, pathMax));
            for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
                if (ran.nextBool()) {
                    path.lineTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
                } else {
                    path.quadTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax),
                            ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
                }
            }
            if (ran.nextBool()) {
                path.close();
            }
        }
        SkRect classicBounds = path.getBounds();
        SkRect tightBounds;
        REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
        REPORTER_ASSERT(data->fReporter, classicBounds.contains(tightBounds));
        canvas.drawColor(SK_ColorWHITE);
        canvas.drawPath(path, paint);
        SkIRect bitsWritten = {31, 31, 0, 0};
        for (int y = 0; y < bitHeight; ++y) {
            uint32_t* addr1 = data->fBitmap->getAddr32(0, y);
            bool lineWritten = false;
            for (int x = 0; x < bitWidth; ++x) {
                if (addr1[x] == (uint32_t) -1) {
                    continue;
                }
                lineWritten = true;
                bitsWritten.fLeft = SkTMin(bitsWritten.fLeft, x);
                bitsWritten.fRight = SkTMax(bitsWritten.fRight, x);
            }
            if (!lineWritten) {
                continue;
            }
            bitsWritten.fTop = SkTMin(bitsWritten.fTop, y);
            bitsWritten.fBottom = SkTMax(bitsWritten.fBottom, y);
        }
        if (!bitsWritten.isEmpty()) {
            SkIRect tightOut;
            tightBounds.roundOut(&tightOut);
            REPORTER_ASSERT(data->fReporter, tightOut.contains(bitsWritten));
        }
    }
}