Exemplo n.º 1
0
static void oneOffTest1(size_t outer, size_t inner) {
    const Quadratic& quad1 = testSet[outer];
    const Quadratic& quad2 = testSet[inner];
    Intersections intersections2;
    intersect2(quad1, quad2, intersections2);
    if (intersections2.fUnsortable) {
        SkASSERT(0);
        return;
    }
    for (int pt = 0; pt < intersections2.used(); ++pt) {
        double tt1 = intersections2.fT[0][pt];
        double tx1, ty1;
        xy_at_t(quad1, tt1, tx1, ty1);
        int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
        double tt2 = intersections2.fT[1][pt2];
        double tx2, ty2;
        xy_at_t(quad2, tt2, tx2, ty2);
        if (!AlmostEqualUlps(tx1, tx2)) {
            SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                __FUNCTION__, (int)outer, (int)inner, tt1, tx1, ty1, tt2, tx2, ty2);
            SkASSERT(0);
        }
        if (!AlmostEqualUlps(ty1, ty2)) {
            SkDebugf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                __FUNCTION__, (int)outer, (int)inner, tt1, tx1, ty1, tt2, tx2, ty2);
            SkASSERT(0);
        }
#if ONE_OFF_DEBUG
        SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
            outer, inner, tt1, tx1, tx2, tt2);
#endif
    }
}
Exemplo n.º 2
0
static void oneOffTest() {
    for (size_t outer = 0; outer < testSetCount - 1; ++outer) {
        for (size_t inner = outer + 1; inner < testSetCount; ++inner) {
            const Quadratic& quad1 = testSet[outer];
            const Quadratic& quad2 = testSet[inner];
            double tt1, tt2;
            Intersections intersections2;
            intersect2(quad1, quad2, intersections2);
            for (int pt = 0; pt < intersections2.used(); ++pt) {
                tt1 = intersections2.fT[0][pt];
                double tx1, ty1;
                xy_at_t(quad1, tt1, tx1, ty1);
                int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
                tt2 = intersections2.fT[1][pt2];
                double tx2, ty2;
                xy_at_t(quad2, tt2, tx2, ty2);
                if (!approximately_equal(tx1, tx2)) {
                    SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                        __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
                    SkASSERT(0);
                }
                if (!approximately_equal(ty1, ty2)) {
                    SkDebugf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                        __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
                    SkASSERT(0);
                }
                SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
                    outer, inner, tt1, tx1, tx2, tt2);
            }
        }
    }
}
Exemplo n.º 3
0
bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
    Cubic sub1, sub2;
    // FIXME: carry last subdivide and reduceOrder result with cubic
    sub_divide(cubic1, minT1, maxT1, sub1);
    sub_divide(cubic2, minT2, maxT2, sub2);
    Intersections i;
    intersect2(sub1, sub2, i);
    if (i.used() == 0) {
        return false;
    }
    double x1, y1, x2, y2;
    t1 = minT1 + i.fT[0][0] * (maxT1 - minT1);
    t2 = minT2 + i.fT[1][0] * (maxT2 - minT2);
    xy_at_t(cubic1, t1, x1, y1);
    xy_at_t(cubic2, t2, x2, y2);
    if (AlmostEqualUlps(x1, x2) && AlmostEqualUlps(y1, y2)) {
        return true;
    }
    double half1 = (minT1 + maxT1) / 2;
    double half2 = (minT2 + maxT2) / 2;
    ++depth;
    bool result;
    if (depth & 1) {
        result = intersect(minT1, half1, minT2, maxT2) || intersect(half1, maxT1, minT2, maxT2)
            || intersect(minT1, maxT1, minT2, half2) || intersect(minT1, maxT1, half2, maxT2);
    } else {
        result = intersect(minT1, maxT1, minT2, half2) || intersect(minT1, maxT1, half2, maxT2)
            || intersect(minT1, half1, minT2, maxT2) || intersect(half1, maxT1, minT2, maxT2);
    }
    --depth;
    return result;
}
Exemplo n.º 4
0
double leftMostT(const Quadratic& quad, double startT, double endT) {
    double leftT;
    if (findExtrema(quad[0].x, quad[1].x, quad[2].x, &leftT)
            && startT <= leftT && leftT <= endT) {
        return leftT;
    }
    _Point startPt;
    xy_at_t(quad, startT, startPt.x, startPt.y);
    _Point endPt;
    xy_at_t(quad, endT, endPt.x, endPt.y);
    return startPt.x <= endPt.x ? startT : endT;
}
Exemplo n.º 5
0
void CubicIntersection_RandTest() {
    srand(0);
    const int tests = 10000000;
    for (int test = 0; test < tests; ++test) {
        Cubic cubic1, cubic2;
        for (int i = 0; i < 4; ++i) {
            cubic1[i].x = (double) rand() / RAND_MAX * 100;
            cubic1[i].y = (double) rand() / RAND_MAX * 100;
            cubic2[i].x = (double) rand() / RAND_MAX * 100;
            cubic2[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"
            "{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}},\n",
                cubic1[0].x, cubic1[0].y,  cubic1[1].x, cubic1[1].y, cubic1[2].x, cubic1[2].y,
                cubic1[3].x, cubic1[3].y,
                cubic2[0].x, cubic2[0].y,  cubic2[1].x, cubic2[1].y, cubic2[2].x, cubic2[2].y,
                cubic2[3].x, cubic2[3].y);
    #endif
        _Rect rect1, rect2;
        rect1.setBounds(cubic1);
        rect2.setBounds(cubic2);
        bool boundsIntersect = rect1.left <= rect2.right && rect2.left <= rect2.right
                && rect1.top <= rect2.bottom && rect2.top <= rect1.bottom;
        if (test == -1) {
            SkDebugf("ready...\n");
        }
        Intersections intersections2;
        bool newIntersects = intersect2(cubic1, cubic2, intersections2);
        if (!boundsIntersect && newIntersects) {
            SkDebugf("%s %d unexpected intersection boundsIntersect=%d "
                    " newIntersects=%d\n%s %s\n", __FUNCTION__, test, boundsIntersect,
                    newIntersects, __FUNCTION__, str);
            assert(0);
        }
        for (int pt = 0; pt < intersections2.used(); ++pt) {
            double tt1 = intersections2.fT[0][pt];
            _Point xy1, xy2;
            xy_at_t(cubic1, tt1, xy1.x, xy1.y);
            int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
            double tt2 = intersections2.fT[1][pt2];
            xy_at_t(cubic2, tt2, xy2.x, xy2.y);
        #if 0
            SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
                tt1, xy1.x, xy1.y, xy2.x, xy2.y, tt2);
        #endif
            assert(xy1.approximatelyEqual(xy2));
        }
    }
}
Exemplo n.º 6
0
static bool closeStart(const Cubic& cubic, int cubicIndex, Intersections& i, _Point& pt) {
    if (i.fT[cubicIndex][0] != 0 || i.fT[cubicIndex][1] > CLOSE_ENOUGH) {
        return false;
    }
    pt = xy_at_t(cubic, (i.fT[cubicIndex][0] + i.fT[cubicIndex][1]) / 2);
    return true;
}
Exemplo n.º 7
0
// from http://blog.gludion.com/2009/08/distance-to-quadratic-bezier-curve.html
double nearestT(const Quadratic& quad, const _Point& pt) {
    _Vector pos = quad[0] - pt;
    // search points P of bezier curve with PM.(dP / dt) = 0
    // a calculus leads to a 3d degree equation :
    _Vector A = quad[1] - quad[0];
    _Vector B = quad[2] - quad[1];
    B -= A;
    double a = B.dot(B);
    double b = 3 * A.dot(B);
    double c = 2 * A.dot(A) + pos.dot(B);
    double d = pos.dot(A);
    double ts[3];
    int roots = cubicRootsValidT(a, b, c, d, ts);
    double d0 = pt.distanceSquared(quad[0]);
    double d2 = pt.distanceSquared(quad[2]);
    double distMin = SkTMin(d0, d2);
    int bestIndex = -1;
    for (int index = 0; index < roots; ++index) {
        _Point onQuad;
        xy_at_t(quad, ts[index], onQuad.x, onQuad.y);
        double dist = pt.distanceSquared(onQuad);
        if (distMin > dist) {
            distMin = dist;
            bestIndex = index;
        }
    }
    if (bestIndex >= 0) {
        return ts[bestIndex];
    }
    return d0 < d2 ? 0 : 1;
}
Exemplo n.º 8
0
static void cubicTangent(const Cubic& cubic, double t, _Line& tangent, _Point& pt, _Point& dxy) {
    xy_at_t(cubic, t, tangent[0].x, tangent[0].y);
    pt = tangent[1] = tangent[0];
    dxdy_at_t(cubic, t, dxy);
    tangent[0] -= dxy;
    tangent[1] += dxy;
}
Exemplo n.º 9
0
static bool closeEnd(const Cubic& cubic, int cubicIndex, Intersections& i, _Point& pt) {
    int last = i.used() - 1;
    if (i.fT[cubicIndex][last] != 1 || i.fT[cubicIndex][last - 1] < 1 - CLOSE_ENOUGH) {
        return false;
    }
    pt = xy_at_t(cubic, (i.fT[cubicIndex][last] + i.fT[cubicIndex][last - 1]) / 2);
    return true;
}
Exemplo n.º 10
0
// OPTIMIZE: avoid computing the unused half
void xy_at_t(const Cubic& cubic, double t, double& x, double& y) {
    _Point xy = xy_at_t(cubic, t);
    if (&x) {
        x = xy.x;
    }
    if (&y) {
        y = xy.y;
    }
}
Exemplo n.º 11
0
void CubicIntersection_Test() {
    for (size_t index = firstCubicIntersectionTest; index < tests_count; ++index) {
        const Cubic& cubic1 = tests[index][0];
        const Cubic& cubic2 = tests[index][1];
        Cubic reduce1, reduce2;
        int order1 = reduceOrder(cubic1, reduce1, kReduceOrder_NoQuadraticsAllowed);
        int order2 = reduceOrder(cubic2, reduce2, kReduceOrder_NoQuadraticsAllowed);
        if (order1 < 4) {
            printf("%s [%d] cubic1 order=%d\n", __FUNCTION__, (int) index, order1);
            continue;
        }
        if (order2 < 4) {
            printf("%s [%d] cubic2 order=%d\n", __FUNCTION__, (int) index, order2);
            continue;
        }
        if (implicit_matches(reduce1, reduce2)) {
            printf("%s [%d] coincident\n", __FUNCTION__, (int) index);
            continue;
        }
        Intersections tIntersections;
        intersect(reduce1, reduce2, tIntersections);
        if (!tIntersections.intersected()) {
            printf("%s [%d] no intersection\n", __FUNCTION__, (int) index);
            continue;
        }
        for (int pt = 0; pt < tIntersections.used(); ++pt) {
            double tt1 = tIntersections.fT[0][pt];
            double tx1, ty1;
            xy_at_t(cubic1, tt1, tx1, ty1);
            double tt2 = tIntersections.fT[1][pt];
            double tx2, ty2;
            xy_at_t(cubic2, tt2, tx2, ty2);
            if (!AlmostEqualUlps(tx1, tx2)) {
                printf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                    __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
            }
            if (!AlmostEqualUlps(ty1, ty2)) {
                printf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                    __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
            }
        }
    }
}
Exemplo n.º 12
0
static void standardTestCases() {
    for (size_t index = firstQuadIntersectionTest; index < quadraticTests_count; ++index) {
        const Quadratic& quad1 = quadraticTests[index][0];
        const Quadratic& quad2 = quadraticTests[index][1];
        Quadratic reduce1, reduce2;
        int order1 = reduceOrder(quad1, reduce1);
        int order2 = reduceOrder(quad2, reduce2);
        if (order1 < 3) {
            printf("[%d] quad1 order=%d\n", (int) index, order1);
        }
        if (order2 < 3) {
            printf("[%d] quad2 order=%d\n", (int) index, order2);
        }
        if (order1 == 3 && order2 == 3) {
            Intersections intersections, intersections2;
            intersect(reduce1, reduce2, intersections);
            intersect2(reduce1, reduce2, intersections2);
            SkASSERT(intersections.used() == intersections2.used());
            if (intersections.intersected()) {
                for (int pt = 0; pt < intersections.used(); ++pt) {
                    double tt1 = intersections.fT[0][pt];
                    double tx1, ty1;
                    xy_at_t(quad1, tt1, tx1, ty1);
                    double tt2 = intersections.fT[1][pt];
                    double tx2, ty2;
                    xy_at_t(quad2, tt2, tx2, ty2);
                    if (!approximately_equal(tx1, tx2)) {
                        printf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                            __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
                    }
                    if (!approximately_equal(ty1, ty2)) {
                        printf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                            __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
                    }
                    tt1 = intersections2.fT[0][pt];
                    SkASSERT(approximately_equal(intersections.fT[0][pt], tt1));
                    tt2 = intersections2.fT[1][pt];
                    SkASSERT(approximately_equal(intersections.fT[1][pt], tt2));
                }
            }
        }
    }
}
Exemplo n.º 13
0
int horizontalIntersect(double axisIntercept, double left, double right) {
    int roots = horizontalIntersect(axisIntercept);
    for (int index = 0; index < roots; ) {
        double x;
        xy_at_t(quad, intersections.fT[0][index], x, *(double*) NULL);
        double lineT = (x - left) / (right - left);
        if (lineIntersects(lineT, index, roots)) {
            ++index;
        }
    }
    return roots;
}
Exemplo n.º 14
0
int verticalIntersect(double axisIntercept, double top, double bottom) {
    int roots = verticalIntersect(axisIntercept);
    for (int index = 0; index < roots; ) {
        double y;
        xy_at_t(quad, intersections.fT[0][index], *(double*) NULL, y);
        double lineT = (y - top) / (bottom - top);
        if (lineIntersects(lineT, index, roots)) {
            ++index;
        }
    }
    return roots;
}
Exemplo n.º 15
0
static void oneOff(const Cubic& cubic1, const Cubic& cubic2) {
    SkTDArray<Quadratic> quads1;
    cubic_to_quadratics(cubic1, calcPrecision(cubic1), quads1);
#if ONE_OFF_DEBUG
    for (int index = 0; index < quads1.count(); ++index) {
        const Quadratic& q = quads1[index];
        SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
                 q[1].x, q[1].y,  q[2].x, q[2].y);
    }
    SkDebugf("\n");
#endif
    SkTDArray<Quadratic> quads2;
    cubic_to_quadratics(cubic2, calcPrecision(cubic2), quads2);
#if ONE_OFF_DEBUG
    for (int index = 0; index < quads2.count(); ++index) {
        const Quadratic& q = quads2[index];
        SkDebugf("  {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
                 q[1].x, q[1].y,  q[2].x, q[2].y);
    }
    SkDebugf("\n");
#endif
    Intersections intersections2;
    intersect2(cubic1, cubic2, intersections2);
    for (int pt = 0; pt < intersections2.used(); ++pt) {
        double tt1 = intersections2.fT[0][pt];
        _Point xy1, xy2;
        xy_at_t(cubic1, tt1, xy1.x, xy1.y);
        int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
        double tt2 = intersections2.fT[1][pt2];
        xy_at_t(cubic2, tt2, xy2.x, xy2.y);
#if ONE_OFF_DEBUG
        SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
            tt1, xy1.x, xy1.y, xy2.x, xy2.y, tt2);
#endif
        assert(xy1.approximatelyEqual(xy2));
    }
}
Exemplo n.º 16
0
static double verticalIntersect(const Quadratic& quad, const _Point& pt) {
    Intersections intersections;
    LineQuadraticIntersections q(quad, *((_Line*) 0), intersections);
    int result = q.horizontalIntersect(pt.x);
    if (result == 0) {
        return -1;
    }
    assert(result == 1);
    double x, y;
    xy_at_t(quad, intersections.fT[0][0], x, y);
    if (approximately_equal(y, pt.y)) {
        return intersections.fT[0][0];
    }
    return -1;
}
Exemplo n.º 17
0
void LineCubicIntersection_Test() {
    for (size_t index = firstLineCubicIntersectionTest; index < lineCubicTests_count; ++index) {
        const Cubic& cubic = lineCubicTests[index].cubic;
        const _Line& line = lineCubicTests[index].line;
        Cubic reduce1;
        _Line reduce2;
        int order1 = reduceOrder(cubic, reduce1, kReduceOrder_NoQuadraticsAllowed);
        int order2 = reduceOrder(line, reduce2);
        if (order1 < 4) {
            printf("[%d] cubic order=%d\n", (int) index, order1);
        }
        if (order2 < 2) {
            printf("[%d] line order=%d\n", (int) index, order2);
        }
        if (order1 == 4 && order2 == 2) {
            double range1[2], range2[2];
            int roots = intersect(reduce1, reduce2, range1, range2);
            for (int pt = 0; pt < roots; ++pt) {
                double tt1 = range1[pt];
                double tx1, ty1;
                xy_at_t(cubic, tt1, tx1, ty1);
                double tt2 = range2[pt];
                double tx2, ty2;
                xy_at_t(line, tt2, tx2, ty2);
                if (!approximately_equal(tx1, tx2)) {
                    printf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                        __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
                }
                if (!approximately_equal(ty1, ty2)) {
                    printf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
                        __FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
                }
            }
        }
    }
}
Exemplo n.º 18
0
void LineIntersection_Test() {
    size_t index;
    for (index = firstLineIntersectionTest; index < tests_count; ++index) {
        const _Line& line1 = tests[index][0];
        const _Line& line2 = tests[index][1];
        double t1[2], t2[2];
        int pts = intersect(line1, line2, t1, t2);
        if (!pts) {
            printf("%s [%zu] no intersection found\n", __FUNCTION__, index);
        }
        for (int i = 0; i < pts; ++i) {
            _Point result1, result2;
            xy_at_t(line1, t1[i], result1.x, result1.y);
            xy_at_t(line2, t2[i], result2.x, result2.y);
            if (!result1.approximatelyEqual(result2)) {
                if (pts == 1) {
                    printf("%s [%zu] not equal\n", __FUNCTION__, index);
                } else {
                    xy_at_t(line2, t2[i ^ 1], result2.x, result2.y);
                    if (!result1.approximatelyEqual(result2)) {
                        printf("%s [%zu] not equal\n", __FUNCTION__, index);
                    }
                }
            }
        }
    }
    for (index = firstNoIntersectionTest; index < noIntersect_count; ++index) {
        const _Line& line1 = noIntersect[index][0];
        const _Line& line2 = noIntersect[index][1];
        double t1[2], t2[2];
        int pts = intersect(line1, line2, t1, t2);
        if (pts) {
            printf("%s [%zu] no intersection expected\n", __FUNCTION__, index);
        }
    }
}
Exemplo n.º 19
0
// FIXME: after testing, make this static
void computeDelta(const Cubic& c1, double t1, double scale1, const Cubic& c2, double t2,
        double scale2, double& delta1, double& delta2) {
    _Line tangent1, tangent2, line1, line2;
    _Point dxy1, dxy2;
    cubicTangent(c1, t1, line1, tangent1[0], dxy1);
    cubicTangent(c2, t2, line2, tangent2[0], dxy2);
    double range1[2], range2[2];
    int found = intersect(line1, line2, range1, range2);
    if (found == 0) {
        range1[0] = 0.5;
    } else {
        SkASSERT(found == 1);
    }
    xy_at_t(line1, range1[0], tangent1[1].x, tangent1[1].y);
#if SK_DEBUG
    if (found == 1) {
        xy_at_t(line2, range2[0], tangent2[1].x, tangent2[1].y);
        SkASSERT(tangent2[1].approximatelyEqual(tangent1[1]));
    }
#endif
    tangent2[1] = tangent1[1];
    delta1 = cubicDelta(dxy1, tangent1, scale1 / precisionUnit);
    delta2 = cubicDelta(dxy2, tangent2, scale2 / precisionUnit);
}
Exemplo n.º 20
0
int horizontalIntersect(const Quadratic& quad, double left, double right,
        double y, double tRange[2]) {
    Intersections i;
    LineQuadraticIntersections q(quad, *((_Line*) 0), i);
    int result = q.horizontalIntersect(y);
    int tCount = 0;
    for (int index = 0; index < result; ++index) {
        double x, y;
        xy_at_t(quad, i.fT[0][index], x, y);
        if (x < left || x > right) {
            continue;
        }
        tRange[tCount++] = i.fT[0][index];
    }
    return tCount;
}
Exemplo n.º 21
0
void _Rect::setBounds(const Quadratic& quad) {
    set(quad[0]);
    add(quad[2]);
    double tValues[2];
    int roots = 0;
    if (!between(quad[0].x, quad[1].x, quad[2].x)) {
        roots = findExtrema(quad[0].x, quad[1].x, quad[2].x, tValues);
    }
    if (!between(quad[0].y, quad[1].y, quad[2].y)) {
        roots += findExtrema(quad[0].y, quad[1].y, quad[2].y, &tValues[roots]);
    }
    for (int x = 0; x < roots; ++x) {
        _Point result;
        xy_at_t(quad, tValues[x], result.x, result.y);
        add(result);
    }
}
static void pointFinder(const Quadratic& q1, const Quadratic& q2) {
    for (int index = 0; index < 3; ++index) {
        double t = nearestT(q1, q2[index]);
        _Point onQuad;
        xy_at_t(q1, t, onQuad.x, onQuad.y);
        SkDebugf("%s t=%1.9g (%1.9g,%1.9g) dist=%1.9g\n", __FUNCTION__, t, onQuad.x, onQuad.y,
                onQuad.distance(q2[index]));
        double left[3];
        left[0] = is_left((const _Line&) q1[0], q2[index]);
        left[1] = is_left((const _Line&) q1[1], q2[index]);
        _Line diag = {q1[0], q1[2]};
        left[2] = is_left(diag, q2[index]);
        SkDebugf("%s left=(%d, %d, %d) inHull=%s\n", __FUNCTION__, floatSign(left[0]),
                floatSign(left[1]), floatSign(left[2]),
                point_in_hull(q1, q2[index]) ? "true" : "false");
    }
    SkDebugf("\n");
}
Exemplo n.º 23
0
int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) {
    addHorizontalEndPoints(left, right, axisIntercept);
    double rootVals[2];
    int roots = horizontalIntersect(axisIntercept, rootVals);
    for (int index = 0; index < roots; ++index) {
        double x;
        double quadT = rootVals[index];
        xy_at_t(quad, quadT, x, *(double*) NULL);
        double lineT = (x - left) / (right - left);
        if (pinTs(quadT, lineT)) {
            intersections.insert(quadT, lineT);
        }
    }
    if (flipped) {
        flip();
    }
    return intersections.fUsed;
}
Exemplo n.º 24
0
int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
    addVerticalEndPoints(top, bottom, axisIntercept);
    double rootVals[2];
    int roots = verticalIntersect(axisIntercept, rootVals);
    for (int index = 0; index < roots; ++index) {
        double y;
        double quadT = rootVals[index];
        xy_at_t(quad, quadT, *(double*) NULL, y);
        double lineT = (y - top) / (bottom - top);
        if (pinTs(quadT, lineT)) {
            intersections.insert(quadT, lineT);
        }
    }
    if (flipped) {
        flip();
    }
    return intersections.fUsed;
}
Exemplo n.º 25
0
_Point top(const Quadratic& quad, double startT, double endT) {
    Quadratic sub;
    sub_divide(quad, startT, endT, sub);
    _Point topPt = sub[0];
    if (topPt.y > sub[2].y || (topPt.y == sub[2].y && topPt.x > sub[2].x)) {
        topPt = sub[2];
    }
    if (!between(sub[0].y, sub[1].y, sub[2].y)) {
        double extremeT;
        if (findExtrema(sub[0].y, sub[1].y, sub[2].y, &extremeT)) {
            extremeT = startT + (endT - startT) * extremeT;
            _Point test;
            xy_at_t(quad, extremeT, test.x, test.y);
            if (topPt.y > test.y || (topPt.y == test.y && topPt.x > test.x)) {
                topPt = test;
            }
        }
    }
    return topPt;
}
Exemplo n.º 26
0
_Point top(const Cubic& cubic, double startT, double endT) {
    Cubic sub;
    sub_divide(cubic, startT, endT, sub);
    _Point topPt = sub[0];
    if (topPt.y > sub[3].y || (topPt.y == sub[3].y && topPt.x > sub[3].x)) {
        topPt = sub[3];
    }
    double extremeTs[2];
    if (!monotonic_in_y(sub)) {
        int roots = findExtrema(sub[0].y, sub[1].y, sub[2].y, sub[3].y, extremeTs);
        for (int index = 0; index < roots; ++index) {
            _Point mid;
            double t = startT + (endT - startT) * extremeTs[index];
            xy_at_t(cubic, t, mid.x, mid.y);
            if (topPt.y > mid.y || (topPt.y == mid.y && topPt.x > mid.x)) {
                topPt = mid;
            }
        }
    }
    return topPt;
}
Exemplo n.º 27
0
bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
    bool t1IsLine = maxT1 - minT1 <= quad1Divisions;
    bool t2IsLine = maxT2 - minT2 <= quad2Divisions;
    if (t1IsLine | t2IsLine) {
        return intersectAsLine(minT1, maxT1, minT2, maxT2, t1IsLine, t2IsLine);
    }
    Quadratic smaller, larger;
    // FIXME: carry last subdivide and reduceOrder result with quad
    sub_divide(quad1, minT1, maxT1, intersections.swapped() ? larger : smaller);
    sub_divide(quad2, minT2, maxT2, intersections.swapped() ? smaller : larger);
    double minT, maxT;
    if (!bezier_clip(smaller, larger, minT, maxT)) {
        if (approximately_equal(minT, maxT)) {
            double smallT, largeT;
            _Point q2pt, q1pt;
            if (intersections.swapped()) {
                largeT = interp(minT2, maxT2, minT);
                xy_at_t(quad2, largeT, q2pt.x, q2pt.y);
                xy_at_t(quad1, minT1, q1pt.x, q1pt.y);
                if (AlmostEqualUlps(q2pt.x, q1pt.x) && AlmostEqualUlps(q2pt.y, q1pt.y)) {
                    smallT = minT1;
                } else {
                    xy_at_t(quad1, maxT1, q1pt.x, q1pt.y); // FIXME: debug code
                    assert(AlmostEqualUlps(q2pt.x, q1pt.x) && AlmostEqualUlps(q2pt.y, q1pt.y));
                    smallT = maxT1;
                }
            } else {
                smallT = interp(minT1, maxT1, minT);
                xy_at_t(quad1, smallT, q1pt.x, q1pt.y);
                xy_at_t(quad2, minT2, q2pt.x, q2pt.y);
                if (AlmostEqualUlps(q2pt.x, q1pt.x) && AlmostEqualUlps(q2pt.y, q1pt.y)) {
                    largeT = minT2;
                } else {
                    xy_at_t(quad2, maxT2, q2pt.x, q2pt.y); // FIXME: debug code
                    assert(AlmostEqualUlps(q2pt.x, q1pt.x) && AlmostEqualUlps(q2pt.y, q1pt.y));
                    largeT = maxT2;
                }
            }
            intersections.add(smallT, largeT);
            return true;
        }
        return false;
    }
    int split;
    if (intersections.swapped()) {
        double newMinT1 = interp(minT1, maxT1, minT);
        double newMaxT1 = interp(minT1, maxT1, maxT);
        split = (newMaxT1 - newMinT1 > (maxT1 - minT1) * tClipLimit) << 1;
#define VERBOSE 0
#if VERBOSE
        printf("%s d=%d s=%d new1=(%g,%g) old1=(%g,%g) split=%d\n", __FUNCTION__, depth,
            splits, newMinT1, newMaxT1, minT1, maxT1, split);
#endif
        minT1 = newMinT1;
        maxT1 = newMaxT1;
    } else {
        double newMinT2 = interp(minT2, maxT2, minT);
        double newMaxT2 = interp(minT2, maxT2, maxT);
        split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
#if VERBOSE
        printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n", __FUNCTION__, depth,
            splits, newMinT2, newMaxT2, minT2, maxT2, split);
#endif
        minT2 = newMinT2;
        maxT2 = newMaxT2;
    }
    return chop(minT1, maxT1, minT2, maxT2, split);
}
Exemplo n.º 28
0
static void hackToFixPartialCoincidence(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
    // look to see if non-coincident data basically has unsortable tangents

    // look to see if a point between non-coincident data is on the curve
    int cIndex;
    for (int uIndex = 0; uIndex < i.fUsed; ) {
        double bestDist1 = 1;
        double bestDist2 = 1;
        int closest1 = -1;
        int closest2 = -1;
        for (cIndex = 0; cIndex < i.fCoincidentUsed; ++cIndex) {
            double dist = fabs(i.fT[0][uIndex] - i.fCoincidentT[0][cIndex]);
            if (bestDist1 > dist) {
                bestDist1 = dist;
                closest1 = cIndex;
            }
            dist = fabs(i.fT[1][uIndex] - i.fCoincidentT[1][cIndex]);
            if (bestDist2 > dist) {
                bestDist2 = dist;
                closest2 = cIndex;
            }
        }
        _Line ends;
        _Point mid;
        double t1 = i.fT[0][uIndex];
        xy_at_t(q1, t1, ends[0].x, ends[0].y);
        xy_at_t(q1, i.fCoincidentT[0][closest1], ends[1].x, ends[1].y);
        double midT = (t1 + i.fCoincidentT[0][closest1]) / 2;
        xy_at_t(q1, midT, mid.x, mid.y);
        LineParameters params;
        params.lineEndPoints(ends);
        double midDist = params.pointDistance(mid);
        // Note that we prefer to always measure t error, which does not scale,
        // instead of point error, which is scale dependent. FIXME
        if (!approximately_zero(midDist)) {
            ++uIndex;
            continue;
        }
        double t2 = i.fT[1][uIndex];
        xy_at_t(q2, t2, ends[0].x, ends[0].y);
        xy_at_t(q2, i.fCoincidentT[1][closest2], ends[1].x, ends[1].y);
        midT = (t2 + i.fCoincidentT[1][closest2]) / 2;
        xy_at_t(q2, midT, mid.x, mid.y);
        params.lineEndPoints(ends);
        midDist = params.pointDistance(mid);
        if (!approximately_zero(midDist)) {
            ++uIndex;
            continue;
        }
        // if both midpoints are close to the line, lengthen coincident span
        int cEnd = closest1 ^ 1; // assume coincidence always travels in pairs
        if (!between(i.fCoincidentT[0][cEnd], t1, i.fCoincidentT[0][closest1])) {
            i.fCoincidentT[0][closest1] = t1;
        }
        cEnd = closest2 ^ 1;
        if (!between(i.fCoincidentT[0][cEnd], t2, i.fCoincidentT[0][closest2])) {
            i.fCoincidentT[0][closest2] = t2;
        }
        int remaining = --i.fUsed - uIndex;
        if (remaining > 0) {
            memmove(&i.fT[0][uIndex], &i.fT[0][uIndex + 1], sizeof(i.fT[0][0]) * remaining);
            memmove(&i.fT[1][uIndex], &i.fT[1][uIndex + 1], sizeof(i.fT[1][0]) * remaining);
        }
    }
    // if coincident data is subjectively a tiny span, replace it with a single point
    for (cIndex = 0; cIndex < i.fCoincidentUsed; ) {
        double start1 = i.fCoincidentT[0][cIndex];
        double end1 = i.fCoincidentT[0][cIndex + 1];
        _Line ends1;
        xy_at_t(q1, start1, ends1[0].x, ends1[0].y);
        xy_at_t(q1, end1, ends1[1].x, ends1[1].y);
        if (!AlmostEqualUlps(ends1[0].x, ends1[1].x) || AlmostEqualUlps(ends1[0].y, ends1[1].y)) {
            cIndex += 2;
            continue;
        }
        double start2 = i.fCoincidentT[1][cIndex];
        double end2 = i.fCoincidentT[1][cIndex + 1];
        _Line ends2;
        xy_at_t(q2, start2, ends2[0].x, ends2[0].y);
        xy_at_t(q2, end2, ends2[1].x, ends2[1].y);
        // again, approximately should be used with T values, not points FIXME
        if (!AlmostEqualUlps(ends2[0].x, ends2[1].x) || AlmostEqualUlps(ends2[0].y, ends2[1].y)) {
            cIndex += 2;
            continue;
        }
        if (approximately_less_than_zero(start1) || approximately_less_than_zero(end1)) {
            start1 = 0;
        } else if (approximately_greater_than_one(start1) || approximately_greater_than_one(end1)) {
            start1 = 1;
        } else {
            start1 = (start1 + end1) / 2;
        }
        if (approximately_less_than_zero(start2) || approximately_less_than_zero(end2)) {
            start2 = 0;
        } else if (approximately_greater_than_one(start2) || approximately_greater_than_one(end2)) {
            start2 = 1;
        } else {
            start2 = (start2 + end2) / 2;
        }
        i.insert(start1, start2);
        i.fCoincidentUsed -= 2;
        int remaining = i.fCoincidentUsed - cIndex;
        if (remaining > 0) {
            memmove(&i.fCoincidentT[0][cIndex], &i.fCoincidentT[0][cIndex + 2], sizeof(i.fCoincidentT[0][0]) * remaining);
            memmove(&i.fCoincidentT[1][cIndex], &i.fCoincidentT[1][cIndex + 2], sizeof(i.fCoincidentT[1][0]) * remaining);
        }
    }
}
Exemplo n.º 29
0
bool intersectAsLine(double minT1, double maxT1, double minT2, double maxT2,
       bool treat1AsLine, bool treat2AsLine)
{
    _Line line1, line2;
    if (intersections.swapped()) {
        std::swap(treat1AsLine, treat2AsLine);
        std::swap(minT1, minT2);
        std::swap(maxT1, maxT2);
    }
    if (coinMinT1 >= 0) {
        bool earlyExit;
        if ((earlyExit = coinMaxT1 == minT1)) {
            coinMaxT1 = maxT1;
        }
        if (coinMaxT2 == minT2) {
            coinMaxT2 = maxT2;
            return true;
        }
        if (earlyExit) {
            return true;
        }
        coinMinT1 = -1;
    }
    // do line/quadratic or even line/line intersection instead
    if (treat1AsLine) {
        xy_at_t(quad1, minT1, line1[0].x, line1[0].y);
        xy_at_t(quad1, maxT1, line1[1].x, line1[1].y);
    }
    if (treat2AsLine) {
        xy_at_t(quad2, minT2, line2[0].x, line2[0].y);
        xy_at_t(quad2, maxT2, line2[1].x, line2[1].y);
    }
    int pts;
    double smallT1, largeT1, smallT2, largeT2;
    if (treat1AsLine & treat2AsLine) {
        double t1[2], t2[2];
        pts = ::intersect(line1, line2, t1, t2);
        if (pts == 2) {
            smallT1 = interp(minT1, maxT1, t1[0]);
            largeT1 = interp(minT2, maxT2, t2[0]);
            smallT2 = interp(minT1, maxT1, t1[1]);
            largeT2 = interp(minT2, maxT2, t2[1]);
            intersections.addCoincident(smallT1, smallT2, largeT1, largeT2);
        } else {
            smallT1 = interp(minT1, maxT1, t1[0]);
            largeT1 = interp(minT2, maxT2, t2[0]);
            intersections.add(smallT1, largeT1);
        }
    } else {
        Intersections lq;
        pts = ::intersect(treat1AsLine ? quad2 : quad1,
                treat1AsLine ? line1 : line2, lq);
        if (pts == 2) { // if the line and edge are coincident treat differently
            _Point midQuad, midLine;
            double midQuadT = (lq.fT[0][0] + lq.fT[0][1]) / 2;
            xy_at_t(treat1AsLine ? quad2 : quad1, midQuadT, midQuad.x, midQuad.y);
            double lineT = t_at(treat1AsLine ? line1 : line2, midQuad);
            xy_at_t(treat1AsLine ? line1 : line2, lineT, midLine.x, midLine.y);
            if (AlmostEqualUlps(midQuad.x, midLine.x)
                    && AlmostEqualUlps(midQuad.y, midLine.y)) {
                smallT1 = lq.fT[0][0];
                largeT1 = lq.fT[1][0];
                smallT2 = lq.fT[0][1];
                largeT2 = lq.fT[1][1];
                if (treat2AsLine) {
                    smallT1 = interp(minT1, maxT1, smallT1);
                    smallT2 = interp(minT1, maxT1, smallT2);
                } else {
                    largeT1 = interp(minT2, maxT2, largeT1);
                    largeT2 = interp(minT2, maxT2, largeT2);
                }
                intersections.addCoincident(smallT1, smallT2, largeT1, largeT2);
                goto setCoinMinMax;
            }
        }
        for (int index = 0; index < pts; ++index) {
            smallT1 = lq.fT[0][index];
            largeT1 = lq.fT[1][index];
            if (treat2AsLine) {
                smallT1 = interp(minT1, maxT1, smallT1);
            } else {
                largeT1 = interp(minT2, maxT2, largeT1);
            }
            intersections.add(smallT1, largeT1);
        }
    }
    if (pts > 0) {
setCoinMinMax:
        coinMinT1 = minT1;
        coinMaxT1 = maxT1;
        coinMinT2 = minT2;
        coinMaxT2 = maxT2;
    }
    return pts > 0;
}
Exemplo n.º 30
0
// this flavor centers potential intersections recursively. In contrast, '2' may inadvertently
// chase intersections near quadratic ends, requiring odd hacks to find them.
static bool intersect3(const Cubic& cubic1, double t1s, double t1e, const Cubic& cubic2,
        double t2s, double t2e, double precisionScale, Intersections& i) {
    i.upDepth();
    bool result = false;
    Cubic c1, c2;
    sub_divide(cubic1, t1s, t1e, c1);
    sub_divide(cubic2, t2s, t2e, c2);
    SkTDArray<double> ts1;
    // OPTIMIZE: if c1 == c2, call once (happens when detecting self-intersection)
    cubic_to_quadratics(c1, calcPrecision(c1) * precisionScale, ts1);
    SkTDArray<double> ts2;
    cubic_to_quadratics(c2, calcPrecision(c2) * precisionScale, ts2);
    double t1Start = t1s;
    int ts1Count = ts1.count();
    for (int i1 = 0; i1 <= ts1Count; ++i1) {
        const double tEnd1 = i1 < ts1Count ? ts1[i1] : 1;
        const double t1 = t1s + (t1e - t1s) * tEnd1;
        Quadratic s1;
        int o1 = quadPart(cubic1, t1Start, t1, s1);
        double t2Start = t2s;
        int ts2Count = ts2.count();
        for (int i2 = 0; i2 <= ts2Count; ++i2) {
            const double tEnd2 = i2 < ts2Count ? ts2[i2] : 1;
            const double t2 = t2s + (t2e - t2s) * tEnd2;
            if (cubic1 == cubic2 && t1Start >= t2Start) {
                t2Start = t2;
                continue;
            }
            Quadratic s2;
            int o2 = quadPart(cubic2, t2Start, t2, s2);
        #if ONE_OFF_DEBUG
            char tab[] = "                  ";
            if (tLimits1[0][0] >= t1Start && tLimits1[0][1] <= t1
                    && tLimits1[1][0] >= t2Start && tLimits1[1][1] <= t2) {
                Cubic cSub1, cSub2;
                sub_divide(cubic1, t1Start, t1, cSub1);
                sub_divide(cubic2, t2Start, t2, cSub2);
                SkDebugf("%.*s %s t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)", i.depth()*2, tab, __FUNCTION__,
                        t1Start, t1, t2Start, t2);
                Intersections xlocals;
                intersectWithOrder(s1, o1, s2, o2, xlocals);
                SkDebugf(" xlocals.fUsed=%d\n", xlocals.used());
            }
        #endif
            Intersections locals;
            intersectWithOrder(s1, o1, s2, o2, locals);
            double coStart[2] = { -1 };
            _Point coPoint;
            int tCount = locals.used();
            for (int tIdx = 0; tIdx < tCount; ++tIdx) {
                double to1 = t1Start + (t1 - t1Start) * locals.fT[0][tIdx];
                double to2 = t2Start + (t2 - t2Start) * locals.fT[1][tIdx];
    // if the computed t is not sufficiently precise, iterate
                _Point p1 = xy_at_t(cubic1, to1);
                _Point p2 = xy_at_t(cubic2, to2);
                if (p1.approximatelyEqual(p2)) {
                    if (locals.fIsCoincident[0] & 1 << tIdx) {
                        if (coStart[0] < 0) {
                            coStart[0] = to1;
                            coStart[1] = to2;
                            coPoint = p1;
                        } else {
                            i.insertCoincidentPair(coStart[0], to1, coStart[1], to2, coPoint, p1);
                            coStart[0] = -1;
                        }
                        result = true;
                    } else if (cubic1 != cubic2 || !approximately_equal(to1, to2)) {
                        if (i.swapped()) { // FIXME: insert should respect swap
                            i.insert(to2, to1, p1);
                        } else {
                            i.insert(to1, to2, p1);
                        }
                        result = true;
                    }
                } else {
                    double offset = precisionScale / 16; // FIME: const is arbitrary -- test & refine
#if 1
                    double c1Bottom = tIdx == 0 ? 0 :
                            (t1Start + (t1 - t1Start) * locals.fT[0][tIdx - 1] + to1) / 2;
                    double c1Min = SkTMax(c1Bottom, to1 - offset);
                    double c1Top = tIdx == tCount - 1 ? 1 :
                            (t1Start + (t1 - t1Start) * locals.fT[0][tIdx + 1] + to1) / 2;
                    double c1Max = SkTMin(c1Top, to1 + offset);
                    double c2Min = SkTMax(0., to2 - offset);
                    double c2Max = SkTMin(1., to2 + offset);
                #if ONE_OFF_DEBUG
                    SkDebugf("%.*s %s 1 contains1=%d/%d contains2=%d/%d\n", i.depth()*2, tab, __FUNCTION__,
                            c1Min <= tLimits1[0][1] && tLimits1[0][0] <= c1Max
                         && c2Min <= tLimits1[1][1] && tLimits1[1][0] <= c2Max,
                            to1 - offset <= tLimits1[0][1] && tLimits1[0][0] <= to1 + offset
                         && to2 - offset <= tLimits1[1][1] && tLimits1[1][0] <= to2 + offset,
                            c1Min <= tLimits2[0][1] && tLimits2[0][0] <= c1Max
                         && c2Min <= tLimits2[1][1] && tLimits2[1][0] <= c2Max,
                            to1 - offset <= tLimits2[0][1] && tLimits2[0][0] <= to1 + offset
                         && to2 - offset <= tLimits2[1][1] && tLimits2[1][0] <= to2 + offset);
                    SkDebugf("%.*s %s 1 c1Bottom=%1.9g c1Top=%1.9g c2Bottom=%1.9g c2Top=%1.9g"
                            " 1-o=%1.9g 1+o=%1.9g 2-o=%1.9g 2+o=%1.9g offset=%1.9g\n",
                            i.depth()*2, tab, __FUNCTION__, c1Bottom, c1Top, 0., 1.,
                            to1 - offset, to1 + offset, to2 - offset, to2 + offset, offset);
                    SkDebugf("%.*s %s 1 to1=%1.9g to2=%1.9g c1Min=%1.9g c1Max=%1.9g c2Min=%1.9g"
                            " c2Max=%1.9g\n", i.depth()*2, tab, __FUNCTION__, to1, to2, c1Min, c1Max, c2Min, c2Max);
                #endif
                    intersect3(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offset, i);
                #if ONE_OFF_DEBUG
                    SkDebugf("%.*s %s 1 i.used=%d t=%1.9g\n", i.depth()*2, tab, __FUNCTION__, i.used(),
                            i.used() > 0 ? i.fT[0][i.used() - 1] : -1);
                #endif
                    if (tCount > 1) {
                        c1Min = SkTMax(0., to1 - offset);
                        c1Max = SkTMin(1., to1 + offset);
                        double c2Bottom = tIdx == 0 ? to2 :
                                (t2Start + (t2 - t2Start) * locals.fT[1][tIdx - 1] + to2) / 2;
                        double c2Top = tIdx == tCount - 1 ? to2 :
                                (t2Start + (t2 - t2Start) * locals.fT[1][tIdx + 1] + to2) / 2;
                        if (c2Bottom > c2Top) {
                            SkTSwap(c2Bottom, c2Top);
                        }
                        if (c2Bottom == to2) {
                            c2Bottom = 0;
                        }
                        if (c2Top == to2) {
                            c2Top = 1;
                        }
                        c2Min = SkTMax(c2Bottom, to2 - offset);
                        c2Max = SkTMin(c2Top, to2 + offset);
                    #if ONE_OFF_DEBUG
                        SkDebugf("%.*s %s 2 contains1=%d/%d contains2=%d/%d\n", i.depth()*2, tab, __FUNCTION__,
                            c1Min <= tLimits1[0][1] && tLimits1[0][0] <= c1Max
                         && c2Min <= tLimits1[1][1] && tLimits1[1][0] <= c2Max,
                            to1 - offset <= tLimits1[0][1] && tLimits1[0][0] <= to1 + offset
                         && to2 - offset <= tLimits1[1][1] && tLimits1[1][0] <= to2 + offset,
                            c1Min <= tLimits2[0][1] && tLimits2[0][0] <= c1Max
                         && c2Min <= tLimits2[1][1] && tLimits2[1][0] <= c2Max,
                            to1 - offset <= tLimits2[0][1] && tLimits2[0][0] <= to1 + offset
                         && to2 - offset <= tLimits2[1][1] && tLimits2[1][0] <= to2 + offset);
                        SkDebugf("%.*s %s 2 c1Bottom=%1.9g c1Top=%1.9g c2Bottom=%1.9g c2Top=%1.9g"
                                " 1-o=%1.9g 1+o=%1.9g 2-o=%1.9g 2+o=%1.9g offset=%1.9g\n",
                                i.depth()*2, tab, __FUNCTION__, 0., 1., c2Bottom, c2Top,
                                to1 - offset, to1 + offset, to2 - offset, to2 + offset, offset);
                        SkDebugf("%.*s %s 2 to1=%1.9g to2=%1.9g c1Min=%1.9g c1Max=%1.9g c2Min=%1.9g"
                                " c2Max=%1.9g\n", i.depth()*2, tab, __FUNCTION__, to1, to2, c1Min, c1Max, c2Min, c2Max);
                    #endif
                        intersect3(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offset, i);
                #if ONE_OFF_DEBUG
                    SkDebugf("%.*s %s 2 i.used=%d t=%1.9g\n", i.depth()*2, tab, __FUNCTION__, i.used(),
                            i.used() > 0 ? i.fT[0][i.used() - 1] : -1);
                #endif
                        c1Min = SkTMax(c1Bottom, to1 - offset);
                        c1Max = SkTMin(c1Top, to1 + offset);
                    #if ONE_OFF_DEBUG
                        SkDebugf("%.*s %s 3 contains1=%d/%d contains2=%d/%d\n", i.depth()*2, tab, __FUNCTION__,
                            c1Min <= tLimits1[0][1] && tLimits1[0][0] <= c1Max
                         && c2Min <= tLimits1[1][1] && tLimits1[1][0] <= c2Max,
                            to1 - offset <= tLimits1[0][1] && tLimits1[0][0] <= to1 + offset
                         && to2 - offset <= tLimits1[1][1] && tLimits1[1][0] <= to2 + offset,
                            c1Min <= tLimits2[0][1] && tLimits2[0][0] <= c1Max
                         && c2Min <= tLimits2[1][1] && tLimits2[1][0] <= c2Max,
                            to1 - offset <= tLimits2[0][1] && tLimits2[0][0] <= to1 + offset
                         && to2 - offset <= tLimits2[1][1] && tLimits2[1][0] <= to2 + offset);
                        SkDebugf("%.*s %s 3 c1Bottom=%1.9g c1Top=%1.9g c2Bottom=%1.9g c2Top=%1.9g"
                                " 1-o=%1.9g 1+o=%1.9g 2-o=%1.9g 2+o=%1.9g offset=%1.9g\n",
                                i.depth()*2, tab, __FUNCTION__, 0., 1., c2Bottom, c2Top,
                                to1 - offset, to1 + offset, to2 - offset, to2 + offset, offset);
                        SkDebugf("%.*s %s 3 to1=%1.9g to2=%1.9g c1Min=%1.9g c1Max=%1.9g c2Min=%1.9g"
                                " c2Max=%1.9g\n", i.depth()*2, tab, __FUNCTION__, to1, to2, c1Min, c1Max, c2Min, c2Max);
                    #endif
                        intersect3(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offset, i);
                #if ONE_OFF_DEBUG
                    SkDebugf("%.*s %s 3 i.used=%d t=%1.9g\n", i.depth()*2, tab, __FUNCTION__, i.used(),
                            i.used() > 0 ? i.fT[0][i.used() - 1] : -1);
                #endif
                    }
#else
                    double c1Bottom = tIdx == 0 ? 0 :
                            (t1Start + (t1 - t1Start) * locals.fT[0][tIdx - 1] + to1) / 2;
                    double c1Min = SkTMax(c1Bottom, to1 - offset);
                    double c1Top = tIdx == tCount - 1 ? 1 :
                            (t1Start + (t1 - t1Start) * locals.fT[0][tIdx + 1] + to1) / 2;
                    double c1Max = SkTMin(c1Top, to1 + offset);
                    double c2Bottom = tIdx == 0 ? to2 :
                            (t2Start + (t2 - t2Start) * locals.fT[1][tIdx - 1] + to2) / 2;
                    double c2Top = tIdx == tCount - 1 ? to2 :
                            (t2Start + (t2 - t2Start) * locals.fT[1][tIdx + 1] + to2) / 2;
                    if (c2Bottom > c2Top) {
                        SkTSwap(c2Bottom, c2Top);
                    }
                    if (c2Bottom == to2) {
                        c2Bottom = 0;
                    }
                    if (c2Top == to2) {
                        c2Top = 1;
                    }
                    double c2Min = SkTMax(c2Bottom, to2 - offset);
                    double c2Max = SkTMin(c2Top, to2 + offset);
                #if ONE_OFF_DEBUG
                    SkDebugf("%s contains1=%d/%d contains2=%d/%d\n", __FUNCTION__,
                            c1Min <= 0.210357794 && 0.210357794 <= c1Max
                         && c2Min <= 0.223476406 && 0.223476406 <= c2Max,
                            to1 - offset <= 0.210357794 && 0.210357794 <= to1 + offset
                         && to2 - offset <= 0.223476406 && 0.223476406 <= to2 + offset,
                            c1Min <= 0.211324707 && 0.211324707 <= c1Max
                         && c2Min <= 0.211327209 && 0.211327209 <= c2Max,
                            to1 - offset <= 0.211324707 && 0.211324707 <= to1 + offset
                         && to2 - offset <= 0.211327209 && 0.211327209 <= to2 + offset);
                    SkDebugf("%s c1Bottom=%1.9g c1Top=%1.9g c2Bottom=%1.9g c2Top=%1.9g"
                            " 1-o=%1.9g 1+o=%1.9g 2-o=%1.9g 2+o=%1.9g offset=%1.9g\n",
                            __FUNCTION__, c1Bottom, c1Top, c2Bottom, c2Top,
                            to1 - offset, to1 + offset, to2 - offset, to2 + offset, offset);
                    SkDebugf("%s to1=%1.9g to2=%1.9g c1Min=%1.9g c1Max=%1.9g c2Min=%1.9g"
                            " c2Max=%1.9g\n", __FUNCTION__, to1, to2, c1Min, c1Max, c2Min, c2Max);
                #endif
#endif
                    intersect3(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offset, i);
                    // TODO: if no intersection is found, either quadratics intersected where
                    // cubics did not, or the intersection was missed. In the former case, expect
                    // the quadratics to be nearly parallel at the point of intersection, and check
                    // for that.
                }
            }
            SkASSERT(coStart[0] == -1);
            t2Start = t2;
        }
        t1Start = t1;
    }
    i.downDepth();
    return result;
}