Exemple #1
0
int quarticRoots(const double A, const double B, const double C, const double D,
        const double E, double s[4]) {
    if (approximately_zero(A)) {
        if (approximately_zero(B)) {
            return quadraticRootsX(C, D, E, s);
        }
        return cubicRootsX(B, C, D, E, s);
    }
    int num;
    int i;
    if (approximately_zero(E)) { // 0 is one root
        num = cubicRootsX(A, B, C, D, s);
        for (i = 0; i < num; ++i) {
            if (approximately_zero(s[i])) {
                return num;
            }
        }
        s[num++] = 0;
        return num;
    }
    if (approximately_zero_squared(A + B + C + D + E)) { // 1 is one root
        num = cubicRootsX(A, A + B, -(D + E), -E, s); // note that -C==A+B+D+E
        for (i = 0; i < num; ++i) {
            if (approximately_equal(s[i], 1)) {
                return num;
            }
        }
        s[num++] = 1;
        return num;
    }
    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;
    if (approximately_zero(r)) {
    /* no absolute term: y(y^3 + py + q) = 0 */
        num = cubicRootsX(1, 0, p, q, s);
        s[num++] = 0;
    } else {
        /* solve the resolvent cubic ... */
        (void) cubicRootsX(1, -p / 2, -r, r * p / 2 - q * q / 8, s);
        /* ... and take the one real solution ... */
        const double z = s[0];
        /* ... to build two quadric equations */
        u = z * z - r;
        v = 2 * z - p;
        if (approximately_zero(u)) {
            u = 0;
        } else if (u > 0) {
            u = sqrt(u);
        } else {
            return 0;
        }
        if (approximately_zero(v)) {
            v = 0;
        } else if (v > 0) {
            v = sqrt(v);
        } else {
            return 0;
        }
        num = quadraticRootsX(1, q < 0 ? -v : v, z - u, s);
        num += quadraticRootsX(1, q < 0 ? v : -v, z + u, s + num);
    }
    // eliminate duplicates
    for (i = 0; i < num - 1; ++i) {
        for (int j = i + 1; j < num; ) {
            if (approximately_equal(s[i], s[j])) {
                if (j < --num) {
                    s[j] = s[num];
                }
            } else {
                ++j;
            }
        }
    }
    /* resubstitute */
    const double sub = a / 4;
    for (i = 0; i < num; ++i) {
        s[i] -= sub;
    }
    return num;
}
Exemple #2
0
static int cubicRootsX(double A, double B, double C, double D, double s[3]) {
    if (approximately_zero(A)) {  // we're just a quadratic
        return quadraticRootsX(B, C, D, s);
    }
    if (approximately_zero(D)) { // 0 is one root
        int num = quadraticRootsX(A, B, C, s);
        for (int i = 0; i < num; ++i) {
            if (approximately_zero(s[i])) {
                return num;
            }
        }
        s[num++] = 0;
        return num;
    }
    if (approximately_zero(A + B + C + D)) { // 1 is one root
        int num = quadraticRootsX(A, A + B, -D, s);
        for (int i = 0; i < num; ++i) {
            if (approximately_equal(s[i], 1)) {
                return num;
            }
        }
        s[num++] = 1;
        return num;
    }
    double a, b, c;
    {
        double invA = 1 / A;
        a = B * invA;
        b = C * invA;
        c = D * invA;
    }
    double a2 = a * a;
    double Q = (a2 - b * 3) / 9;
    double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
    double Q3 = Q * Q * Q;
    double R2MinusQ3 = R * R - Q3;
    double adiv3 = a / 3;
    double r;
    double* roots = s;

    if (approximately_zero_squared(R2MinusQ3)) {
        if (approximately_zero(R)) {/* one triple solution */
            *roots++ = -adiv3;
        } else { /* one single and one double solution */

            double u = cube_root(-R);
            *roots++ = 2 * u - adiv3;
            *roots++ = -u - adiv3;
        }
    }
    else if (R2MinusQ3 < 0)   // we have 3 real roots
    {
        double theta = acos(R / sqrt(Q3));
        double neg2RootQ = -2 * sqrt(Q);

        r = neg2RootQ * cos(theta / 3) - adiv3;
        *roots++ = r;

        r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
        *roots++ = r;

        r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
        *roots++ = r;
    }
    else                // we have 1 real root
    {
        double A = fabs(R) + sqrt(R2MinusQ3);
        A = cube_root(A);
        if (R > 0) {
            A = -A;
        }
        if (A != 0) {
            A += Q / A;
        }
        r = A - adiv3;
        *roots++ = r;
    }
    return (int)(roots - s);
}
Exemple #3
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;
}
int cubicRootsReal(double A, double B, double C, double D, double s[3]) {
#ifdef SK_DEBUG
    // create a string mathematica understands
    // GDB set print repe 15 # if repeated digits is a bother
    //     set print elements 400 # if line doesn't fit
    char str[1024];
    bzero(str, sizeof(str));
    sprintf(str, "Solve[%1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]", A, B, C, D);
    mathematica_ize(str, sizeof(str));
#if ONE_OFF_DEBUG && ONE_OFF_DEBUG_MATHEMATICA
    SkDebugf("%s\n", str);
#endif
#endif
    if (approximately_zero(A)
            && approximately_zero_when_compared_to(A, B)
            && approximately_zero_when_compared_to(A, C)
            && approximately_zero_when_compared_to(A, D)) {  // we're just a quadratic
        return quadraticRootsReal(B, C, D, s);
    }
    if (approximately_zero_when_compared_to(D, A)
            && approximately_zero_when_compared_to(D, B)
            && approximately_zero_when_compared_to(D, C)) { // 0 is one root
        int num = quadraticRootsReal(A, B, C, s);
        for (int i = 0; i < num; ++i) {
            if (approximately_zero(s[i])) {
                return num;
            }
        }
        s[num++] = 0;
        return num;
    }
    if (approximately_zero(A + B + C + D)) { // 1 is one root
        int num = quadraticRootsReal(A, A + B, -D, s);
        for (int i = 0; i < num; ++i) {
            if (AlmostEqualUlps(s[i], 1)) {
                return num;
            }
        }
        s[num++] = 1;
        return num;
    }
    double a, b, c;
    {
        double invA = 1 / A;
        a = B * invA;
        b = C * invA;
        c = D * invA;
    }
    double a2 = a * a;
    double Q = (a2 - b * 3) / 9;
    double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
    double R2 = R * R;
    double Q3 = Q * Q * Q;
    double R2MinusQ3 = R2 - Q3;
    double adiv3 = a / 3;
    double r;
    double* roots = s;
#if 0
    if (approximately_zero_squared(R2MinusQ3) && AlmostEqualUlps(R2, Q3)) {
        if (approximately_zero_squared(R)) {/* one triple solution */
            *roots++ = -adiv3;
        } else { /* one single and one double solution */

            double u = cube_root(-R);
            *roots++ = 2 * u - adiv3;
            *roots++ = -u - adiv3;
        }
    }
    else
#endif
    if (R2MinusQ3 < 0)   // we have 3 real roots
    {
        double theta = acos(R / sqrt(Q3));
        double neg2RootQ = -2 * sqrt(Q);

        r = neg2RootQ * cos(theta / 3) - adiv3;
        *roots++ = r;

        r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
        if (!AlmostEqualUlps(s[0], r)) {
            *roots++ = r;
        }
        r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
        if (!AlmostEqualUlps(s[0], r) && (roots - s == 1 || !AlmostEqualUlps(s[1], r))) {
            *roots++ = r;
        }
    }
    else                // we have 1 real root
    {
        double sqrtR2MinusQ3 = sqrt(R2MinusQ3);
        double A = fabs(R) + sqrtR2MinusQ3;
        A = cube_root(A);
        if (R > 0) {
            A = -A;
        }
        if (A != 0) {
            A += Q / A;
        }
        r = A - adiv3;
        *roots++ = r;
        if (AlmostEqualUlps(R2, Q3)) {
            r = -A / 2 - adiv3;
            if (!AlmostEqualUlps(s[0], r)) {
                *roots++ = r;
            }
        }
    }
    return (int)(roots - s);
}
Exemple #5
0
/*(
for quads and cubics, set up a parameterized line (e.g. LineParameters )
for points [0] to [1]. See if point [2] is on that line, or on one side
or the other. If it both quads' end points are on the same side, choose
the shorter tangent. If the tangents are equal, choose the better second
tangent angle

maybe I could set up LineParameters lazily
*/
bool SkOpAngle::operator<(const SkOpAngle& rh) const {
    double y = dy();
    double ry = rh.dy();
    if ((y < 0) ^ (ry < 0)) {  // OPTIMIZATION: better to use y * ry < 0 ?
        return y < 0;
    }
    double x = dx();
    double rx = rh.dx();
    if (y == 0 && ry == 0 && x * rx < 0) {
        return x < rx;
    }
    double x_ry = x * ry;
    double rx_y = rx * y;
    double cmp = x_ry - rx_y;
    if (!approximately_zero(cmp)) {
        return cmp < 0;
    }
    if (approximately_zero(x_ry) && approximately_zero(rx_y)
            && !approximately_zero_squared(cmp)) {
        return cmp < 0;
    }
    // at this point, the initial tangent line is coincident
    // see if edges curl away from each other
    if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
            || !approximately_zero(rh.fSide))) {
        // FIXME: running demo will trigger this assertion
        // (don't know if commenting out will trigger further assertion or not)
        // commenting it out allows demo to run in release, though
        return fSide < rh.fSide;
    }
    // see if either curve can be lengthened and try the tangent compare again
    if (/* cmp && */ (*fSpans)[fEnd].fOther != rh.fSegment  // tangents not absolutely identical
            && (*rh.fSpans)[rh.fEnd].fOther != fSegment) {  // and not intersecting
        SkOpAngle longer = *this;
        SkOpAngle rhLonger = rh;
        if (longer.lengthen() | rhLonger.lengthen()) {
            return longer < rhLonger;
        }
    }
    if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
            || (rh.fVerb == SkPath::kLine_Verb
            && approximately_zero(rx) && approximately_zero(ry))) {
        // See general unsortable comment below. This case can happen when
        // one line has a non-zero change in t but no change in x and y.
        fUnsortable = true;
        rh.fUnsortable = true;
        return this < &rh;  // even with no solution, return a stable sort
    }
    if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny
            || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) {
        fUnsortable = true;
        rh.fUnsortable = true;
        return this < &rh;  // even with no solution, return a stable sort
    }
    SkASSERT(fVerb >= SkPath::kQuad_Verb);
    SkASSERT(rh.fVerb >= SkPath::kQuad_Verb);
    // FIXME: until I can think of something better, project a ray from the
    // end of the shorter tangent to midway between the end points
    // through both curves and use the resulting angle to sort
    // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
    double len = fTangent1.normalSquared();
    double rlen = rh.fTangent1.normalSquared();
    SkDLine ray;
    SkIntersections i, ri;
    int roots, rroots;
    bool flip = false;
    do {
        bool useThis = (len < rlen) ^ flip;
        const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart;
        SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
        ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
            part[2] : part[1];
        ray[1].fX = (part[0].fX + part[partVerb].fX) / 2;
        ray[1].fY = (part[0].fY + part[partVerb].fY) / 2;
        SkASSERT(ray[0] != ray[1]);
        roots = (i.*CurveRay[fVerb])(fPts, ray);
        rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray);
    } while ((roots == 0 || rroots == 0) && (flip ^= true));
    if (roots == 0 || rroots == 0) {
        // FIXME: we don't have a solution in this case. The interim solution
        // is to mark the edges as unsortable, exclude them from this and
        // future computations, and allow the returned path to be fragmented
        fUnsortable = true;
        rh.fUnsortable = true;
        return this < &rh;  // even with no solution, return a stable sort
    }
    SkDPoint loc;
    double best = SK_ScalarInfinity;
    SkDVector dxy;
    double dist;
    int index;
    for (index = 0; index < roots; ++index) {
        loc = (*CurveDPointAtT[fVerb])(fPts, i[0][index]);
        dxy = loc - ray[0];
        dist = dxy.lengthSquared();
        if (best > dist) {
            best = dist;
        }
    }
    for (index = 0; index < rroots; ++index) {
        loc = (*CurveDPointAtT[rh.fVerb])(rh.fPts, ri[0][index]);
        dxy = loc - ray[0];
        dist = dxy.lengthSquared();
        if (best > dist) {
            return fSide < 0;
        }
    }
    return fSide > 0;
}
int SkQuarticRootsReal(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 = SkDCubic::RootsReal(1, 0, p, q, s);
        s[num++] = 0;
    } else {
        /* solve the resolvent cubic ... */
        double cubicRoots[3];
        int roots = SkDCubic::RootsReal(1, -p / 2, -r, r * p / 2 - q * q / 8, cubicRoots);
        int index;
        /* ... 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 = SkDQuad::RootsReal(1, q < 0 ? -v : v, z - u, s);
            num2 = SkDQuad::RootsReal(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 (AlmostDequalUlps(s[i], s[j])) {
                if (j < --num) {
                    s[j] = s[num];
                }
            } else {
                ++j;
            }
        }
    }
    return num;
}