| Index: src/pathops/SkPathOpsCubic.cpp
|
| diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
|
| index a89604f94cafa98ae9617868cf36bf86014151aa..9d70d58ec15d7a5219637e2eff3f7b869b9f2b59 100644
|
| --- a/src/pathops/SkPathOpsCubic.cpp
|
| +++ b/src/pathops/SkPathOpsCubic.cpp
|
| @@ -9,9 +9,58 @@
|
| #include "SkPathOpsLine.h"
|
| #include "SkPathOpsQuad.h"
|
| #include "SkPathOpsRect.h"
|
| +#include "SkTSort.h"
|
|
|
| const int SkDCubic::gPrecisionUnit = 256; // FIXME: test different values in test framework
|
|
|
| +// give up when changing t no longer moves point
|
| +// also, copy point rather than recompute it when it does change
|
| +double SkDCubic::binarySearch(double min, double max, double axisIntercept,
|
| + SearchAxis xAxis) const {
|
| + double t = (min + max) / 2;
|
| + double step = (t - min) / 2;
|
| + SkDPoint cubicAtT = ptAtT(t);
|
| + double calcPos = (&cubicAtT.fX)[xAxis];
|
| + double calcDist = calcPos - axisIntercept;
|
| + do {
|
| + double priorT = t - step;
|
| + SkASSERT(priorT >= min);
|
| + SkDPoint lessPt = ptAtT(priorT);
|
| + if (approximately_equal(lessPt.fX, cubicAtT.fX)
|
| + && approximately_equal(lessPt.fY, cubicAtT.fY)) {
|
| + return -1; // binary search found no point at this axis intercept
|
| + }
|
| + double lessDist = (&lessPt.fX)[xAxis] - axisIntercept;
|
| +#if DEBUG_CUBIC_BINARY_SEARCH
|
| + SkDebugf("t=%1.9g calc=%1.9g dist=%1.9g step=%1.9g less=%1.9g\n", t, calcPos, calcDist,
|
| + step, lessDist);
|
| +#endif
|
| + double lastStep = step;
|
| + step /= 2;
|
| + if (calcDist > 0 ? calcDist > lessDist : calcDist < lessDist) {
|
| + t = priorT;
|
| + } else {
|
| + double nextT = t + lastStep;
|
| + SkASSERT(nextT <= max);
|
| + SkDPoint morePt = ptAtT(nextT);
|
| + if (approximately_equal(morePt.fX, cubicAtT.fX)
|
| + && approximately_equal(morePt.fY, cubicAtT.fY)) {
|
| + return -1; // binary search found no point at this axis intercept
|
| + }
|
| + double moreDist = (&morePt.fX)[xAxis] - axisIntercept;
|
| + if (calcDist > 0 ? calcDist <= moreDist : calcDist >= moreDist) {
|
| + continue;
|
| + }
|
| + t = nextT;
|
| + }
|
| + SkDPoint testAtT = ptAtT(t);
|
| + cubicAtT = testAtT;
|
| + calcPos = (&cubicAtT.fX)[xAxis];
|
| + calcDist = calcPos - axisIntercept;
|
| + } while (!approximately_equal(calcPos, axisIntercept));
|
| + return t;
|
| +}
|
| +
|
| // FIXME: cache keep the bounds and/or precision with the caller?
|
| double SkDCubic::calcPrecision() const {
|
| SkDRect dRect;
|
| @@ -93,6 +142,27 @@ bool SkDCubic::monotonicInY() const {
|
| && between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
|
| }
|
|
|
| +int SkDCubic::searchRoots(double extremeTs[6], int extrema, double axisIntercept,
|
| + SearchAxis xAxis, double* validRoots) const {
|
| + extrema += findInflections(&extremeTs[extrema]);
|
| + extremeTs[extrema++] = 0;
|
| + extremeTs[extrema] = 1;
|
| + SkTQSort(extremeTs, extremeTs + extrema);
|
| + int validCount = 0;
|
| + for (int index = 0; index < extrema; ) {
|
| + double min = extremeTs[index];
|
| + double max = extremeTs[++index];
|
| + if (min == max) {
|
| + continue;
|
| + }
|
| + double newT = binarySearch(min, max, axisIntercept, xAxis);
|
| + if (newT >= 0) {
|
| + validRoots[validCount++] = newT;
|
| + }
|
| + }
|
| + return validCount;
|
| +}
|
| +
|
| bool SkDCubic::serpentine() const {
|
| #if 0 // FIXME: enabling this fixes cubicOp114 but breaks cubicOp58d and cubicOp53d
|
| double tValues[2];
|
| @@ -210,7 +280,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;
|
|
|