Index: src/pathops/SkPathOpsCubic.cpp |
diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp |
index a89604f94cafa98ae9617868cf36bf86014151aa..59e829643b612c2061158255a641dd34e610e850 100644 |
--- a/src/pathops/SkPathOpsCubic.cpp |
+++ b/src/pathops/SkPathOpsCubic.cpp |
@@ -12,6 +12,48 @@ |
const int SkDCubic::gPrecisionUnit = 256; // FIXME: test different values in test framework |
+int SkDCubic::AddValidTs(double allRoots[3], int realRoots, double validRoots[3]) { |
+ int valid = SkDQuad::AddValidTs(allRoots, realRoots, validRoots); |
+ if (valid != 1) { |
+ return valid; |
+ } |
+ if (realRoots == 1) { |
+ return valid; |
+ } |
+ return -1; |
+} |
+ |
+double SkDCubic::binarySearch(double step, double t, double axisIntercept, bool yAxis) const { |
+ do { |
+ SkDPoint cubicAtT = ptAtT(t); |
+ double calcDist = yAxis ? cubicAtT.fX : cubicAtT.fY; |
+ if (approximately_equal(calcDist, axisIntercept)) { |
+ break; |
+ } |
+ if (step == 0) { |
+ return -1; // binary search with this step failed |
+ } |
+ calcDist = fabs(calcDist - axisIntercept); |
+ double lastStep = step; |
+ step /= 2; |
+ SkDPoint lessPt = ptAtT(t - lastStep); |
+ double lessDist = fabs((yAxis ? lessPt.fX : lessPt.fY) - axisIntercept); |
+ if (calcDist > lessDist) { |
+ t -= step; |
+ t = SkTMax(0., t); |
+ } else { |
+ SkDPoint morePt = ptAtT(t + lastStep); |
+ double moreDist = fabs((yAxis ? morePt.fX : morePt.fY) - axisIntercept); |
+ if (calcDist <= moreDist) { |
+ continue; |
+ } |
+ t += step; |
+ t = SkTMin(1., t); |
+ } |
+ } while (true); |
+ return t; |
+} |
+ |
// FIXME: cache keep the bounds and/or precision with the caller? |
double SkDCubic::calcPrecision() const { |
SkDRect dRect; |
@@ -93,6 +135,49 @@ bool SkDCubic::monotonicInY() const { |
&& between(fPts[0].fY, fPts[2].fY, fPts[3].fY); |
} |
+void SkDCubic::searchRoots(double allRoots[3], int realRoots, double* tPtr, double axisIntercept, |
+ bool yAxis) const { |
+ double largest = SkTMax(fabs(allRoots[0]), fabs(allRoots[1])); |
+ if (realRoots == 3) { |
+ largest = SkTMax(largest, fabs(allRoots[2])); |
+ } |
+ int largeBits; |
+ if (largest <= 1) { |
+ double smallest = SkTMin(allRoots[0], allRoots[1]); |
+ if (realRoots == 3) { |
+ smallest = SkTMin(smallest, allRoots[2]); |
+ } |
+ SkASSERT(smallest < 0); |
+ SkASSERT(smallest >= -1); |
+ largeBits = 0; |
+ } else { |
+ (void) frexp(largest, &largeBits); |
+ SkASSERT(largeBits >= 0); |
+ SkASSERT(largeBits < 256); |
+ } |
+ double step = 1e-6; |
+ if (largeBits > 21) { |
+ step = 1e-1; |
+ } else if (largeBits > 18) { |
+ step = 1e-2; |
+ } else if (largeBits > 15) { |
+ step = 1e-3; |
+ } else if (largeBits > 12) { |
+ step = 1e-4; |
+ } else if (largeBits > 9) { |
+ step = 1e-5; |
+ } |
+ do { |
+ double newT = binarySearch(step, *tPtr, axisIntercept, yAxis); |
+ if (newT >= 0) { |
+ *tPtr = newT; |
+ return; |
+ } |
+ step *= 1.5; |
+ SkASSERT(step < 1); |
+ } while (true); |
+} |
+ |
bool SkDCubic::serpentine() const { |
#if 0 // FIXME: enabling this fixes cubicOp114 but breaks cubicOp58d and cubicOp53d |
double tValues[2]; |
@@ -118,6 +203,13 @@ bool SkDCubic::serpentine() const { |
static const double PI = 3.141592653589793; |
// from SkGeometry.cpp (and Numeric Solutions, 5.6) |
+int SkDCubic::RootsValidT(double A, double B, double C, double D, double s[3], int* sCount, |
+ double t[3]) { |
+ *sCount = RootsReal(A, B, C, D, s); |
+ int foundRoots = SkDCubic::AddValidTs(s, *sCount, t); |
+ return foundRoots; |
+} |
+ |
int SkDCubic::RootsValidT(double A, double B, double C, double D, double t[3]) { |
double s[3]; |
int realRoots = RootsReal(A, B, C, D, s); |
@@ -180,6 +272,20 @@ int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) { |
double R2 = R * R; |
double Q3 = Q * Q * Q; |
double R2MinusQ3 = R2 - Q3; |
+ double R2Q3Max = SkTMax(R2, fabs(Q3)); |
+ if (R2Q3Max * FLT_EPSILON > fabs(R2MinusQ3)) { |
+#if defined(__clang__) || defined(__GNUC__) |
+ __float128 R2_128 = (__float128) R * (__float128) R; |
+ __float128 Q3_128 = (__float128) Q * (__float128) Q * (__float128) Q; |
+ __float128 R2MinusQ3_128 = R2_128 - Q3_128; |
+ R2MinusQ3 = (double) R2MinusQ3_128; |
+#else |
+ SkFloat128 R2_128 = SkFloat128Mul(R, R); |
+ SkFloat128 Q3_128 = SkFloat128Mul(Q, Q); |
+ Q3_128 = SkFloat128Mul(Q3_128, Q); |
+ R2MinusQ3 = SkFloat128Sub(R2_128, Q3_128); |
+#endif |
+ } |
double adiv3 = a / 3; |
double r; |
double* roots = s; |
@@ -210,7 +316,7 @@ int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) { |
} |
r = A - adiv3; |
*roots++ = r; |
- if (AlmostDequalUlps(R2, Q3)) { |
+ if (AlmostDequalUlps((double) R2, (double) Q3)) { |
r = -A / 2 - adiv3; |
if (!AlmostDequalUlps(s[0], r)) { |
*roots++ = r; |