aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pathops/SkPathOpsCubic.cpp
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2015-04-23 09:13:37 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-04-23 09:13:37 -0700
commit03b03cad01628146bbb8d4f33c073bd0c77ee558 (patch)
tree3daa35fc7a85abd54f6d48e23d3f8f665b677dc5 /src/pathops/SkPathOpsCubic.cpp
parent4b17fa353e777de309ca8b0706f1d3e326b59822 (diff)
working on initial winding for cubics
Path ops works well for all tests except for cubics. Isolate failures caused by cubics, and do a better job of computing the initial winding for cubics. TBR=reed@google.com BUG=skia:3588 Review URL: https://codereview.chromium.org/1096923003
Diffstat (limited to 'src/pathops/SkPathOpsCubic.cpp')
-rw-r--r--src/pathops/SkPathOpsCubic.cpp90
1 files changed, 83 insertions, 7 deletions
diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
index a44d29bb0f..63f828fb22 100644
--- a/src/pathops/SkPathOpsCubic.cpp
+++ b/src/pathops/SkPathOpsCubic.cpp
@@ -8,6 +8,7 @@
#include "SkLineParameters.h"
#include "SkPathOpsConic.h"
#include "SkPathOpsCubic.h"
+#include "SkPathOpsCurve.h"
#include "SkPathOpsLine.h"
#include "SkPathOpsQuad.h"
#include "SkPathOpsRect.h"
@@ -74,14 +75,66 @@ double SkDCubic::calcPrecision() const {
return (width > height ? width : height) / gPrecisionUnit;
}
-bool SkDCubic::clockwise() const {
- double sum = (fPts[0].fX - fPts[3].fX) * (fPts[0].fY + fPts[3].fY);
- for (int idx = 0; idx < 3; ++idx) {
- sum += (fPts[idx + 1].fX - fPts[idx].fX) * (fPts[idx + 1].fY + fPts[idx].fY);
+bool SkDCubic::clockwise(bool* swap) const {
+ SkDPoint lastPt = fPts[kPointLast];
+ SkDPoint firstPt = fPts[0];
+ double sum = 0;
+ // pick the control point furthest from the line connecting the end points
+ SkLineParameters lineParameters;
+ lineParameters.cubicEndPoints(*this, 0, 3);
+ lineParameters.normalize();
+ double tiniest = SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY),
+ fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
+ double largest = SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY),
+ fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
+ largest = SkTMax(largest, -tiniest);
+ double pt1dist = lineParameters.controlPtDistance(*this, 1);
+ double pt2dist = lineParameters.controlPtDistance(*this, 2);
+#if DEBUG_SWAP_TOP
+ SkDebugf("%s pt1dist=%1.9g pt2dist=%1.9g\n", __FUNCTION__, pt1dist, pt2dist);
+#endif
+ int furthest;
+ if (!approximately_zero_when_compared_to(pt1dist, largest)
+ && !approximately_zero_when_compared_to(pt2dist, largest) && pt1dist * pt2dist < 0) {
+ furthest = 2;
+ } else {
+ furthest = fabs(pt1dist) < fabs(pt2dist) ? 2 : 1;
+ }
+ for (int idx = 1; idx <= 3; ++idx) {
+ sum += (firstPt.fX - lastPt.fX) * (firstPt.fY + lastPt.fY);
+ lastPt = firstPt;
+ firstPt = idx == 1 ? fPts[furthest] : fPts[kPointLast];
}
+ *swap = sum > 0 && !this->monotonicInY();
return sum <= 0;
}
+bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* swap) {
+ SkDCubic cubic;
+ cubic.set(pts);
+#if 0
+ bool flip = startT > endT;
+ double inflectionTs[2];
+ int inflections = cubic.findInflections(inflectionTs);
+ for (int index = 0; index < inflections; ++index) {
+ double inflectionT = inflectionTs[index];
+ if (between(startT, inflectionT, endT)) {
+ if (flip) {
+ if (!roughly_equal(inflectionT, endT)) {
+ startT = inflectionT;
+ }
+ } else {
+ if (!roughly_equal(inflectionT, startT)) {
+ endT = inflectionT;
+ }
+ }
+ }
+ }
+#endif
+ SkDCubic part = cubic.subDivide(startT, endT);
+ return part.clockwise(swap);
+}
+
void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) {
*A = src[6]; // d
*B = src[4] * 3; // 3*c
@@ -186,7 +239,7 @@ bool SkDCubic::isLinear(int startIndex, int endIndex) const {
return approximately_zero_when_compared_to(distance, largest);
}
-bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) {
+bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t, CubicType* resultType) {
SkScalar d[3];
SkCubicType cubicType = SkClassifyCubic(pointsPtr, d);
if (cubicType == kLoop_SkCubicType) {
@@ -203,6 +256,7 @@ bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) {
SkScalar smaller = SkTMax(0.f, SkTMin(ls, ms));
SkScalar larger = SkTMin(1.f, SkTMax(ls, ms));
*t = (smaller + larger) / 2;
+ *resultType = kSplitAtLoop_SkDCubicType;
return *t > 0 && *t < 1;
}
} else if (kSerpentine_SkCubicType == cubicType || kCusp_SkCubicType == cubicType) {
@@ -213,17 +267,36 @@ bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) {
if (infTCount == 2) {
double maxCurvature[3];
int roots = cubic.findMaxCurvature(maxCurvature);
+#if DEBUG_CUBIC_SPLIT
+ SkDebugf("%s\n", __FUNCTION__);
+ cubic.dump();
+ for (int index = 0; index < infTCount; ++index) {
+ SkDebugf("inflectionsTs[%d]=%1.9g ", index, inflectionTs[index]);
+ SkDPoint pt = cubic.ptAtT(inflectionTs[index]);
+ SkDVector dPt = cubic.dxdyAtT(inflectionTs[index]);
+ SkDLine perp = {{pt - dPt, pt + dPt}};
+ perp.dump();
+ }
+ for (int index = 0; index < roots; ++index) {
+ SkDebugf("maxCurvature[%d]=%1.9g ", index, maxCurvature[index]);
+ SkDPoint pt = cubic.ptAtT(maxCurvature[index]);
+ SkDVector dPt = cubic.dxdyAtT(maxCurvature[index]);
+ SkDLine perp = {{pt - dPt, pt + dPt}};
+ perp.dump();
+ }
+#endif
for (int index = 0; index < roots; ++index) {
if (between(inflectionTs[0], maxCurvature[index], inflectionTs[1])) {
*t = maxCurvature[index];
+ *resultType = kSplitAtMaxCurvature_SkDCubicType;
return true;
}
}
} else if (infTCount == 1) {
*t = inflectionTs[0];
+ *resultType = kSplitAtInflection_SkDCubicType;
return *t > 0 && *t < 1;
}
- return false;
}
return false;
}
@@ -446,10 +519,12 @@ int SkDCubic::findMaxCurvature(double tValues[]) const {
return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues);
}
-SkDPoint SkDCubic::top(double startT, double endT) const {
+SkDPoint SkDCubic::top(double startT, double endT, double* topT) const {
SkDCubic sub = subDivide(startT, endT);
SkDPoint topPt = sub[0];
+ *topT = startT;
if (topPt.fY > sub[3].fY || (topPt.fY == sub[3].fY && topPt.fX > sub[3].fX)) {
+ *topT = endT;
topPt = sub[3];
}
double extremeTs[2];
@@ -459,6 +534,7 @@ SkDPoint SkDCubic::top(double startT, double endT) const {
double t = startT + (endT - startT) * extremeTs[index];
SkDPoint mid = ptAtT(t);
if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) {
+ *topT = t;
topPt = mid;
}
}