// 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 Cubic& cubic, Cubic& reduction, ReduceOrder_Quadratics allowQuadratics,
        ReduceOrder_Styles reduceStyle) {
    int index, minX, maxX, minY, maxY;
    int minXSet, minYSet;
    minX = maxX = minY = maxY = 0;
    minXSet = minYSet = 0;
    for (index = 1; index < 4; ++index) {
        if (cubic[minX].x > cubic[index].x) {
            minX = index;
        }
        if (cubic[minY].y > cubic[index].y) {
            minY = index;
        }
        if (cubic[maxX].x < cubic[index].x) {
            maxX = index;
        }
        if (cubic[maxY].y < cubic[index].y) {
            maxY = index;
        }
    }
    for (index = 0; index < 4; ++index) {
        double cx = cubic[index].x;
        double cy = cubic[index].y;
        double denom = SkTMax(fabs(cx), SkTMax(fabs(cy),
                SkTMax(fabs(cubic[minX].x), fabs(cubic[minY].y))));
        if (denom == 0) {
            minXSet |= 1 << index;
            minYSet |= 1 << index;
            continue;
        }
        double inv = 1 / denom;
        if (approximately_equal_half(cx * inv, cubic[minX].x * inv)) {
            minXSet |= 1 << index;
        }
        if (approximately_equal_half(cy * inv, cubic[minY].y * inv)) {
            minYSet |= 1 << index;
        }
    }
    if (minXSet == 0xF) { // test for vertical line
        if (minYSet == 0xF) { // return 1 if all four are coincident
            return coincident_line(cubic, reduction);
        }
        return vertical_line(cubic, reduceStyle, reduction);
    }
    if (minYSet == 0xF) { // test for horizontal line
        return horizontal_line(cubic, reduceStyle, reduction);
    }
    int result = check_linear(cubic, reduceStyle, minX, maxX, minY, maxY, reduction);
    if (result) {
        return result;
    }
    if (allowQuadratics == kReduceOrder_QuadraticsAllowed
            && (result = check_quadratic(cubic, reduction))) {
        return result;
    }
    memcpy(reduction, cubic, sizeof(Cubic));
    return 4;
}
Beispiel #2
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 SkDCubic& cubic, Quadratics allowQuadratics) {
    int index, minX, maxX, minY, maxY;
    int minXSet, minYSet;
    minX = maxX = minY = maxY = 0;
    minXSet = minYSet = 0;
    for (index = 1; index < 4; ++index) {
        if (cubic[minX].fX > cubic[index].fX) {
            minX = index;
        }
        if (cubic[minY].fY > cubic[index].fY) {
            minY = index;
        }
        if (cubic[maxX].fX < cubic[index].fX) {
            maxX = index;
        }
        if (cubic[maxY].fY < cubic[index].fY) {
            maxY = index;
        }
    }
    for (index = 0; index < 4; ++index) {
        double cx = cubic[index].fX;
        double cy = cubic[index].fY;
        double denom = SkTMax(fabs(cx), SkTMax(fabs(cy),
                SkTMax(fabs(cubic[minX].fX), fabs(cubic[minY].fY))));
        if (denom == 0) {
            minXSet |= 1 << index;
            minYSet |= 1 << index;
            continue;
        }
        double inv = 1 / denom;
        if (approximately_equal_half(cx * inv, cubic[minX].fX * inv)) {
            minXSet |= 1 << index;
        }
        if (approximately_equal_half(cy * inv, cubic[minY].fY * inv)) {
            minYSet |= 1 << index;
        }
    }
    if (minXSet == 0xF) {  // test for vertical line
        if (minYSet == 0xF) {  // return 1 if all four are coincident
            return coincident_line(cubic, fCubic);
        }
        return vertical_line(cubic, fCubic);
    }
    if (minYSet == 0xF) {  // test for horizontal line
        return horizontal_line(cubic, fCubic);
    }
    int result = check_linear(cubic, minX, maxX, minY, maxY, fCubic);
    if (result) {
        return result;
    }
    if (allowQuadratics == SkReduceOrder::kAllow_Quadratics
            && (result = check_quadratic(cubic, fCubic))) {
        return result;
    }
    fCubic = cubic;
    return 4;
}
Beispiel #3
0
// give up when changing t no longer moves point
// also, copy point rather than recompute it when it does change
double SkDCubic::binarySearch(double min, double max, double axisIntercept,
        SearchAxis xAxis) const {
    double t = (min + max) / 2;
    double step = (t - min) / 2;
    SkDPoint cubicAtT = ptAtT(t);
    double calcPos = (&cubicAtT.fX)[xAxis];
    double calcDist = calcPos - axisIntercept;
    do {
        double priorT = t - step;
        SkOPASSERT(priorT >= min);
        SkDPoint lessPt = ptAtT(priorT);
        if (approximately_equal_half(lessPt.fX, cubicAtT.fX)
                && approximately_equal_half(lessPt.fY, cubicAtT.fY)) {
            return -1;  // binary search found no point at this axis intercept
        }
        double lessDist = (&lessPt.fX)[xAxis] - axisIntercept;
#if DEBUG_CUBIC_BINARY_SEARCH
        SkDebugf("t=%1.9g calc=%1.9g dist=%1.9g step=%1.9g less=%1.9g\n", t, calcPos, calcDist,
                step, lessDist);
#endif
        double lastStep = step;
        step /= 2;
        if (calcDist > 0 ? calcDist > lessDist : calcDist < lessDist) {
            t = priorT;
        } else {
            double nextT = t + lastStep;
            if (nextT > max) {
                return -1;
            }
            SkDPoint morePt = ptAtT(nextT);
            if (approximately_equal_half(morePt.fX, cubicAtT.fX)
                    && approximately_equal_half(morePt.fY, cubicAtT.fY)) {
                return -1;  // binary search found no point at this axis intercept
            }
            double moreDist = (&morePt.fX)[xAxis] - axisIntercept;
            if (calcDist > 0 ? calcDist <= moreDist : calcDist >= moreDist) {
                continue;
            }
            t = nextT;
        }
        SkDPoint testAtT = ptAtT(t);
        cubicAtT = testAtT;
        calcPos = (&cubicAtT.fX)[xAxis];
        calcDist = calcPos - axisIntercept;
    } while (!approximately_equal(calcPos, axisIntercept));
    return t;
}