bool intersect3(const Cubic& c1, const Cubic& c2, Intersections& i) {
    bool result = intersect3(c1, 0, 1, c2, 0, 1, 1, i);
    // FIXME: pass in cached bounds from caller
    _Rect c1Bounds, c2Bounds;
    c1Bounds.setBounds(c1); // OPTIMIZE use setRawBounds ?
    c2Bounds.setBounds(c2);
    result |= intersectEnd(c1, false, c2, c2Bounds, i);
    result |= intersectEnd(c1, true, c2, c2Bounds, i);
    bool selfIntersect = c1 == c2;
    if (!selfIntersect) {
        i.swap();
        result |= intersectEnd(c2, false, c1, c1Bounds, i);
        result |= intersectEnd(c2, true, c1, c1Bounds, i);
        i.swap();
    }
    // If an end point and a second point very close to the end is returned, the second
    // point may have been detected because the approximate quads
    // intersected at the end and close to it. Verify that the second point is valid.
    if (i.used() <= 1 || i.coincidentUsed()) {
        return result;
    }
    _Point pt[2];
    if (closeStart(c1, 0, i, pt[0]) && closeStart(c2, 1, i, pt[1])
            && pt[0].approximatelyEqual(pt[1])) {
        i.removeOne(1);
    }
    if (closeEnd(c1, 0, i, pt[0]) && closeEnd(c2, 1, i, pt[1])
            && pt[0].approximatelyEqual(pt[1])) {
        i.removeOne(i.used() - 2);
    }
    return result;
}
Example #2
0
// FIXME: add intersection of convex null on cubics' ends with the opposite cubic. The hull line
// segments can be constructed to be only as long as the calculated precision suggests. If the hull
// line segments intersect the cubic, then use the intersections to construct a subdivision for
// quadratic curve fitting.
bool intersect2(const Cubic& c1, const Cubic& c2, Intersections& i) {
#if SK_DEBUG
    debugDepth = 0;
#endif
    bool result = intersect2(c1, 0, 1, c2, 0, 1, 1, i);
    // FIXME: pass in cached bounds from caller
    _Rect c1Bounds, c2Bounds;
    c1Bounds.setBounds(c1); // OPTIMIZE use setRawBounds ?
    c2Bounds.setBounds(c2);
    result |= intersectEnd(c1, false, c2, c2Bounds, i);
    result |= intersectEnd(c1, true, c2, c2Bounds, i);
    i.swap();
    result |= intersectEnd(c2, false, c1, c1Bounds, i);
    result |= intersectEnd(c2, true, c1, c1Bounds, i);
    i.swap();
    return result;
}
Example #3
0
// this flavor approximates the cubics with quads to find the intersecting ts
// OPTIMIZE: if this strategy proves successful, the quad approximations, or the ts used
// to create the approximations, could be stored in the cubic segment
// FIXME: this strategy needs to intersect the convex hull on either end with the opposite to
// account for inset quadratics that cause the endpoint intersection to avoid detection
// the segments can be very short -- the length of the maximum quadratic error (precision)
// FIXME: this needs to recurse on itself, taking a range of T values and computing the new
// t range ala is linear inner. The range can be figured by taking the dx/dy and determining
// the fraction that matches the precision. That fraction is the change in t for the smaller cubic.
static bool intersect2(const Cubic& cubic1, double t1s, double t1e, const Cubic& cubic2,
        double t2s, double t2e, double precisionScale, Intersections& i) {
    Cubic c1, c2;
    sub_divide(cubic1, t1s, t1e, c1);
    sub_divide(cubic2, t2s, t2e, c2);
    SkTDArray<double> ts1;
    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;
        Cubic part1;
        sub_divide(cubic1, t1Start, t1, part1);
        Quadratic q1;
        demote_cubic_to_quad(part1, q1);
  //      start here;
        // should reduceOrder be looser in this use case if quartic is going to blow up on an
        // extremely shallow quadratic?
        Quadratic s1;
        int o1 = reduceOrder(q1, 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;
            Cubic part2;
            sub_divide(cubic2, t2Start, t2, part2);
            Quadratic q2;
            demote_cubic_to_quad(part2, q2);
            Quadratic s2;
            double o2 = reduceOrder(q2, s2);
            Intersections locals;
            if (o1 == 3 && o2 == 3) {
                intersect2(q1, q2, locals);
            } else if (o1 <= 2 && o2 <= 2) {
                locals.fUsed = intersect((const _Line&) s1, (const _Line&) s2, locals.fT[0],
                        locals.fT[1]);
            } else if (o1 == 3 && o2 <= 2) {
                intersect(q1, (const _Line&) s2, locals);
            } else {
                SkASSERT(o1 <= 2 && o2 == 3);
                intersect(q2, (const _Line&) s1, locals);
                for (int s = 0; s < locals.fUsed; ++s) {
                    SkTSwap(locals.fT[0][s], locals.fT[1][s]);
                }
            }
            for (int tIdx = 0; tIdx < locals.used(); ++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, p2;
                xy_at_t(cubic1, to1, p1.x, p1.y);
                xy_at_t(cubic2, to2, p2.x, p2.y);
                if (p1.approximatelyEqual(p2)) {
                    i.insert(i.swapped() ? to2 : to1, i.swapped() ? to1 : to2);
                } else {
                    double dt1, dt2;
                    computeDelta(cubic1, to1, (t1e - t1s), cubic2, to2, (t2e - t2s), dt1, dt2);
                    double scale = precisionScale;
                    if (dt1 > 0.125 || dt2 > 0.125) {
                        scale /= 2;
                        SkDebugf("%s scale=%1.9g\n", __FUNCTION__, scale);
                    }
#if SK_DEBUG
                    ++debugDepth;
                    assert(debugDepth < 10);
#endif
                    i.swap();
                    intersect2(cubic2, SkTMax(to2 - dt2, 0.), SkTMin(to2 + dt2, 1.),
                            cubic1, SkTMax(to1 - dt1, 0.), SkTMin(to1 + dt1, 1.), scale, i);
                    i.swap();
#if SK_DEBUG
                    --debugDepth;
#endif
                }
            }
            t2Start = t2;
        }
        t1Start = t1;
    }
    return i.intersected();
}