Example #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
    }
}
Example #2
0
// check to see if it is a quadratic or a line
static int check_quadratic(const SkDCubic& cubic, SkDCubic& reduction) {
    double dx10 = cubic[1].fX - cubic[0].fX;
    double dx23 = cubic[2].fX - cubic[3].fX;
    double midX = cubic[0].fX + dx10 * 3 / 2;
    double sideAx = midX - cubic[3].fX;
    double sideBx = dx23 * 3 / 2;
    if (approximately_zero(sideAx) ? !approximately_equal(sideAx, sideBx)
            : !AlmostEqualUlps(sideAx, sideBx)) {
        return 0;
    }
    double dy10 = cubic[1].fY - cubic[0].fY;
    double dy23 = cubic[2].fY - cubic[3].fY;
    double midY = cubic[0].fY + dy10 * 3 / 2;
    double sideAy = midY - cubic[3].fY;
    double sideBy = dy23 * 3 / 2;
    if (approximately_zero(sideAy) ? !approximately_equal(sideAy, sideBy)
            : !AlmostEqualUlps(sideAy, sideBy)) {
        return 0;
    }
    reduction[0] = cubic[0];
    reduction[1].fX = midX;
    reduction[1].fY = midY;
    reduction[2] = cubic[3];
    return 3;
}
Example #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;
}
Example #4
0
// unlike quadratic roots, this does not discard real roots <= 0 or >= 1
int quadraticRootsReal(const double A, const double B, const double C, double s[2]) {
    const double p = B / (2 * A);
    const double q = C / A;
    if (approximately_zero(A) && (approximately_zero_inverse(p) || approximately_zero_inverse(q))) {
        if (approximately_zero(B)) {
            s[0] = 0;
            return C == 0;
        }
        s[0] = -C / B;
        return 1;
    }
    /* normal form: x^2 + px + q = 0 */
    const double p2 = p * p;
#if 0
    double D = AlmostEqualUlps(p2, q) ? 0 : p2 - q;
    if (D <= 0) {
        if (D < 0) {
            return 0;
        }
        s[0] = -p;
        SkDebugf("[%d] %1.9g\n", 1, s[0]);
        return 1;
    }
    double sqrt_D = sqrt(D);
    s[0] = sqrt_D - p;
    s[1] = -sqrt_D - p;
    SkDebugf("[%d] %1.9g %1.9g\n", 2, s[0], s[1]);
    return 2;
#else
    if (!AlmostEqualUlps(p2, q) && p2 < q) {
        return 0;
    }
    double sqrt_D = 0;
    if (p2 > q) {
        sqrt_D = sqrt(p2 - q);
    }
    s[0] = sqrt_D - p;
    s[1] = -sqrt_D - p;
#if 0
    if (AlmostEqualUlps(s[0], s[1])) {
        SkDebugf("[%d] %1.9g\n", 1, s[0]);
    } else {
        SkDebugf("[%d] %1.9g %1.9g\n", 2, s[0], s[1]);
    }
#endif
    return 1 + !AlmostEqualUlps(s[0], s[1]);
#endif
}
Example #5
0
double SkDLine::nearPoint(const SkDPoint& xy) const {
    if (!AlmostBetweenUlps(fPts[0].fX, xy.fX, fPts[1].fX)
            || !AlmostBetweenUlps(fPts[0].fY, xy.fY, fPts[1].fY)) {
        return -1;
    }
    // project a perpendicular ray from the point to the line; find the T on the line
    SkDVector len = fPts[1] - fPts[0]; // the x/y magnitudes of the line
    double denom = len.fX * len.fX + len.fY * len.fY;  // see DLine intersectRay
    SkDVector ab0 = xy - fPts[0];
    double numer = len.fX * ab0.fX + ab0.fY * len.fY;
    if (!between(0, numer, denom)) {
        return -1;
    }
    double t = numer / denom;
    SkDPoint realPt = ptAtT(t);
    double dist = realPt.distance(xy);   // OPTIMIZATION: can we compare against distSq instead ?
    // find the ordinal in the original line with the largest unsigned exponent
    double tiniest = SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
    double largest = SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
    largest = SkTMax(largest, -tiniest);
    if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance?
        return -1;
    }
    t = SkPinT(t);
    SkASSERT(between(0, t, 1));
    return t;
}
Example #6
0
// reduce to a quadratic or smaller
// look for identical points
// look for all four points in a line
    // note that three points in a line doesn't simplify a cubic
// look for approximation with single quadratic
    // save approximation with multiple quadratics for later
int SkReduceOrder::reduce(const SkDQuad& quad) {
    int index, minX, maxX, minY, maxY;
    int minXSet, minYSet;
    minX = maxX = minY = maxY = 0;
    minXSet = minYSet = 0;
    for (index = 1; index < 3; ++index) {
        if (quad[minX].fX > quad[index].fX) {
            minX = index;
        }
        if (quad[minY].fY > quad[index].fY) {
            minY = index;
        }
        if (quad[maxX].fX < quad[index].fX) {
            maxX = index;
        }
        if (quad[maxY].fY < quad[index].fY) {
            maxY = index;
        }
    }
    for (index = 0; index < 3; ++index) {
        if (AlmostEqualUlps(quad[index].fX, quad[minX].fX)) {
            minXSet |= 1 << index;
        }
        if (AlmostEqualUlps(quad[index].fY, quad[minY].fY)) {
            minYSet |= 1 << index;
        }
    }
    if ((minXSet & 0x05) == 0x5 && (minYSet & 0x05) == 0x5) { // test for degenerate
        // this quad starts and ends at the same place, so never contributes
        // to the fill
        return coincident_line(quad, fQuad);
    }
    if (minXSet == 0x7) {  // test for vertical line
        return vertical_line(quad, fQuad);
    }
    if (minYSet == 0x7) {  // test for horizontal line
        return horizontal_line(quad, fQuad);
    }
    int result = check_linear(quad, minX, maxX, minY, maxY, fQuad);
    if (result) {
        return result;
    }
    fQuad = quad;
    return 3;
}
Example #7
0
void SkOpSegment::debugValidate() const {
#if DEBUG_VALIDATE
    int count = fTs.count();
    SK_ALWAYSBREAK(count >= 2);
    SK_ALWAYSBREAK(fTs[0].fT == 0);
    SK_ALWAYSBREAK(fTs[count - 1].fT == 1);
    int done = 0;
    double t = -1;
    const SkOpSpan* last = NULL;
    bool tinyTFound = false;
    bool hasLoop = false;
    for (int i = 0; i < count; ++i) {
        const SkOpSpan& span = fTs[i];
        SK_ALWAYSBREAK(t <= span.fT);
        t = span.fT;
        int otherIndex = span.fOtherIndex;
        const SkOpSegment* other = span.fOther;
        SK_ALWAYSBREAK(other != this || fVerb == SkPath::kCubic_Verb);
        const SkOpSpan& otherSpan = other->fTs[otherIndex];
        SK_ALWAYSBREAK(otherSpan.fPt == span.fPt);
        SK_ALWAYSBREAK(otherSpan.fOtherT == t);
        SK_ALWAYSBREAK(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]);
        done += span.fDone;
        if (last) {
            SK_ALWAYSBREAK(last->fT != span.fT || last->fOther != span.fOther);
            bool tsEqual = last->fT == span.fT;
            bool tsPreciselyEqual = precisely_equal(last->fT, span.fT);
            SK_ALWAYSBREAK(!tsEqual || tsPreciselyEqual);
            bool pointsEqual = last->fPt == span.fPt;
            bool pointsNearlyEqual = AlmostEqualUlps(last->fPt, span.fPt);
#if 0  // bufferOverflow test triggers this
            SK_ALWAYSBREAK(!tsPreciselyEqual || pointsNearlyEqual);
#endif
//            SK_ALWAYSBREAK(!last->fTiny || !tsPreciselyEqual || span.fTiny || tinyTFound);
            SK_ALWAYSBREAK(last->fTiny || tsPreciselyEqual || !pointsEqual || hasLoop);
            SK_ALWAYSBREAK(!last->fTiny || pointsEqual);
            SK_ALWAYSBREAK(!last->fTiny || last->fDone);
            SK_ALWAYSBREAK(!last->fSmall || pointsNearlyEqual);
            SK_ALWAYSBREAK(!last->fSmall || last->fDone);
//            SK_ALWAYSBREAK(!last->fSmall || last->fTiny);
//            SK_ALWAYSBREAK(last->fTiny || !pointsEqual || last->fDone == span.fDone);
            if (last->fTiny) {
                tinyTFound |= !tsPreciselyEqual;
            } else {
                tinyTFound = false;
            }
        }
        last = &span;
        hasLoop |= last->fLoop;
    }
    SK_ALWAYSBREAK(done == fDoneSpans);
//    if (fAngles.count() ) {
//        fAngles.begin()->debugValidateLoop();
//    }
#endif
}
// check to see if it is a quadratic or a line
static int check_quadratic(const Cubic& cubic, Cubic& reduction) {
    double dx10 = cubic[1].x - cubic[0].x;
    double dx23 = cubic[2].x - cubic[3].x;
    double midX = cubic[0].x + dx10 * 3 / 2;
    if (!AlmostEqualUlps(midX - cubic[3].x, dx23 * 3 / 2)) {
        return 0;
    }
    double dy10 = cubic[1].y - cubic[0].y;
    double dy23 = cubic[2].y - cubic[3].y;
    double midY = cubic[0].y + dy10 * 3 / 2;
    if (!AlmostEqualUlps(midY - cubic[3].y, dy23 * 3 / 2)) {
        return 0;
    }
    reduction[0] = cubic[0];
    reduction[1].x = midX;
    reduction[1].y = midY;
    reduction[2] = cubic[3];
    return 3;
}
Example #9
0
// reduce to a quadratic or smaller
// look for identical points
// look for all four points in a line
    // note that three points in a line doesn't simplify a cubic
// look for approximation with single quadratic
    // save approximation with multiple quadratics for later
int reduceOrder(const Quadratic& quad, Quadratic& reduction) {
    int index, minX, maxX, minY, maxY;
    int minXSet, minYSet;
    minX = maxX = minY = maxY = 0;
    minXSet = minYSet = 0;
    for (index = 1; index < 3; ++index) {
        if (quad[minX].x > quad[index].x) {
            minX = index;
        }
        if (quad[minY].y > quad[index].y) {
            minY = index;
        }
        if (quad[maxX].x < quad[index].x) {
            maxX = index;
        }
        if (quad[maxY].y < quad[index].y) {
            maxY = index;
        }
    }
    for (index = 0; index < 3; ++index) {
        if (AlmostEqualUlps(quad[index].x, quad[minX].x)) {
            minXSet |= 1 << index;
        }
        if (AlmostEqualUlps(quad[index].y, quad[minY].y)) {
            minYSet |= 1 << index;
        }
    }
    if (minXSet == 0x7) { // test for vertical line
        if (minYSet == 0x7) { // return 1 if all four are coincident
            return coincident_line(quad, reduction);
        }
        return vertical_line(quad, reduction);
    }
    if (minYSet == 0xF) { // test for horizontal line
        return horizontal_line(quad, reduction);
    }
    int result = check_linear(quad, reduction, minX, maxX, minY, maxY);
    if (result) {
        return result;
    }
    memcpy(reduction, quad, sizeof(Quadratic));
    return 3;
}
static bool checkEndPointH(const SkDPoint& end, double left, double right,
                           double y, bool flipped, double* tPtr) {
    if (!between(left, end.fX, right) || !AlmostEqualUlps(y, end.fY)) {
        return false;
    }
    double t = (end.fX - left) / (right - left);
    SkASSERT(between(0, t, 1));
    *tPtr = flipped ? 1 - t : t;
    return true;
}
static bool checkEndPointV(const SkDPoint& end, double top, double bottom,
                           double x, bool flipped, double* tPtr) {
    if (!between(top, end.fY, bottom) || !AlmostEqualUlps(x, end.fX)) {
        return false;
    }
    double t = (end.fY - top) / (bottom - top);
    SkASSERT(between(0, t, 1));
    *tPtr = flipped ? 1 - t : t;
    return true;
}
Example #12
0
// reduce to a quadratic or smaller
// look for identical points
// look for all four points in a line
    // note that three points in a line doesn't simplify a cubic
// look for approximation with single quadratic
    // save approximation with multiple quadratics for later
int SkReduceOrder::reduce(const SkDQuad& quad) {
    int index, minX, maxX, minY, maxY;
    int minXSet, minYSet;
    minX = maxX = minY = maxY = 0;
    minXSet = minYSet = 0;
    for (index = 1; index < 3; ++index) {
        if (quad[minX].fX > quad[index].fX) {
            minX = index;
        }
        if (quad[minY].fY > quad[index].fY) {
            minY = index;
        }
        if (quad[maxX].fX < quad[index].fX) {
            maxX = index;
        }
        if (quad[maxY].fY < quad[index].fY) {
            maxY = index;
        }
    }
    for (index = 0; index < 3; ++index) {
        if (AlmostEqualUlps(quad[index].fX, quad[minX].fX)) {
            minXSet |= 1 << index;
        }
        if (AlmostEqualUlps(quad[index].fY, quad[minY].fY)) {
            minYSet |= 1 << index;
        }
    }
    if (minXSet == 0x7) {  // test for vertical line
        if (minYSet == 0x7) {  // return 1 if all four are coincident
            return coincident_line(quad, fQuad);
        }
        return vertical_line(quad, fQuad);
    }
    if (minYSet == 0xF) {  // test for horizontal line
        return horizontal_line(quad, fQuad);
    }
    int result = check_linear(quad, minX, maxX, minY, maxY, fQuad);
    if (result) {
        return result;
    }
    fQuad = quad;
    return 3;
}
Example #13
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);
            }
        }
    }
}
double SkDLine::NearPointV(const SkDPoint& xy, double top, double bottom, double x) {
    if (!AlmostEqualUlps(xy.fX, x)) {
        return -1;
    }
    if (!AlmostBetweenUlps(top, xy.fY, bottom)) {
        return -1;
    }
    double t = (xy.fY - top) / (bottom - top);
    t = SkPinT(t);
    SkASSERT(between(0, t, 1));
    return t;
}
double SkDLine::NearPointH(const SkDPoint& xy, double left, double right, double y) {
    if (!AlmostEqualUlps(xy.fY, y)) {
        return -1;
    }
    if (!AlmostBetweenUlps(left, xy.fX, right)) {
        return -1;
    }
    double t = (xy.fX - left) / (right - left);
    t = SkPinT(t);
    SkASSERT(between(0, t, 1));
    return t;
}
Example #16
0
static void testC(skiatest::Reporter* reporter, const SkDCubic* cubics, const char* name,
                  int firstTest, size_t testCount) {
    // test if computed line end points are valid
    for (size_t index = firstTest; index < testCount; ++index) {
        const SkDCubic& cubic = cubics[index];
        double precision = cubic.calcPrecision();
        SkTDArray<SkDQuad> quads;
        CubicToQuads(cubic, precision, quads);
        if (!AlmostEqualUlps(cubic[0].fX, quads[0][0].fX)
                || !AlmostEqualUlps(cubic[0].fY, quads[0][0].fY)) {
            SkDebugf("[%d] unmatched start\n", static_cast<int>(index));
            REPORTER_ASSERT(reporter, 0);
        }
        int last = quads.count() - 1;
        if (!AlmostEqualUlps(cubic[3].fX, quads[last][2].fX)
                || !AlmostEqualUlps(cubic[3].fY, quads[last][2].fY)) {
            SkDebugf("[%d] unmatched end\n", static_cast<int>(index));
            REPORTER_ASSERT(reporter, 0);
        }
    }
}
static void LineParameterTest(skiatest::Reporter* reporter) {
    for (size_t index = 0; index < tests_count; ++index) {
        SkLineParameters lineParameters;
        const SkDCubic& cubic = tests[index];
        lineParameters.cubicEndPoints(cubic);
        double denormalizedDistance[2];
        denormalizedDistance[0] = lineParameters.controlPtDistance(cubic, 1);
        denormalizedDistance[1] = lineParameters.controlPtDistance(cubic, 2);
        double normalSquared = lineParameters.normalSquared();
        size_t inner;
        for (inner = 0; inner < 2; ++inner) {
            double distSq = denormalizedDistance[inner];
            distSq *= distSq;
            double answersSq = answers[index][inner];
            answersSq *= answersSq;
            if (AlmostEqualUlps(distSq, normalSquared * answersSq)) {
                continue;
            }
            SkDebugf("%s [%d,%d] denormalizedDistance:%g != answer:%g"
                    " distSq:%g answerSq:%g normalSquared:%g\n",
                    __FUNCTION__, static_cast<int>(index), (int)inner,
                    denormalizedDistance[inner], answers[index][inner],
                    distSq, answersSq, normalSquared);
        }
        lineParameters.normalize();
        double normalizedDistance[2];
        normalizedDistance[0] = lineParameters.controlPtDistance(cubic, 1);
        normalizedDistance[1] = lineParameters.controlPtDistance(cubic, 2);
        for (inner = 0; inner < 2; ++inner) {
            if (AlmostEqualUlps(fabs(normalizedDistance[inner]), answers[index][inner])) {
                continue;
            }
            SkDebugf("%s [%d,%d] normalizedDistance:%1.10g != answer:%g\n",
                    __FUNCTION__, static_cast<int>(index), (int)inner,
                    normalizedDistance[inner], answers[index][inner]);
            REPORTER_ASSERT(reporter, 0);
        }
    }
}
static int horizontal_coincident(const SkDLine& line, double y) {
    double min = line[0].fY;
    double max = line[1].fY;
    if (min > max) {
        SkTSwap(min, max);
    }
    if (min > y || max < y) {
        return 0;
    }
    if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX)) {
        return 2;
    }
    return 1;
}
static int vertical_coincident(const SkDLine& line, double x) {
    double min = line[0].fX;
    double max = line[1].fX;
    if (min > max) {
        SkTSwap(min, max);
    }
    if (!precisely_between(min, x, max)) {
        return 0;
    }
    if (AlmostEqualUlps(min, max)) {
        return 2;
    }
    return 1;
}
Example #20
0
int SkIntersections::horizontal(const SkDLine& line, double y) {
    double min = line[0].fY;
    double max = line[1].fY;
    if (min > max) {
        SkTSwap(min, max);
    }
    if (min > y || max < y) {
        return fUsed = 0;
    }
    if (AlmostEqualUlps(min, max)) {
        fT[0][0] = 0;
        fT[0][1] = 1;
        return fUsed = 2;
    }
    fT[0][0] = (y - line[0].fY) / (line[1].fY - line[0].fY);
    return fUsed = 1;
}
Example #21
0
int SkIntersections::vertical(const SkDLine& line, double x) {
    double min = line[0].fX;
    double max = line[1].fX;
    if (min > max) {
        SkTSwap(min, max);
    }
    if (!precisely_between(min, x, max)) {
        return fUsed = 0;
    }
    if (AlmostEqualUlps(min, max)) {
        fT[0][0] = 0;
        fT[0][1] = 1;
        return fUsed = 2;
    }
    fT[0][0] = (x - line[0].fX) / (line[1].fX - line[0].fX);
    return fUsed = 1;
}
Example #22
0
int SkIntersections::intersectRay(const SkDLine& a, const SkDLine& b) {
    fMax = 2;
    SkDVector aLen = a[1] - a[0];
    SkDVector bLen = b[1] - b[0];
    /* Slopes match when denom goes to zero:
                      axLen / ayLen ==                   bxLen / byLen
    (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
             byLen  * axLen         ==  ayLen          * bxLen
             byLen  * axLen         -   ayLen          * bxLen == 0 ( == denom )
     */
    double denom = bLen.fY * aLen.fX - aLen.fY * bLen.fX;
    SkDVector ab0 = a[0] - b[0];
    double numerA = ab0.fY * bLen.fX - bLen.fY * ab0.fX;
    double numerB = ab0.fY * aLen.fX - aLen.fY * ab0.fX;
#if 0
    if (!between(0, numerA, denom) || !between(0, numerB, denom)) {
        fUsed = 0;
        return 0;
    }
#endif
    numerA /= denom;
    numerB /= denom;
    int used;
    if (!approximately_zero(denom)) {
        fT[0][0] = numerA;
        fT[1][0] = numerB;
        used = 1;
    } else {
       /* See if the axis intercepts match:
                  ay - ax * ayLen / axLen  ==          by - bx * ayLen / axLen
         axLen * (ay - ax * ayLen / axLen) == axLen * (by - bx * ayLen / axLen)
         axLen *  ay - ax * ayLen          == axLen *  by - bx * ayLen
        */
        if (!AlmostEqualUlps(aLen.fX * a[0].fY - aLen.fY * a[0].fX,
                aLen.fX * b[0].fY - aLen.fY * b[0].fX)) {
            return fUsed = 0;
        }
        // there's no great answer for intersection points for coincident rays, but return something
        fT[0][0] = fT[1][0] = 0;
        fT[1][0] = fT[1][1] = 1;
        used = 2;
    }
    computePoints(a, used);
    return fUsed;
}
Example #23
0
/*      y<0 y==0 y>0  x<0 x==0 x>0 xy<0 xy==0 xy>0
    0    x                      x               x
    1    x                      x          x
    2    x                      x    x
    3    x                  x        x
    4    x             x             x
    5    x             x                   x
    6    x             x                        x
    7         x        x                        x
    8             x    x                        x
    9             x    x                   x
    10            x    x             x
    11            x         x        x
    12            x             x    x
    13            x             x          x
    14            x             x               x
    15        x                 x               x
*/
int SkOpAngle::findSector(SkPath::Verb verb, double x, double y) const {
    double absX = fabs(x);
    double absY = fabs(y);
    double xy = SkPath::kLine_Verb == verb || !AlmostEqualUlps(absX, absY) ? absX - absY : 0;
    // If there are four quadrants and eight octants, and since the Latin for sixteen is sedecim,
    // one could coin the term sedecimant for a space divided into 16 sections.
   // http://english.stackexchange.com/questions/133688/word-for-something-partitioned-into-16-parts
    static const int sedecimant[3][3][3] = {
    //       y<0           y==0           y>0
    //   x<0 x==0 x>0  x<0 x==0 x>0  x<0 x==0 x>0
        {{ 4,  3,  2}, { 7, -1, 15}, {10, 11, 12}},  // abs(x) <  abs(y)
        {{ 5, -1,  1}, {-1, -1, -1}, { 9, -1, 13}},  // abs(x) == abs(y)
        {{ 6,  3,  0}, { 7, -1, 15}, { 8, 11, 14}},  // abs(x) >  abs(y)
    };
    int sector = sedecimant[(xy >= 0) + (xy > 0)][(y >= 0) + (y > 0)][(x >= 0) + (x > 0)] * 2 + 1;
    SkASSERT(SkPath::kLine_Verb == verb || sector >= 0);
    return sector;
}
Example #24
0
// given a line, see if the opposite curve's convex hull is all on one side
// returns -1=not on one side    0=this CW of test   1=this CCW of test
int SkOpAngle::allOnOneSide(const SkOpAngle& test) const {
    SkASSERT(!fIsCurve);
    SkASSERT(test.fIsCurve);
    const SkDPoint& origin = test.fCurvePart[0];
    SkVector line;
    if (fSegment->verb() == SkPath::kLine_Verb) {
        const SkPoint* linePts = fSegment->pts();
        int lineStart = fStart < fEnd ? 0 : 1;
        line = linePts[lineStart ^ 1] - linePts[lineStart];
    } else {
        SkPoint shortPts[2] = { fCurvePart[0].asSkPoint(), fCurvePart[1].asSkPoint() };
        line = shortPts[1] - shortPts[0];
    }
    float crosses[3];
    SkPath::Verb testVerb = test.fSegment->verb();
    int iMax = SkPathOpsVerbToPoints(testVerb);
//    SkASSERT(origin == test.fCurveHalf[0]);
    const SkDCubic& testCurve = test.fCurvePart;
//    do {
        for (int index = 1; index <= iMax; ++index) {
            float xy1 = (float) (line.fX * (testCurve[index].fY - origin.fY));
            float xy2 = (float) (line.fY * (testCurve[index].fX - origin.fX));
            crosses[index - 1] = AlmostEqualUlps(xy1, xy2) ? 0 : xy1 - xy2;
        }
        if (crosses[0] * crosses[1] < 0) {
            return -1;
        }
        if (SkPath::kCubic_Verb == testVerb) {
            if (crosses[0] * crosses[2] < 0 || crosses[1] * crosses[2] < 0) {
                return -1;
            }
        }
        if (crosses[0]) {
            return crosses[0] < 0;
        }
        if (crosses[1]) {
            return crosses[1] < 0;
        }
        if (SkPath::kCubic_Verb == testVerb && crosses[2]) {
            return crosses[2] < 0;
        }
    fUnorderable = true;
    return -1;
}
static bool checkEndPoint(double x, double y, const SkDLine& l, double* tPtr, int useX) {
    if (!between(l[0].fX, x, l[1].fX) || !between(l[0].fY, y, l[1].fY)) {
        return false;
    }
    double xLen = l[1].fX - l[0].fX;
    double yLen = l[1].fY - l[0].fY;
    if (useX < 0) {
        useX = SkTAbs(xLen) > SkTAbs(yLen);
    }
    // OPTIMIZATION: do between test before divide
    double t = useX ? (x - l[0].fX) / xLen : (y - l[0].fY) / yLen;
    if (!between(0, t, 1)) {
        return false;
    }
    double opp = useX ? (1 - t) * l[0].fY + t * l[1].fY : (1 - t) * l[0].fX + t * l[1].fX;
    if (!AlmostEqualUlps(opp, useX ? y : x)) {
        return false;
    }
    *tPtr = t;
    return true;
}
int SkIntersections::intersectRay(const SkDLine& a, const SkDLine& b) {
    double axLen = a[1].fX - a[0].fX;
    double ayLen = a[1].fY - a[0].fY;
    double bxLen = b[1].fX - b[0].fX;
    double byLen = b[1].fY - b[0].fY;
    /* Slopes match when denom goes to zero:
                      axLen / ayLen ==                   bxLen / byLen
    (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
             byLen  * axLen         ==  ayLen          * bxLen
             byLen  * axLen         -   ayLen          * bxLen == 0 ( == denom )
     */
    double denom = byLen * axLen - ayLen * bxLen;
    double ab0y = a[0].fY - b[0].fY;
    double ab0x = a[0].fX - b[0].fX;
    double numerA = ab0y * bxLen - byLen * ab0x;
    double numerB = ab0y * axLen - ayLen * ab0x;
    numerA /= denom;
    numerB /= denom;
    int used;
    if (!approximately_zero(denom)) {
        fT[0][0] = numerA;
        fT[1][0] = numerB;
        used = 1;
    } else {
       /* See if the axis intercepts match:
                  ay - ax * ayLen / axLen  ==          by - bx * ayLen / axLen
         axLen * (ay - ax * ayLen / axLen) == axLen * (by - bx * ayLen / axLen)
         axLen *  ay - ax * ayLen          == axLen *  by - bx * ayLen
        */
        if (!AlmostEqualUlps(axLen * a[0].fY - ayLen * a[0].fX,
                axLen * b[0].fY - ayLen * b[0].fX)) {
            return fUsed = 0;
        }
        // there's no great answer for intersection points for coincident rays, but return something
        fT[0][0] = fT[1][0] = 0;
        fT[1][0] = fT[1][1] = 1;
        used = 2;
    }
    return computePoints(a, used);
}
Example #27
0
double SkDLine::NearPointV(const SkDPoint& xy, double top, double bottom, double x) {
    if (!AlmostBequalUlps(xy.fX, x)) {
        return -1;
    }
    if (!AlmostBetweenUlps(top, xy.fY, bottom)) {
        return -1;
    }
    double t = (xy.fY - top) / (bottom - top);
    t = SkPinT(t);
    SkASSERT(between(0, t, 1));
    double realPtY = (1 - t) * top + t * bottom;
    SkDVector distU = {xy.fX - x, xy.fY - realPtY};
    double distSq = distU.fX * distU.fX + distU.fY * distU.fY;
    double dist = sqrt(distSq); // OPTIMIZATION: can we compare against distSq instead ?
    double tiniest = SkTMin(SkTMin(x, top), bottom);
    double largest = SkTMax(SkTMax(x, top), bottom);
    largest = SkTMax(largest, -tiniest);
    if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance?
        return -1;
    }
    return t;
}
Example #28
0
double SkDLine::NearPointH(const SkDPoint& xy, double left, double right, double y) {
    if (!AlmostBequalUlps(xy.fY, y)) {
        return -1;
    }
    if (!AlmostBetweenUlps(left, xy.fX, right)) {
        return -1;
    }
    double t = (xy.fX - left) / (right - left);
    t = SkPinT(t);
    SkASSERT(between(0, t, 1));
    double realPtX = (1 - t) * left + t * right;
    SkDVector distU = {xy.fY - y, xy.fX - realPtX};
    double distSq = distU.fX * distU.fX + distU.fY * distU.fY;
    double dist = sqrt(distSq); // OPTIMIZATION: can we compare against distSq instead ?
    double tiniest = SkTMin(SkTMin(y, left), right);
    double largest = SkTMax(SkTMax(y, left), right);
    largest = SkTMax(largest, -tiniest);
    if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance?
        return -1;
    }
    return t;
}
Example #29
0
int quarticRootsReal(int firstCubicRoot, const double A, const double B, const double C,
        const double D, const double E, double s[4]) {
    double  u, v;
    /* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */
    const double invA = 1 / A;
    const double a = B * invA;
    const double b = C * invA;
    const double c = D * invA;
    const double d = E * invA;
    /*  substitute x = y - a/4 to eliminate cubic term:
    x^4 + px^2 + qx + r = 0 */
    const double a2 = a * a;
    const double p = -3 * a2 / 8 + b;
    const double q = a2 * a / 8 - a * b / 2 + c;
    const double r = -3 * a2 * a2 / 256 + a2 * b / 16 - a * c / 4 + d;
    int num;
    if (approximately_zero(r)) {
    /* no absolute term: y(y^3 + py + q) = 0 */
        num = cubicRootsReal(1, 0, p, q, s);
        s[num++] = 0;
    } else {
        /* solve the resolvent cubic ... */
        double cubicRoots[3];
        int roots = cubicRootsReal(1, -p / 2, -r, r * p / 2 - q * q / 8, cubicRoots);
        int index;
    #if 0 && SK_DEBUG // enable to verify that any cubic root is as good as any other
        double tries[3][4];
        int nums[3];
        for (index = 0; index < roots; ++index) {
            /* ... and take one real solution ... */
            const double z = cubicRoots[index];
            /* ... to build two quadric equations */
            u = z * z - r;
            v = 2 * z - p;
            if (approximately_zero_squared(u)) {
                u = 0;
            } else if (u > 0) {
                u = sqrt(u);
            } else {
                SkDebugf("%s u=%1.9g <0\n", __FUNCTION__, u);
                continue;
            }
            if (approximately_zero_squared(v)) {
                v = 0;
            } else if (v > 0) {
                v = sqrt(v);
            } else {
                SkDebugf("%s v=%1.9g <0\n", __FUNCTION__, v);
                continue;
            }
            nums[index] = quadraticRootsReal(1, q < 0 ? -v : v, z - u, tries[index]);
            nums[index] += quadraticRootsReal(1, q < 0 ? v : -v, z + u, tries[index] + nums[index]);
            /* resubstitute */
            const double sub = a / 4;
            for (int i = 0; i < nums[index]; ++i) {
                tries[index][i] -= sub;
            }
        }
        for (index = 0; index < roots; ++index) {
            SkDebugf("%s", __FUNCTION__);
            for (int idx2 = 0; idx2 < nums[index]; ++idx2) {
                SkDebugf(" %1.9g", tries[index][idx2]);
            }
            SkDebugf("\n");
        }
    #endif
        /* ... and take one real solution ... */
        double z;
        num = 0;
        int num2 = 0;
        for (index = firstCubicRoot; index < roots; ++index) {
            z = cubicRoots[index];
            /* ... to build two quadric equations */
            u = z * z - r;
            v = 2 * z - p;
            if (approximately_zero_squared(u)) {
                u = 0;
            } else if (u > 0) {
                u = sqrt(u);
            } else {
                continue;
            }
            if (approximately_zero_squared(v)) {
                v = 0;
            } else if (v > 0) {
                v = sqrt(v);
            } else {
                continue;
            }
            num = quadraticRootsReal(1, q < 0 ? -v : v, z - u, s);
            num2 = quadraticRootsReal(1, q < 0 ? v : -v, z + u, s + num);
            if (!((num | num2) & 1)) {
                break; // prefer solutions without single quad roots
            }
        }
        num += num2;
        if (!num) {
            return 0; // no valid cubic root
        }
    }
    /* resubstitute */
    const double sub = a / 4;
    for (int i = 0; i < num; ++i) {
        s[i] -= sub;
    }
    // eliminate duplicates
    for (int i = 0; i < num - 1; ++i) {
        for (int j = i + 1; j < num; ) {
            if (AlmostEqualUlps(s[i], s[j])) {
                if (j < --num) {
                    s[j] = s[num];
                }
            } else {
                ++j;
            }
        }
    }
    return num;
}
Example #30
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);
}