Exemplo n.º 1
0
bool SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherIndex,
        const SkIntersections& ts, int ptIndex, bool swap) {
    SkPoint pt0 = ts.pt(ptIndex).asSkPoint();
    SkPoint pt1 = ts.pt(ptIndex + 1).asSkPoint();
    if (SkDPoint::ApproximatelyEqual(pt0, pt1)) {
        // FIXME: one could imagine a case where it would be incorrect to ignore this
        // suppose two self-intersecting cubics overlap to form a partial coincidence --
        // although it isn't clear why the regular coincidence could wouldn't pick this up
        // this is exceptional enough to ignore for now
        return false;
    }
    SkCoincidence& coincidence = fPartialCoincidences.push_back();
    coincidence.fOther = other;
    coincidence.fSegments[0] = index;
    coincidence.fSegments[1] = otherIndex;
    coincidence.fTs[swap][0] = ts[0][ptIndex];
    coincidence.fTs[swap][1] = ts[0][ptIndex + 1];
    coincidence.fTs[!swap][0] = ts[1][ptIndex];
    coincidence.fTs[!swap][1] = ts[1][ptIndex + 1];
    coincidence.fPts[0][0] = coincidence.fPts[1][0] = pt0;
    coincidence.fPts[0][1] = coincidence.fPts[1][1] = pt1;
    coincidence.fNearly[0] = 0;
    coincidence.fNearly[1] = 0;
    return true;
}
Exemplo n.º 2
0
static void selfOneOff(skiatest::Reporter* reporter, int index) {
    const SkDCubic& cubic = selfSet[index];
#if ONE_OFF_DEBUG
    int idx2;
    double max[3];
    int ts = cubic.findMaxCurvature(max);
    for (idx2 = 0; idx2 < ts; ++idx2) {
        SkDebugf("%s max[%d]=%1.9g (%1.9g, %1.9g)\n", __FUNCTION__, idx2,
                max[idx2], cubic.ptAtT(max[idx2]).fX, cubic.ptAtT(max[idx2]).fY);
    }
    SkTArray<double, true> ts1;
    SkTArray<SkDQuad, true> quads1;
    cubic.toQuadraticTs(cubic.calcPrecision(), &ts1);
    for (idx2 = 0; idx2 < ts1.count(); ++idx2) {
        SkDebugf("%s t[%d]=%1.9g\n", __FUNCTION__, idx2, ts1[idx2]);
    }
    CubicToQuads(cubic, cubic.calcPrecision(), quads1);
    for (idx2 = 0; idx2 < quads1.count(); ++idx2) {
        const SkDQuad& q = quads1[idx2];
        SkDebugf("  {{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}},\n",
                q[0].fX, q[0].fY,  q[1].fX, q[1].fY,  q[2].fX, q[2].fY);
    }
    SkDebugf("\n");
#endif
    SkIntersections i;
    int result = i.intersect(cubic);
    REPORTER_ASSERT(reporter, result == 1);
    REPORTER_ASSERT(reporter, i.used() == 1);
    REPORTER_ASSERT(reporter, !approximately_equal(i[0][0], i[1][0]));
    SkDPoint pt1 = cubic.ptAtT(i[0][0]);
    SkDPoint pt2 = cubic.ptAtT(i[1][0]);
    REPORTER_ASSERT(reporter, pt1.approximatelyEqual(pt2));
    reporter->bumpTestCount();
}
Exemplo n.º 3
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;
        }
    }
}
static int doIntersect(SkIntersections& intersections, const SkDConic& conic, const SkDLine& line,
                       bool& flipped) {
    int result;
    flipped = false;
    if (line[0].fX == line[1].fX) {
        double top = line[0].fY;
        double bottom = line[1].fY;
        flipped = top > bottom;
        if (flipped) {
            SkTSwap<double>(top, bottom);
        }
        result = intersections.vertical(conic, top, bottom, line[0].fX, flipped);
    } else if (line[0].fY == line[1].fY) {
        double left = line[0].fX;
        double right = line[1].fX;
        flipped = left > right;
        if (flipped) {
            SkTSwap<double>(left, right);
        }
        result = intersections.horizontal(conic, left, right, line[0].fY, flipped);
    } else {
        intersections.intersect(conic, line);
        result = intersections.used();
    }
    return result;
}
Exemplo n.º 5
0
bool SkOpContour::addCoincident(int index, SkOpContour* other, int otherIndex,
        const SkIntersections& ts, bool swap) {
    SkPoint pt0 = ts.pt(0).asSkPoint();
    SkPoint pt1 = ts.pt(1).asSkPoint();
    if (pt0 == pt1) {
        // FIXME: one could imagine a case where it would be incorrect to ignore this
        // suppose two self-intersecting cubics overlap to be coincident --
        // this needs to check that by some measure the t values are far enough apart
        // or needs to check to see if the self-intersection bit was set on the cubic segment
        return false;
    }
    SkCoincidence& coincidence = fCoincidences.push_back();
    coincidence.fOther = other;
    coincidence.fSegments[0] = index;
    coincidence.fSegments[1] = otherIndex;
    coincidence.fTs[swap][0] = ts[0][0];
    coincidence.fTs[swap][1] = ts[0][1];
    coincidence.fTs[!swap][0] = ts[1][0];
    coincidence.fTs[!swap][1] = ts[1][1];
    coincidence.fPts[swap][0] = pt0;
    coincidence.fPts[swap][1] = pt1;
    bool nearStart = ts.nearlySame(0);
    bool nearEnd = ts.nearlySame(1);
    coincidence.fPts[!swap][0] = nearStart ? ts.pt2(0).asSkPoint() : pt0;
    coincidence.fPts[!swap][1] = nearEnd ? ts.pt2(1).asSkPoint() : pt1;
    coincidence.fNearly[0] = nearStart;
    coincidence.fNearly[1] = nearEnd;
    return true;
}
Exemplo n.º 6
0
static void TestLineIntersection(skiatest::Reporter* reporter) {
    size_t index;
    for (index = 0; index < tests_count; ++index) {
        const SkDLine& line1 = tests[index][0];
        const SkDLine& line2 = tests[index][1];
        SkIntersections ts;
        int pts = ts.intersect(line1, line2);
        REPORTER_ASSERT(reporter, pts);
        for (int i = 0; i < pts; ++i) {
            SkDPoint result1 = line1.xyAtT(ts[0][i]);
            SkDPoint result2 = line2.xyAtT(ts[1][i]);
            if (!result1.approximatelyEqual(result2)) {
                REPORTER_ASSERT(reporter, pts != 1);
                result2 = line2.xyAtT(ts[1][i ^ 1]);
                REPORTER_ASSERT(reporter, result1.approximatelyEqual(result2));
            }
        }
    }
    for (index = 0; index < noIntersect_count; ++index) {
        const SkDLine& line1 = noIntersect[index][0];
        const SkDLine& line2 = noIntersect[index][1];
        SkIntersections ts;
        int pts = ts.intersect(line1, line2);
        REPORTER_ASSERT(reporter, !pts);
    }
}
Exemplo n.º 7
0
static int doIntersect(SkIntersections& intersections, const SkDQuad& quad, const SkDLine& line,
                       bool& flipped) {
    int result;
    flipped = false;
    if (line[0].fX == line[1].fX) {
        double top = line[0].fY;
        double bottom = line[1].fY;
        flipped = top > bottom;
        if (flipped) {
            using std::swap;
            swap(top, bottom);
        }
        result = intersections.vertical(quad, top, bottom, line[0].fX, flipped);
    } else if (line[0].fY == line[1].fY) {
        double left = line[0].fX;
        double right = line[1].fX;
        flipped = left > right;
        if (flipped) {
            using std::swap;
            swap(left, right);
        }
        result = intersections.horizontal(quad, left, right, line[0].fY, flipped);
    } else {
        intersections.intersect(quad, line);
        result = intersections.used();
    }
    return result;
}
// returns false if there's more than one intercept or the intercept doesn't match the point
// returns true if the intercept was successfully added or if the
// original quads need to be subdivided
static bool add_intercept(const SkDQuad& q1, const SkDQuad& q2, double tMin, double tMax,
                          SkIntersections* i, bool* subDivide) {
    double tMid = (tMin + tMax) / 2;
    SkDPoint mid = q2.ptAtT(tMid);
    SkDLine line;
    line[0] = line[1] = mid;
    SkDVector dxdy = q2.dxdyAtT(tMid);
    line[0] -= dxdy;
    line[1] += dxdy;
    SkIntersections rootTs;
    rootTs.allowNear(false);
    int roots = rootTs.intersect(q1, line);
    if (roots == 0) {
        if (subDivide) {
            *subDivide = true;
        }
        return true;
    }
    if (roots == 2) {
        return false;
    }
    SkDPoint pt2 = q1.ptAtT(rootTs[0][0]);
    if (!pt2.approximatelyEqualHalf(mid)) {
        return false;
    }
    i->insertSwap(rootTs[0][0], tMid, pt2);
    return true;
}
Exemplo n.º 9
0
SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2) const {
    SkASSERT(t1 != t2);
    SkDPoint b;
    SkDQuad sub = subDivide(t1, t2);
    SkDLine b0 = {{a, sub[1] + (a - sub[0])}};
    SkDLine b1 = {{c, sub[1] + (c - sub[2])}};
    SkIntersections i;
    i.intersectRay(b0, b1);
    if (i.used() == 1 && i[0][0] >= 0 && i[1][0] >= 0) {
        b = i.pt(0);
    } else {
        SkASSERT(i.used() <= 2);
        b = SkDPoint::Mid(b0[1], b1[1]);
    }
    if (t1 == 0 || t2 == 0) {
        align(0, &b);
    }
    if (t1 == 1 || t2 == 1) {
        align(2, &b);
    }
    if (AlmostBequalUlps(b.fX, a.fX)) {
        b.fX = a.fX;
    } else if (AlmostBequalUlps(b.fX, c.fX)) {
        b.fX = c.fX;
    }
    if (AlmostBequalUlps(b.fY, a.fY)) {
        b.fY = a.fY;
    } else if (AlmostBequalUlps(b.fY, c.fY)) {
        b.fY = c.fY;
    }
    return b;
}
static void PathOpsCubicLineIntersectionTest(skiatest::Reporter* reporter) {
    for (size_t index = 0; index < lineCubicTests_count; ++index) {
        int iIndex = static_cast<int>(index);
        const SkDCubic& cubic = lineCubicTests[index].cubic;
        const SkDLine& line = lineCubicTests[index].line;
        SkReduceOrder reduce1;
        SkReduceOrder reduce2;
        int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics,
                SkReduceOrder::kFill_Style);
        int order2 = reduce2.reduce(line);
        if (order1 < 4) {
            SkDebugf("[%d] cubic order=%d\n", iIndex, order1);
            REPORTER_ASSERT(reporter, 0);
        }
        if (order2 < 2) {
            SkDebugf("[%d] line order=%d\n", iIndex, order2);
            REPORTER_ASSERT(reporter, 0);
        }
        if (order1 == 4 && order2 == 2) {
            SkIntersections i;
            int roots = i.intersect(cubic, line);
            for (int pt = 0; pt < roots; ++pt) {
                double tt1 = i[0][pt];
                SkDPoint xy1 = cubic.xyAtT(tt1);
                double tt2 = i[1][pt];
                SkDPoint xy2 = line.xyAtT(tt2);
                if (!xy1.approximatelyEqual(xy2)) {
                    SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                        __FUNCTION__, iIndex, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
                }
                REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
            }
        }
    }
}
Exemplo n.º 11
0
static void selfOneOff(skiatest::Reporter* reporter, int index) {
    const CubicPts& cubic = selfSet[index];
    SkPoint c[4];
    for (int i = 0; i < 4; ++i) {
        c[i] = cubic.fPts[i].asSkPoint();
    }
    SkScalar loopT;
    SkScalar d[3];
    SkCubicType cubicType = SkClassifyCubic(c, d);
    if (SkDCubic::ComplexBreak(c, &loopT) && cubicType == SkCubicType::kLoop_SkCubicType) {
        SkIntersections i;
        SkPoint twoCubics[7];
        SkChopCubicAt(c, twoCubics, loopT);
        SkDCubic chopped[2];
        chopped[0].set(&twoCubics[0]);
        chopped[1].set(&twoCubics[3]);
        int result = i.intersect(chopped[0], chopped[1]);
        REPORTER_ASSERT(reporter, result == 2);
        REPORTER_ASSERT(reporter, i.used() == 2);
        for (int index = 0; index < result; ++index) {
            SkDPoint pt1 = chopped[0].ptAtT(i[0][index]);
            SkDPoint pt2 = chopped[1].ptAtT(i[1][index]);
            REPORTER_ASSERT(reporter, pt1.approximatelyEqual(pt2));
            reporter->bumpTestCount();
        }
    }
}
Exemplo n.º 12
0
// intersect the end of the cubic with the other. Try lines from the end to control and opposite
// end to determine range of t on opposite cubic.
bool SkIntersections::cubicExactEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2) {
    int t1Index = start ? 0 : 3;
    double testT = (double) !start;
    bool swap = swapped();
    // quad/quad at this point checks to see if exact matches have already been found
    // cubic/cubic can't reject so easily since cubics can intersect same point more than once
    SkDLine tmpLine;
    tmpLine[0] = tmpLine[1] = cubic2[t1Index];
    tmpLine[1].fX += cubic2[2 - start].fY - cubic2[t1Index].fY;
    tmpLine[1].fY -= cubic2[2 - start].fX - cubic2[t1Index].fX;
    SkIntersections impTs;
    impTs.allowNear(false);
    impTs.intersectRay(cubic1, tmpLine);
    for (int index = 0; index < impTs.used(); ++index) {
        SkDPoint realPt = impTs.pt(index);
        if (!tmpLine[0].approximatelyEqual(realPt)) {
            continue;
        }
        if (swap) {
            cubicInsert(testT, impTs[0][index], tmpLine[0], cubic2, cubic1);
        } else {
            cubicInsert(impTs[0][index], testT, tmpLine[0], cubic1, cubic2);
        }
        return true;
    }
    return false;
}
static void cubicQuadIntersection(skiatest::Reporter* reporter, int index) {
    int iIndex = static_cast<int>(index);
    const SkDCubic& cubic = quadCubicTests[index].cubic;
    SkASSERT(ValidCubic(cubic));
    const SkDQuad& quad = quadCubicTests[index].quad;
    SkASSERT(ValidQuad(quad));
    SkReduceOrder reduce1;
    SkReduceOrder reduce2;
    int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics);
    int order2 = reduce2.reduce(quad);
    if (order1 != 4) {
        SkDebugf("[%d] cubic order=%d\n", iIndex, order1);
        REPORTER_ASSERT(reporter, 0);
    }
    if (order2 != 3) {
        SkDebugf("[%d] quad order=%d\n", iIndex, order2);
        REPORTER_ASSERT(reporter, 0);
    }
    SkIntersections i;
    int roots = i.intersect(cubic, quad);
    for (int pt = 0; pt < roots; ++pt) {
        double tt1 = i[0][pt];
        SkDPoint xy1 = cubic.ptAtT(tt1);
        double tt2 = i[1][pt];
        SkDPoint xy2 = quad.ptAtT(tt2);
        if (!xy1.approximatelyEqual(xy2)) {
            SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                __FUNCTION__, iIndex, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
        }
        REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
    }
    reporter->bumpTestCount();
}
Exemplo n.º 14
0
static void oneOff(skiatest::Reporter* reporter, const SkDCubic& cubic1, const SkDCubic& cubic2,
        bool coin) {
    SkASSERT(ValidCubic(cubic1));
    SkASSERT(ValidCubic(cubic2));
#if ONE_OFF_DEBUG
    SkDebugf("computed quadratics given\n");
    SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
        cubic1[0].fX, cubic1[0].fY, cubic1[1].fX, cubic1[1].fY,
        cubic1[2].fX, cubic1[2].fY, cubic1[3].fX, cubic1[3].fY);
    SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
        cubic2[0].fX, cubic2[0].fY, cubic2[1].fX, cubic2[1].fY,
        cubic2[2].fX, cubic2[2].fY, cubic2[3].fX, cubic2[3].fY);
#endif
    SkTArray<SkDQuad, true> quads1;
    CubicToQuads(cubic1, cubic1.calcPrecision(), quads1);
#if ONE_OFF_DEBUG
    SkDebugf("computed quadratics set 1\n");
    for (int index = 0; index < quads1.count(); ++index) {
        const SkDQuad& q = quads1[index];
        SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].fX, q[0].fY,
                 q[1].fX, q[1].fY,  q[2].fX, q[2].fY);
    }
#endif
    SkTArray<SkDQuad, true> quads2;
    CubicToQuads(cubic2, cubic2.calcPrecision(), quads2);
#if ONE_OFF_DEBUG
    SkDebugf("computed quadratics set 2\n");
    for (int index = 0; index < quads2.count(); ++index) {
        const SkDQuad& q = quads2[index];
        SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].fX, q[0].fY,
                 q[1].fX, q[1].fY,  q[2].fX, q[2].fY);
    }
#endif
    SkIntersections intersections;
    intersections.intersect(cubic1, cubic2);
    REPORTER_ASSERT(reporter, !coin || intersections.used() == 2);
    double tt1, tt2;
    SkDPoint xy1, xy2;
    for (int pt3 = 0; pt3 < intersections.used(); ++pt3) {
        tt1 = intersections[0][pt3];
        xy1 = cubic1.ptAtT(tt1);
        tt2 = intersections[1][pt3];
        xy2 = cubic2.ptAtT(tt2);
        const SkDPoint& iPt = intersections.pt(pt3);
#if ONE_OFF_DEBUG
        SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n",
                __FUNCTION__, tt1, xy1.fX, xy1.fY, iPt.fX,
                iPt.fY, xy2.fX, xy2.fY, tt2);
#endif
       REPORTER_ASSERT(reporter, xy1.approximatelyEqual(iPt));
       REPORTER_ASSERT(reporter, xy2.approximatelyEqual(iPt));
       REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
    }
    reporter->bumpTestCount();
}
Exemplo n.º 15
0
static void standardTestCases(skiatest::Reporter* reporter) {
    for (size_t index = firstCubicIntersectionTest; index < tests_count; ++index) {
        int iIndex = static_cast<int>(index);
        const CubicPts& cubic1 = tests[index][0];
        const CubicPts& cubic2 = tests[index][1];
        SkDCubic c1, c2;
        c1.debugSet(cubic1.fPts);
        c2.debugSet(cubic2.fPts);
        SkReduceOrder reduce1, reduce2;
        int order1 = reduce1.reduce(c1, SkReduceOrder::kNo_Quadratics);
        int order2 = reduce2.reduce(c2, SkReduceOrder::kNo_Quadratics);
        const bool showSkipped = false;
        if (order1 < 4) {
            if (showSkipped) {
                SkDebugf("%s [%d] cubic1 order=%d\n", __FUNCTION__, iIndex, order1);
            }
            continue;
        }
        if (order2 < 4) {
            if (showSkipped) {
                SkDebugf("%s [%d] cubic2 order=%d\n", __FUNCTION__, iIndex, order2);
            }
            continue;
        }
        SkIntersections tIntersections;
        tIntersections.intersect(c1, c2);
        if (!tIntersections.used()) {
            if (showSkipped) {
                SkDebugf("%s [%d] no intersection\n", __FUNCTION__, iIndex);
            }
            continue;
        }
        if (tIntersections.isCoincident(0)) {
            if (showSkipped) {
                SkDebugf("%s [%d] coincident\n", __FUNCTION__, iIndex);
            }
            continue;
        }
        for (int pt = 0; pt < tIntersections.used(); ++pt) {
            double tt1 = tIntersections[0][pt];
            SkDPoint xy1 = c1.ptAtT(tt1);
            double tt2 = tIntersections[1][pt];
            SkDPoint xy2 = c2.ptAtT(tt2);
            if (!xy1.approximatelyEqual(xy2)) {
                SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                    __FUNCTION__, (int)index, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
            }
            REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
        }
        reporter->bumpTestCount();
    }
}
Exemplo n.º 16
0
void SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherIndex,
        const SkIntersections& ts, int ptIndex, bool swap) {
    SkCoincidence& coincidence = fPartialCoincidences.push_back();
    coincidence.fOther = other;
    coincidence.fSegments[0] = index;
    coincidence.fSegments[1] = otherIndex;
    coincidence.fTs[swap][0] = ts[0][index];
    coincidence.fTs[swap][1] = ts[0][index + 1];
    coincidence.fTs[!swap][0] = ts[1][index];
    coincidence.fTs[!swap][1] = ts[1][index + 1];
    coincidence.fPts[0] = ts.pt(index).asSkPoint();
    coincidence.fPts[1] = ts.pt(index + 1).asSkPoint();
}
static void check_results(skiatest::Reporter* reporter, const SkDLine& line1, const SkDLine& line2,
                          const SkIntersections& ts) {
    for (int i = 0; i < ts.used(); ++i) {
        SkDPoint result1 = line1.ptAtT(ts[0][i]);
        SkDPoint result2 = line2.ptAtT(ts[1][i]);
        if (!result1.approximatelyEqual(result2)) {
            REPORTER_ASSERT(reporter, ts.used() != 1);
            result2 = line2.ptAtT(ts[1][i ^ 1]);
            REPORTER_ASSERT(reporter, result1.approximatelyEqual(result2));
            REPORTER_ASSERT(reporter, result1.approximatelyEqual(ts.pt(i).asSkPoint()));
        }
    }
}
Exemplo n.º 18
0
static void intersectWithOrder(const SkDQuad& simple1, int order1, const SkDQuad& simple2,
        int order2, SkIntersections& i) {
    if (order1 == 3 && order2 == 3) {
        i.intersect(simple1, simple2);
    } else if (order1 <= 2 && order2 <= 2) {
        i.intersect((const SkDLine&) simple1, (const SkDLine&) simple2);
    } else if (order1 == 3 && order2 <= 2) {
        i.intersect(simple1, (const SkDLine&) simple2);
    } else {
        SkASSERT(order1 <= 2 && order2 == 3);
        i.intersect(simple2, (const SkDLine&) simple1);
        i.swapPts();
    }
}
static void hullIntersect(const SkDQuad& q1, const SkDQuad& q2) {
    SkDebugf("%s", __FUNCTION__);
    SkIntersections ts;
    for (int i1 = 0; i1 < 3; ++i1) {
        SkDLine l1 = {{q1[i1], q1[(i1 + 1) % 3]}};
        for (int i2 = 0; i2 < 3; ++i2) {
            SkDLine l2 = {{q2[i2], q2[(i2 + 1) % 3]}};
            if (ts.intersect(l1, l2)) {
                SkDebugf(" [%d,%d]", i1, i2);
            }
        }
    }
    SkDebugf("\n");
}
Exemplo n.º 20
0
static double testArc(skiatest::Reporter* reporter, const SkDQuad& quad, const SkDQuad& arcRef,
        int octant) {
    SkDQuad arc = arcRef;
    SkDVector offset = {quad[0].fX, quad[0].fY};
    arc[0] += offset;
    arc[1] += offset;
    arc[2] += offset;
    SkIntersections i;
    i.intersect(arc, quad);
    if (i.used() == 0) {
        return -1;
    }
    int smallest = -1;
    double t = 2;
    for (int idx = 0; idx < i.used(); ++idx) {
        if (i[0][idx] > 1 || i[0][idx] < 0) {
            i.reset();
            i.intersect(arc, quad);
        }
        if (i[1][idx] > 1 || i[1][idx] < 0) {
            i.reset();
            i.intersect(arc, quad);
        }
        if (t > i[1][idx]) {
            smallest = idx;
            t = i[1][idx];
        }
    }
    REPORTER_ASSERT(reporter, smallest >= 0);
    REPORTER_ASSERT(reporter, t >= 0 && t <= 1);
    return i[1][smallest];
}
DEF_TEST(PathOpsConicLineIntersection, reporter) {
    for (size_t index = 0; index < lineConicTests_count; ++index) {
        int iIndex = static_cast<int>(index);
        const SkDConic& conic = lineConicTests[index].conic;
        SkASSERT(ValidConic(conic));
        const SkDLine& line = lineConicTests[index].line;
        SkASSERT(ValidLine(line));
        SkReduceOrder reducer;
        SkPoint pts[3] = { conic.fPts.fPts[0].asSkPoint(), conic.fPts.fPts[1].asSkPoint(),
            conic.fPts.fPts[2].asSkPoint() };
        SkPoint reduced[3];
        SkPath::Verb order1 = SkReduceOrder::Conic(pts, conic.fWeight, reduced);
        if (order1 != SkPath::kConic_Verb) {
            SkDebugf("%s [%d] conic verb=%d\n", __FUNCTION__, iIndex, order1);
            REPORTER_ASSERT(reporter, 0);
        }
        int order2 = reducer.reduce(line);
        if (order2 < 2) {
            SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, iIndex, order2);
            REPORTER_ASSERT(reporter, 0);
        }
        SkIntersections intersections;
        bool flipped = false;
        int result = doIntersect(intersections, conic, line, flipped);
        REPORTER_ASSERT(reporter, result == lineConicTests[index].result);
        if (intersections.used() <= 0) {
            continue;
        }
        for (int pt = 0; pt < result; ++pt) {
            double tt1 = intersections[0][pt];
            REPORTER_ASSERT(reporter, tt1 >= 0 && tt1 <= 1);
            SkDPoint t1 = conic.ptAtT(tt1);
            double tt2 = intersections[1][pt];
            REPORTER_ASSERT(reporter, tt2 >= 0 && tt2 <= 1);
            SkDPoint t2 = line.ptAtT(tt2);
            if (!t1.approximatelyEqual(t2)) {
                SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
                    __FUNCTION__, iIndex, pt, tt1, t1.fX, t1.fY, tt2, t2.fX, t2.fY);
                REPORTER_ASSERT(reporter, 0);
            }
            if (!t1.approximatelyEqual(lineConicTests[index].expected[0])
                    && (lineConicTests[index].result == 1
                    || !t1.approximatelyEqual(lineConicTests[index].expected[1]))) {
                SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.fX, t1.fY);
                REPORTER_ASSERT(reporter, 0);
            }
        }
    }
}
Exemplo n.º 22
0
DEF_TEST(PathOpsQuadLineIntersection, reporter) {
    for (size_t index = 0; index < lineQuadTests_count; ++index) {
        int iIndex = static_cast<int>(index);
        const QuadPts& q = lineQuadTests[index].quad;
        SkDQuad quad;
        quad.debugSet(q.fPts);
        SkASSERT(ValidQuad(quad));
        const SkDLine& line = lineQuadTests[index].line;
        SkASSERT(ValidLine(line));
        SkReduceOrder reducer1, reducer2;
        int order1 = reducer1.reduce(quad);
        int order2 = reducer2.reduce(line);
        if (order1 < 3) {
            SkDebugf("%s [%d] quad order=%d\n", __FUNCTION__, iIndex, order1);
            REPORTER_ASSERT(reporter, 0);
        }
        if (order2 < 2) {
            SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, iIndex, order2);
            REPORTER_ASSERT(reporter, 0);
        }
        SkIntersections intersections;
        bool flipped = false;
        int result = doIntersect(intersections, quad, line, flipped);
        REPORTER_ASSERT(reporter, result == lineQuadTests[index].result);
        if (intersections.used() <= 0) {
            continue;
        }
        for (int pt = 0; pt < result; ++pt) {
            double tt1 = intersections[0][pt];
            REPORTER_ASSERT(reporter, tt1 >= 0 && tt1 <= 1);
            SkDPoint t1 = quad.ptAtT(tt1);
            double tt2 = intersections[1][pt];
            REPORTER_ASSERT(reporter, tt2 >= 0 && tt2 <= 1);
            SkDPoint t2 = line.ptAtT(tt2);
            if (!t1.approximatelyEqual(t2)) {
                SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
                    __FUNCTION__, iIndex, pt, tt1, t1.fX, t1.fY, tt2, t2.fX, t2.fY);
                REPORTER_ASSERT(reporter, 0);
            }
            if (!t1.approximatelyEqual(lineQuadTests[index].expected[0])
                    && (lineQuadTests[index].result == 1
                    || !t1.approximatelyEqual(lineQuadTests[index].expected[1]))) {
                SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.fX, t1.fY);
                REPORTER_ASSERT(reporter, 0);
            }
        }
    }
}
Exemplo n.º 23
0
static bool closeEnd(const SkDCubic& cubic, int cubicIndex, SkIntersections& i, SkDPoint& pt) {
    int last = i.used() - 1;
    if (i[cubicIndex][last] != 1 || i[cubicIndex][last - 1] < 1 - CLOSE_ENOUGH) {
        return false;
    }
    pt = cubic.xyAtT((i[cubicIndex][last] + i[cubicIndex][last - 1]) / 2);
    return true;
}
static void testOneCoincident(skiatest::Reporter* reporter, const SkDLine& line1,
                              const SkDLine& line2) {
    SkASSERT(ValidLine(line1));
    SkASSERT(ValidLine(line2));
    SkIntersections ts2;
    int pts2 = ts2.intersect(line1, line2);
    REPORTER_ASSERT(reporter, pts2 == 2);
    REPORTER_ASSERT(reporter, pts2 == ts2.used());
    check_results(reporter, line1, line2, ts2);
#if 0
    SkIntersections ts;
    int pts = ts.intersect(line1, line2);
    REPORTER_ASSERT(reporter, pts == pts2);
    REPORTER_ASSERT(reporter, pts == 2);
    REPORTER_ASSERT(reporter, pts == ts.used());
    check_results(reporter, line1, line2, ts);
#endif
}
static void PathOpsCubicQuadIntersectionTest(skiatest::Reporter* reporter) {
    for (size_t index = 0; index < quadCubicTests_count; ++index) {
        int iIndex = static_cast<int>(index);
        const SkDCubic& cubic = quadCubicTests[index].cubic;
        const SkDQuad& quad = quadCubicTests[index].quad;
        SkReduceOrder reduce1;
        SkReduceOrder reduce2;
        int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics,
                SkReduceOrder::kFill_Style);
        int order2 = reduce2.reduce(quad, SkReduceOrder::kFill_Style);
        if (order1 != 4) {
            SkDebugf("[%d] cubic order=%d\n", iIndex, order1);
            REPORTER_ASSERT(reporter, 0);
        }
        if (order2 != 3) {
            SkDebugf("[%d] quad order=%d\n", iIndex, order2);
            REPORTER_ASSERT(reporter, 0);
        }
        SkIntersections i;
        int roots = i.intersect(cubic, quad);
        SkASSERT(roots == quadCubicTests[index].answerCount);
        for (int pt = 0; pt < roots; ++pt) {
            double tt1 = i[0][pt];
            SkDPoint xy1 = cubic.xyAtT(tt1);
            double tt2 = i[1][pt];
            SkDPoint xy2 = quad.xyAtT(tt2);
            if (!xy1.approximatelyEqual(xy2)) {
                SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                    __FUNCTION__, iIndex, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
            }
            REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
            bool found = false;
            for (int idx2 = 0; idx2 < quadCubicTests[index].answerCount; ++idx2) {
                found |= quadCubicTests[index].answers[idx2].approximatelyEqual(xy1);
            }
            REPORTER_ASSERT(reporter, found);
        }
        reporter->bumpTestCount();
    }
}
static void lookNearEnd(const SkDQuad& q1, const SkDQuad& q2, int testT,
        const SkIntersections& orig, bool swap, SkIntersections* i) {
    if (orig.used() == 1 && orig[!swap][0] == testT) {
        return;
    }
    if (orig.used() == 2 && orig[!swap][1] == testT) {
        return;
    }
    SkDLine tmpLine;
    int testTIndex = testT << 1;
    tmpLine[0] = tmpLine[1] = q2[testTIndex];
    tmpLine[1].fX += q2[1].fY - q2[testTIndex].fY;
    tmpLine[1].fY -= q2[1].fX - q2[testTIndex].fX;
    SkIntersections impTs;
    impTs.intersectRay(q1, tmpLine);
    for (int index = 0; index < impTs.used(); ++index) {
        SkDPoint realPt = impTs.pt(index);
        if (!tmpLine[0].approximatelyEqualHalf(realPt)) {
            continue;
        }
        if (swap) {
            i->insert(testT, impTs[0][index], tmpLine[0]);
        } else {
            i->insert(impTs[0][index], testT, tmpLine[0]);
        }
    }
}
Exemplo n.º 27
0
static void oneOff(skiatest::Reporter* reporter, const SkDConic& c1, const SkDConic& c2,
        bool coin) {
#if DEBUG_VISUALIZE_CONICS
    writeFrames();
#endif
    chopBothWays(c1, 0.5, "c1");
    chopBothWays(c2, 0.5, "c2");
#if DEBUG_VISUALIZE_CONICS
    writeDPng(c1, "d1");
    writeDPng(c2, "d2");
#endif
    SkASSERT(ValidConic(c1));
    SkASSERT(ValidConic(c2));
    SkIntersections intersections;
    intersections.intersect(c1, c2);
    if (coin && intersections.used() != 2) {
        SkDebugf("");
    }
    REPORTER_ASSERT(reporter, !coin || intersections.used() == 2);
    double tt1, tt2;
    SkDPoint xy1, xy2;
    for (int pt3 = 0; pt3 < intersections.used(); ++pt3) {
        tt1 = intersections[0][pt3];
        xy1 = c1.ptAtT(tt1);
        tt2 = intersections[1][pt3];
        xy2 = c2.ptAtT(tt2);
        const SkDPoint& iPt = intersections.pt(pt3);
        REPORTER_ASSERT(reporter, xy1.approximatelyEqual(iPt));
        REPORTER_ASSERT(reporter, xy2.approximatelyEqual(iPt));
        REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
    }
    reporter->bumpTestCount();
}
Exemplo n.º 28
0
SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2) const {
    SkASSERT(t1 != t2);
    SkDPoint b;
#if 0
    // this approach assumes that the control point computed directly is accurate enough
    double dx = interp_quad_coords(&fPts[0].fX, (t1 + t2) / 2);
    double dy = interp_quad_coords(&fPts[0].fY, (t1 + t2) / 2);
    b.fX = 2 * dx - (a.fX + c.fX) / 2;
    b.fY = 2 * dy - (a.fY + c.fY) / 2;
#else
    SkDQuad sub = subDivide(t1, t2);
    SkDLine b0 = {{a, sub[1] + (a - sub[0])}};
    SkDLine b1 = {{c, sub[1] + (c - sub[2])}};
    SkIntersections i;
    i.intersectRay(b0, b1);
    if (i.used() == 1 && i[0][0] >= 0 && i[1][0] >= 0) {
        b = i.pt(0);
    } else {
        SkASSERT(i.used() <= 2);
        b = SkDPoint::Mid(b0[1], b1[1]);
    }
#endif
    if (t1 == 0 || t2 == 0) {
        align(0, &b);
    }
    if (t1 == 1 || t2 == 1) {
        align(2, &b);
    }
    if (AlmostBequalUlps(b.fX, a.fX)) {
        b.fX = a.fX;
    } else if (AlmostBequalUlps(b.fX, c.fX)) {
        b.fX = c.fX;
    }
    if (AlmostBequalUlps(b.fY, a.fY)) {
        b.fY = a.fY;
    } else if (AlmostBequalUlps(b.fY, c.fY)) {
        b.fY = c.fY;
    }
    return b;
}
static void standardTestCases(skiatest::Reporter* reporter) {
    bool showSkipped = false;
    for (size_t index = 0; index < quadraticTests_count; ++index) {
        const SkDQuad& quad1 = quadraticTests[index][0];
        SkASSERT(ValidQuad(quad1));
        const SkDQuad& quad2 = quadraticTests[index][1];
        SkASSERT(ValidQuad(quad2));
        SkReduceOrder reduce1, reduce2;
        int order1 = reduce1.reduce(quad1);
        int order2 = reduce2.reduce(quad2);
        if (order1 < 3) {
            if (showSkipped) {
                SkDebugf("[%d] quad1 order=%d\n", static_cast<int>(index), order1);
            }
        }
        if (order2 < 3) {
            if (showSkipped) {
                SkDebugf("[%d] quad2 order=%d\n", static_cast<int>(index), order2);
            }
        }
        if (order1 == 3 && order2 == 3) {
            SkIntersections intersections;
            intersections.intersect(quad1, quad2);
            if (intersections.used() > 0) {
                for (int pt = 0; pt < intersections.used(); ++pt) {
                    double tt1 = intersections[0][pt];
                    SkDPoint xy1 = quad1.ptAtT(tt1);
                    double tt2 = intersections[1][pt];
                    SkDPoint xy2 = quad2.ptAtT(tt2);
                    if (!xy1.approximatelyEqual(xy2)) {
                        SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                                __FUNCTION__, static_cast<int>(index), pt, tt1, xy1.fX, xy1.fY,
                                tt2, xy2.fX, xy2.fY);
                        REPORTER_ASSERT(reporter, 0);
                    }
                }
            }
        }
    }
}
Exemplo n.º 30
0
static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt,
        const SkIntersections& i) {
    SkASSERT(i.used() == pts);
    if (!pts) {
        SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
                CUBIC_DEBUG_DATA(wt.pts()));
        return;
    }
    SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
            i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
    SkDebugf(" " T_DEBUG_STR(wtTs, 1), i[1][0]);
    SkDebugf("\n");
}