// 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;
}
Exemple #2
0
// unlike quadraticRoots in QuadraticUtilities.cpp, this does not discard
// real roots <= 0 or >= 1
static int quadraticRootsX(const double A, const double B, const double C,
        double s[2]) {
    if (approximately_zero(A)) {
        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 p = B / (2 * A);
    const double q = C / A;
    const double D = p * p - q;
    if (D < 0) {
        return 0;
    }
    double sqrt_D = sqrt(D);
    if (approximately_less_than_zero(sqrt_D)) {
        s[0] = -p;
        return 1;
    }
    s[0] = sqrt_D - p;
    s[1] = -sqrt_D - p;
    return 2;
}
int SkReducedQuarticRoots(const double t4, const double t3, const double t2, const double t1,
        const double t0, const bool oneHint, double roots[4]) {
#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];
    sk_bzero(str, sizeof(str));
    SK_SNPRINTF(str, sizeof(str),
            "Solve[%1.19g x^4 + %1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]",
            t4, t3, t2, t1, t0);
    SkPathOpsDebug::MathematicaIze(str, sizeof(str));
#if ONE_OFF_DEBUG && ONE_OFF_DEBUG_MATHEMATICA
    SkDebugf("%s\n", str);
#endif
#endif
    if (approximately_zero_when_compared_to(t4, t0)  // 0 is one root
            && approximately_zero_when_compared_to(t4, t1)
            && approximately_zero_when_compared_to(t4, t2)) {
        if (approximately_zero_when_compared_to(t3, t0)
            && approximately_zero_when_compared_to(t3, t1)
            && approximately_zero_when_compared_to(t3, t2)) {
            return SkDQuad::RootsReal(t2, t1, t0, roots);
        }
        if (approximately_zero_when_compared_to(t4, t3)) {
            return SkDCubic::RootsReal(t3, t2, t1, t0, roots);
        }
    }
    if ((approximately_zero_when_compared_to(t0, t1) || approximately_zero(t1))  // 0 is one root
      //      && approximately_zero_when_compared_to(t0, t2)
            && approximately_zero_when_compared_to(t0, t3)
            && approximately_zero_when_compared_to(t0, t4)) {
        int num = SkDCubic::RootsReal(t4, t3, t2, t1, roots);
        for (int i = 0; i < num; ++i) {
            if (approximately_zero(roots[i])) {
                return num;
            }
        }
        roots[num++] = 0;
        return num;
    }
    if (oneHint) {
        SkASSERT(approximately_zero_double(t4 + t3 + t2 + t1 + t0));  // 1 is one root
        // note that -C == A + B + D + E
        int num = SkDCubic::RootsReal(t4, t4 + t3, -(t1 + t0), -t0, roots);
        for (int i = 0; i < num; ++i) {
            if (approximately_equal(roots[i], 1)) {
                return num;
            }
        }
        roots[num++] = 1;
        return num;
    }
    return -1;
}
Exemple #4
0
bool SkDCubic::isLinear(int startIndex, int endIndex) const {
    SkLineParameters lineParameters;
    lineParameters.cubicEndPoints(*this, startIndex, endIndex);
    // FIXME: maybe it's possible to avoid this and compare non-normalized
    lineParameters.normalize();
    double distance = lineParameters.controlPtDistance(*this, 1);
    if (!approximately_zero(distance)) {
        return false;
    }
    distance = lineParameters.controlPtDistance(*this, 2);
    return approximately_zero(distance);
}
Exemple #5
0
double t_at(const _Line& line, const _Point& pt) {
    double dx = line[1].x - line[0].x;
    double dy = line[1].y - line[0].y;
    if (fabs(dx) > fabs(dy)) {
        if (approximately_zero(dx)) {
            return 0;
        }
        return (pt.x - line[0].x) / dx;
    }
    if (approximately_zero(dy)) {
        return 0;
    }
    return (pt.y - line[0].y) / dy;
}
Exemple #6
0
// unlike cubicRoots in CubicUtilities.cpp, this does not discard
// real roots <= 0 or >= 1
static int cubicRootsX(const double A, const double B, const double C,
        const double D, double s[3]) {
    int num;
    /* normal form: x^3 + Ax^2 + Bx + C = 0 */
    const double invA = 1 / A;
    const double a = B * invA;
    const double b = C * invA;
    const double c = D * invA;
    /*  substitute x = y - a/3 to eliminate quadric term:
    x^3 +px + q = 0 */
    const double a2 = a * a;
    const double Q = (-a2 + b * 3) / 9;
    const double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
    /* use Cardano's formula */
    const double Q3 = Q * Q * Q;
    const double R2plusQ3 = R * R + Q3;
    if (approximately_zero(R2plusQ3)) {
        if (approximately_zero(R)) {/* one triple solution */
            s[0] = 0;
            num = 1;
        } else { /* one single and one double solution */

            double u = cube_root(-R);
            s[0] = 2 * u;
            s[1] = -u;
            num = 2;
        }
    }
    else if (R2plusQ3 < 0) { /* Casus irreducibilis: three real solutions */
        const double theta = acos(-R / sqrt(-Q3)) / 3;
        const double _2RootQ = 2 * sqrt(-Q);
        s[0] = _2RootQ * cos(theta);
        s[1] = -_2RootQ * cos(theta + PI / 3);
        s[2] = -_2RootQ * cos(theta - PI / 3);
        num = 3;
    } else { /* one real solution */
        const double sqrt_D = sqrt(R2plusQ3);
        const double u = cube_root(sqrt_D - R);
        const double v = -cube_root(sqrt_D + R);
        s[0] = u + v;
        num = 1;
    }
    /* resubstitute */
    const double sub = a / 3;
    for (int i = 0; i < num; ++i) {
        s[i] -= sub;
    }
    return num;
}
static void coincidentTest() {
    for (size_t testIndex = 0; testIndex < coincidentTestSetCount - 1; testIndex += 2) {
        const Quadratic& quad1 = coincidentTestSet[testIndex];
        const Quadratic& quad2 = coincidentTestSet[testIndex + 1];
        Intersections intersections2;
        intersect2(quad1, quad2, intersections2);
        SkASSERT(intersections2.coincidentUsed() == 2);
        for (int pt = 0; pt < intersections2.coincidentUsed(); ++pt) {
            double tt1 = intersections2.fT[0][pt];
            double tt2 = intersections2.fT[1][pt];
            SkASSERT(approximately_equal(1, tt1) || approximately_zero(tt1));
            SkASSERT(approximately_equal(1, tt2) || approximately_zero(tt2));
        }
    }
}
// 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
}
Exemple #9
0
/* if returning true, check contains true if cubic's hull collapsed, making the cubic linear
   if returning false, check contains true if the the cubic pair have only the end point in common
*/
bool SkDCubic::hullIntersects(const SkDPoint* pts, int ptCount, bool* isLinear) const {
    bool linear = true;
    char hullOrder[4];
    int hullCount = convexHull(hullOrder);
    int end1 = hullOrder[0];
    int hullIndex = 0;
    const SkDPoint* endPt[2];
    endPt[0] = &fPts[end1];
    do {
        hullIndex = (hullIndex + 1) % hullCount;
        int end2 = hullOrder[hullIndex];
        endPt[1] = &fPts[end2];
        double origX = endPt[0]->fX;
        double origY = endPt[0]->fY;
        double adj = endPt[1]->fX - origX;
        double opp = endPt[1]->fY - origY;
        int oddManMask = other_two(end1, end2);
        int oddMan = end1 ^ oddManMask;
        double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX) * opp;
        int oddMan2 = end2 ^ oddManMask;
        double sign2 = (fPts[oddMan2].fY - origY) * adj - (fPts[oddMan2].fX - origX) * opp;
        if (sign * sign2 < 0) {
            continue;
        }
        if (approximately_zero(sign)) {
            sign = sign2;
            if (approximately_zero(sign)) {
                continue;
            }
        }
        linear = false;
        bool foundOutlier = false;
        for (int n = 0; n < ptCount; ++n) {
            double test = (pts[n].fY - origY) * adj - (pts[n].fX - origX) * opp;
            if (test * sign > 0 && !precisely_zero(test)) {
                foundOutlier = true;
                break;
            }
        }
        if (!foundOutlier) {
            return false;
        }
        endPt[0] = endPt[1];
        end1 = end2;
    } while (hullIndex);
    *isLinear = linear;
    return true;
}
Exemple #10
0
bool rotate(const Cubic& cubic, int zero, int index, Cubic& rotPath) {
    double dy = cubic[index].y - cubic[zero].y;
    double dx = cubic[index].x - cubic[zero].x;
    if (approximately_zero(dy)) {
        if (approximately_zero(dx)) {
            return false;
        }
        memcpy(rotPath, cubic, sizeof(Cubic));
        return true;
    }
    for (int index = 0; index < 4; ++index) {
        rotPath[index].x = cubic[index].x * dx + cubic[index].y * dy;
        rotPath[index].y = cubic[index].y * dx - cubic[index].x * dy;
    }
    return true;
}
Exemple #11
0
// from SkGeometry.cpp (and Numeric Solutions, 5.6)
int cubicRootsValidT(double A, double B, double C, double D, double t[3]) {
#if 0
    if (approximately_zero(A)) {  // we're just a quadratic
        return quadraticRootsValidT(B, C, D, t);
    }
    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* roots = t;
    double r;

    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;
        if (is_unit_interval(r))
            *roots++ = r;

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

        r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
        if (is_unit_interval(r))
            *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;
        if (is_unit_interval(r))
            *roots++ = r;
    }
    return (int)(roots - t);
#else
    double s[3];
    int realRoots = cubicRootsReal(A, B, C, D, s);
    int foundRoots = add_valid_ts(s, realRoots, t);
    return foundRoots;
#endif
}
static double 
r(double n, double omega) {
	if (approximately_zero(omega))
		return  n + 1;
	else
		return sin(omega*(n + 1)/2)/sin(omega/2);
}
 // see parallel routine in line quadratic intersections
 int intersectRay(double roots[3]) {
     double adj = fLine[1].fX - fLine[0].fX;
     double opp = fLine[1].fY - fLine[0].fY;
     SkDCubic c;
     SkDEBUGCODE(c.fDebugGlobalState = fIntersections->globalState());
     for (int n = 0; n < 4; ++n) {
         c[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine[0].fX) * opp;
     }
     double A, B, C, D;
     SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D);
     int count = SkDCubic::RootsValidT(A, B, C, D, roots);
     for (int index = 0; index < count; ++index) {
         SkDPoint calcPt = c.ptAtT(roots[index]);
         if (!approximately_zero(calcPt.fX)) {
             for (int n = 0; n < 4; ++n) {
                 c[n].fY = (fCubic[n].fY - fLine[0].fY) * opp
                         + (fCubic[n].fX - fLine[0].fX) * adj;
             }
             double extremeTs[6];
             int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs);
             count = c.searchRoots(extremeTs, extrema, 0, SkDCubic::kXAxis, roots);
             break;
         }
     }
     return count;
 }
/* if returning true, check contains true if quad's hull collapsed, making the cubic linear
   if returning false, check contains true if the the quad pair have only the end point in common
*/
bool SkDQuad::hullIntersects(const SkDQuad& q2, bool* isLinear) const {
    bool linear = true;
    for (int oddMan = 0; oddMan < kPointCount; ++oddMan) {
        const SkDPoint* endPt[2];
        this->otherPts(oddMan, endPt);
        double origX = endPt[0]->fX;
        double origY = endPt[0]->fY;
        double adj = endPt[1]->fX - origX;
        double opp = endPt[1]->fY - origY;
        double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX) * opp;
        if (approximately_zero(sign)) {
            continue;
        }
        linear = false;
        bool foundOutlier = false;
        for (int n = 0; n < kPointCount; ++n) {
            double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
            if (test * sign > 0 && !precisely_zero(test)) {
                foundOutlier = true;
                break;
            }
        }
        if (!foundOutlier) {
            return false;
        }
    }
    *isLinear = linear;
    return true;
}
static bool only_end_pts_in_common(const SkDQuad& q1, const SkDQuad& q2) {
// the idea here is to see at minimum do a quick reject by rotating all points
// to either side of the line formed by connecting the endpoints
// if the opposite curves points are on the line or on the other side, the
// curves at most intersect at the endpoints
    for (int oddMan = 0; oddMan < 3; ++oddMan) {
        const SkDPoint* endPt[2];
        for (int opp = 1; opp < 3; ++opp) {
            int end = oddMan ^ opp;  // choose a value not equal to oddMan
            if (3 == end) {  // and correct so that largest value is 1 or 2
                end = opp;
            }
            endPt[opp - 1] = &q1[end];
        }
        double origX = endPt[0]->fX;
        double origY = endPt[0]->fY;
        double adj = endPt[1]->fX - origX;
        double opp = endPt[1]->fY - origY;
        double sign = (q1[oddMan].fY - origY) * adj - (q1[oddMan].fX - origX) * opp;
        if (approximately_zero(sign)) {
            goto tryNextHalfPlane;
        }
        for (int n = 0; n < 3; ++n) {
            double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
            if (test * sign > 0 && !precisely_zero(test)) {
                goto tryNextHalfPlane;
            }
        }
        return true;
tryNextHalfPlane:
        ;
    }
    return false;
}
Exemple #16
0
 /* Given a pair of quadratics, determine their parametric coefficients.
  * If the scaled coefficients are nearly equal, then the part of the quadratics
  * may be coincident.
  * OPTIMIZATION -- since comparison short-circuits on no match,
  * lazily compute the coefficients, comparing the easiest to compute first.
  * xx and yy first; then xy; and so on.
  */
bool SkDQuadImplicit::match(const SkDQuadImplicit& p2) const {
    int first = 0;
    for (int index = 0; index <= kC_Coeff; ++index) {
        if (approximately_zero(fP[index]) && approximately_zero(p2.fP[index])) {
            first += first == index;
            continue;
        }
        if (first == index) {
            continue;
        }
        if (!AlmostDequalUlps(fP[index] * p2.fP[first], fP[first] * p2.fP[index])) {
            return false;
        }
    }
    return true;
}
bool isLinear(const Quadratic& quad, int startIndex, int endIndex) {
    LineParameters lineParameters;
    lineParameters.quadEndPoints(quad, startIndex, endIndex);
    // FIXME: maybe it's possible to avoid this and compare non-normalized
    lineParameters.normalize();
    double distance = lineParameters.controlPtDistance(quad);
    return approximately_zero(distance);
}
Exemple #18
0
bool SkOpAngle::orderable(const SkOpAngle& rh) const {
    int result;
    if (!fIsCurve) {
        if (!rh.fIsCurve) {
            double leftX = fTangentHalf.dx();
            double leftY = fTangentHalf.dy();
            double rightX = rh.fTangentHalf.dx();
            double rightY = rh.fTangentHalf.dy();
            double x_ry = leftX * rightY;
            double rx_y = rightX * leftY;
            if (x_ry == rx_y) {
                if (leftX * rightX < 0 || leftY * rightY < 0) {
                    return true;  // exactly 180 degrees apart
                }
                goto unorderable;
            }
            SkASSERT(x_ry != rx_y); // indicates an undetected coincidence -- worth finding earlier
            return x_ry < rx_y;
        }
        if ((result = allOnOneSide(rh)) >= 0) {
            return result;
        }
        if (fUnorderable || approximately_zero(rh.fSide)) {
            goto unorderable;
        }
    } else if (!rh.fIsCurve) {
        if ((result = rh.allOnOneSide(*this)) >= 0) {
            return !result;
        }
        if (rh.fUnorderable || approximately_zero(fSide)) {
            goto unorderable;
        }
    }
    if ((result = convexHullOverlaps(rh)) >= 0) {
        return result;
    }
    return endsIntersect(rh);
unorderable:
    fUnorderable = true;
    rh.fUnorderable = true;
    return true;
}
// note that this only works if both lines are neither horizontal nor vertical
int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
    // see if end points intersect the opposite line
    double t;
    for (int iA = 0; iA < 2; ++iA) {
        if (!checkEndPoint(a[iA].fX, a[iA].fY, b, &t, -1)) {
            continue;
        }
        insert(iA, t, a[iA]);
    }
    for (int iB = 0; iB < 2; ++iB) {
        if (!checkEndPoint(b[iB].fX, b[iB].fY, a, &t, -1)) {
            continue;
        }
        insert(t, iB, b[iB]);
    }
    if (used() > 0) {
        SkASSERT(fUsed <= 2);
        return used(); // coincident lines are returned here
    }
    /* Determine the intersection point of two line segments
       Return FALSE if the lines don't intersect
       from: http://paulbourke.net/geometry/lineline2d/ */
    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;
    bool mayNotOverlap = (numerA < 0 && denom > numerA) || (numerA > 0 && denom < numerA)
            || (numerB < 0 && denom > numerB) || (numerB > 0 && denom < numerB);
    numerA /= denom;
    numerB /= denom;
    if ((!approximately_zero(denom) || (!approximately_zero_inverse(numerA)
            && !approximately_zero_inverse(numerB))) && !sk_double_isnan(numerA)
            && !sk_double_isnan(numerB)) {
        if (mayNotOverlap) {
            return 0;
        }
        fT[0][0] = numerA;
        fT[1][0] = numerB;
        fPt[0] = a.xyAtT(numerA);
        return computePoints(a, 1);
    }
    return 0;
}
 /* Given a pair of quadratics, determine their parametric coefficients.
  * If the scaled coefficients are nearly equal, then the part of the quadratics
  * may be coincident.
  * FIXME: optimization -- since comparison short-circuits on no match,
  * lazily compute the coefficients, comparing the easiest to compute first.
  * xx and yy first; then xy; and so on.
  */
bool implicit_matches(const Quadratic& one, const Quadratic& two) {
    double p1[coeff_count]; // a'xx , b'xy , c'yy , d'x , e'y , f
    double p2[coeff_count];
    implicit_coefficients(one, p1);
    implicit_coefficients(two, p2);
    int first = 0;
    for (int index = 0; index < coeff_count; ++index) {
        if (approximately_zero(p1[index]) || approximately_zero(p2[index])) {
            first += first == index;
            continue;
        }
        if (first == index) {
            continue;
        }
        if (!approximately_equal(p1[index] * p2[first],
                p1[first] * p2[index])) {
            return false;
        }
    }
    return true;
}
Exemple #21
0
static void testOneQuartic(size_t aIndex, size_t bIndex, size_t cIndex, size_t dIndex,
        size_t eIndex) {
    const double A = mulA[aIndex];
    const double B = rootB[bIndex];
    const double C = rootC[cIndex];
    const double D = rootD[dIndex];
    const double E = rootE[eIndex];
    const double b = A * (B + C + D + E);
    const double c = A * (B * C + C * D + B * D + B * E + C * E + D * E);
    const double d = A * (B * C * D + B * C * E + B * D * E + C * D * E);
    const double e = A * B * C * D * E;
    double roots[4];
    bool oneHint = approximately_zero(A + b + c + d + e);
    int rootCount = reducedQuarticRoots(A, b, c, d, e, oneHint, roots);
    if (rootCount < 0) {
        rootCount = quarticRootsReal(0, A, b, c, d, e, roots);
    }
    const int expected = 1 + (B != C) + (B != D && C != D) + (B != E && C != E && D != E);
    SkASSERT(rootCount == expected);
    SkASSERT(AlmostEqualUlps(roots[0], -B)
            || AlmostEqualUlps(roots[0], -C)
            || AlmostEqualUlps(roots[0], -D)
            || AlmostEqualUlps(roots[0], -E));
    if (expected <= 1) {
        return;
    }
    SkASSERT(!AlmostEqualUlps(roots[0], roots[1]));
    SkASSERT(AlmostEqualUlps(roots[1], -B)
            || AlmostEqualUlps(roots[1], -C)
            || AlmostEqualUlps(roots[1], -D)
            || AlmostEqualUlps(roots[1], -E));
    if (expected <= 2) {
        return;
    }
    SkASSERT(!AlmostEqualUlps(roots[0], roots[2])
            && !AlmostEqualUlps(roots[1], roots[2]));
    SkASSERT(AlmostEqualUlps(roots[2], -B)
            || AlmostEqualUlps(roots[2], -C)
            || AlmostEqualUlps(roots[2], -D)
            || AlmostEqualUlps(roots[2], -E));
    if (expected <= 3) {
        return;
    }
    SkASSERT(!AlmostEqualUlps(roots[0], roots[3])
            && !AlmostEqualUlps(roots[1], roots[3])
            && !AlmostEqualUlps(roots[2], roots[3]));
    SkASSERT(AlmostEqualUlps(roots[3], -B)
            || AlmostEqualUlps(roots[3], -C)
            || AlmostEqualUlps(roots[3], -D)
            || AlmostEqualUlps(roots[3], -E));
}
// this does not discard real roots <= 0 or >= 1
int SkDQuad::RootsReal(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 (!AlmostDequalUlps(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;
    return 1 + !AlmostDequalUlps(s[0], s[1]);
}
// See for example, http://www.cs.tut.fi/sgn/arg/music/tuomasv/MScThesis.pdf
double
parabolic_frequency_interpolation(power_t *power, int bin) {
	double p1 = power_t_to_double(power[bin-1]);
	double p2 = power_t_to_double(power[bin]);
	double p3 = power_t_to_double(power[bin+1]);
	if (!p1||!p2||!p3)
		return p2;
	double m1 = log(p1);
	double m2 = log(p2);
	double m3 = log(p3);
//	dp(31, "%g %g %g %g %g %g\n", p1, p2, p3, m1,m2,m3);
	double denominator = m1 - 2*m2 + m3;
	if (approximately_zero(denominator))
		return p2;
	return 0.5*(m1 - m3)/denominator;
}	
double
parabolic_amplitude_interpolation(power_t *power, int bin) {
	double p1 = power_t_to_double(power[bin-1]);
	double p2 = power_t_to_double(power[bin]);
	double p3 = power_t_to_double(power[bin+1]);
	if (!p1||!p2||!p3)
		return p2;
	double m1 = log(p1);
	double m2 = log(p2);
	double m3 = log(p3);
	double denominator = m1 - 2*m2 + m3;
//	dp(0, "%g %g %g %g %g %g %g %g\n",p1,p2,p3,m1,m2,m3,denominator,m2 - 0.125*(m1 - m3)*(m1 - m3)/denominator);
	if (approximately_zero(denominator))
		return p2;
	return exp(m2 - 0.125*(m1 - m3)*(m1 - m3)/denominator);
}	
Exemple #25
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;
}
static bool onlyEndPtsInCommon(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
// the idea here is to see at minimum do a quick reject by rotating all points
// to either side of the line formed by connecting the endpoints
// if the opposite curves points are on the line or on the other side, the
// curves at most intersect at the endpoints
    for (int oddMan = 0; oddMan < 3; ++oddMan) {
        const _Point* endPt[2];
        for (int opp = 1; opp < 3; ++opp) {
            int end = oddMan ^ opp;
            if (end == 3) {
                end = opp;
            }
            endPt[opp - 1] = &q1[end];
        }
        double origX = endPt[0]->x;
        double origY = endPt[0]->y;
        double adj = endPt[1]->x - origX;
        double opp = endPt[1]->y - origY;
        double sign = (q1[oddMan].y - origY) * adj - (q1[oddMan].x - origX) * opp;
        if (approximately_zero(sign)) {
            goto tryNextHalfPlane;
        }
        for (int n = 0; n < 3; ++n) {
            double test = (q2[n].y - origY) * adj - (q2[n].x - origX) * opp;
            if (test * sign > 0) {
                goto tryNextHalfPlane;
            }
        }
        for (int i1 = 0; i1 < 3; i1 += 2) {
            for (int i2 = 0; i2 < 3; i2 += 2) {
                if (q1[i1] == q2[i2]) {
                    i.insert(i1 >> 1, i2 >> 1);
                }
            }
        }
        assert(i.fUsed < 3);
        return true;
tryNextHalfPlane:
        ;
    }
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);
}
static bool only_end_pts_in_common(const SkDCubic& c1, const SkDCubic& c2) {
// the idea here is to see at minimum do a quick reject by rotating all points
// to either side of the line formed by connecting the endpoints
// if the opposite curves points are on the line or on the other side, the
// curves at most intersect at the endpoints
    for (int oddMan = 0; oddMan < 4; ++oddMan) {
        const SkDPoint* endPt[3];
        for (int opp = 1; opp < 4; ++opp) {
            int end = oddMan ^ opp;  // choose a value not equal to oddMan
            endPt[opp - 1] = &c1[end];
        }
        for (int triTest = 0; triTest < 3; ++triTest) {
            double origX = endPt[triTest]->fX;
            double origY = endPt[triTest]->fY;
            int oppTest = triTest + 1;
            if (3 == oppTest) {
                oppTest = 0;
            }
            double adj = endPt[oppTest]->fX - origX;
            double opp = endPt[oppTest]->fY - origY;
            if (adj == 0 && opp == 0) {  // if the other point equals the test point, ignore it
                continue;
            }
            double sign = (c1[oddMan].fY - origY) * adj - (c1[oddMan].fX - origX) * opp;
            if (approximately_zero(sign)) {
                goto tryNextHalfPlane;
            }
            for (int n = 0; n < 4; ++n) {
                double test = (c2[n].fY - origY) * adj - (c2[n].fX - origX) * opp;
                if (test * sign > 0 && !precisely_zero(test)) {
                    goto tryNextHalfPlane;
                }
            }
        }
        return true;
tryNextHalfPlane:
        ;
    }
    return false;
}
Exemple #29
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 #30
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);
}