// 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; }
// 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; }
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); }
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; }
// 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 }
/* 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; }
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; }
// 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; }
/* 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); }
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; }
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); }
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; }
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; }
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); }