1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2012 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsCubic.h"
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTSort.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkIntersections.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkLineParameters.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsConic.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsQuad.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsRect.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
22*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker struct SkDLine;
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker const int SkDCubic::gPrecisionUnit = 256; // FIXME: test different values in test framework
27*c8dee2aaSAndroid Build Coastguard Worker
align(int endIndex,int ctrlIndex,SkDPoint * dstPt) const28*c8dee2aaSAndroid Build Coastguard Worker void SkDCubic::align(int endIndex, int ctrlIndex, SkDPoint* dstPt) const {
29*c8dee2aaSAndroid Build Coastguard Worker if (fPts[endIndex].fX == fPts[ctrlIndex].fX) {
30*c8dee2aaSAndroid Build Coastguard Worker dstPt->fX = fPts[endIndex].fX;
31*c8dee2aaSAndroid Build Coastguard Worker }
32*c8dee2aaSAndroid Build Coastguard Worker if (fPts[endIndex].fY == fPts[ctrlIndex].fY) {
33*c8dee2aaSAndroid Build Coastguard Worker dstPt->fY = fPts[endIndex].fY;
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker }
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard Worker // give up when changing t no longer moves point
38*c8dee2aaSAndroid Build Coastguard Worker // also, copy point rather than recompute it when it does change
binarySearch(double min,double max,double axisIntercept,SearchAxis xAxis) const39*c8dee2aaSAndroid Build Coastguard Worker double SkDCubic::binarySearch(double min, double max, double axisIntercept,
40*c8dee2aaSAndroid Build Coastguard Worker SearchAxis xAxis) const {
41*c8dee2aaSAndroid Build Coastguard Worker double t = (min + max) / 2;
42*c8dee2aaSAndroid Build Coastguard Worker double step = (t - min) / 2;
43*c8dee2aaSAndroid Build Coastguard Worker SkDPoint cubicAtT = ptAtT(t);
44*c8dee2aaSAndroid Build Coastguard Worker double calcPos = (&cubicAtT.fX)[xAxis];
45*c8dee2aaSAndroid Build Coastguard Worker double calcDist = calcPos - axisIntercept;
46*c8dee2aaSAndroid Build Coastguard Worker do {
47*c8dee2aaSAndroid Build Coastguard Worker double priorT = std::max(min, t - step);
48*c8dee2aaSAndroid Build Coastguard Worker SkDPoint lessPt = ptAtT(priorT);
49*c8dee2aaSAndroid Build Coastguard Worker if (approximately_equal_half(lessPt.fX, cubicAtT.fX)
50*c8dee2aaSAndroid Build Coastguard Worker && approximately_equal_half(lessPt.fY, cubicAtT.fY)) {
51*c8dee2aaSAndroid Build Coastguard Worker return -1; // binary search found no point at this axis intercept
52*c8dee2aaSAndroid Build Coastguard Worker }
53*c8dee2aaSAndroid Build Coastguard Worker double lessDist = (&lessPt.fX)[xAxis] - axisIntercept;
54*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_CUBIC_BINARY_SEARCH
55*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("t=%1.9g calc=%1.9g dist=%1.9g step=%1.9g less=%1.9g\n", t, calcPos, calcDist,
56*c8dee2aaSAndroid Build Coastguard Worker step, lessDist);
57*c8dee2aaSAndroid Build Coastguard Worker #endif
58*c8dee2aaSAndroid Build Coastguard Worker double lastStep = step;
59*c8dee2aaSAndroid Build Coastguard Worker step /= 2;
60*c8dee2aaSAndroid Build Coastguard Worker if (calcDist > 0 ? calcDist > lessDist : calcDist < lessDist) {
61*c8dee2aaSAndroid Build Coastguard Worker t = priorT;
62*c8dee2aaSAndroid Build Coastguard Worker } else {
63*c8dee2aaSAndroid Build Coastguard Worker double nextT = t + lastStep;
64*c8dee2aaSAndroid Build Coastguard Worker if (nextT > max) {
65*c8dee2aaSAndroid Build Coastguard Worker return -1;
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker SkDPoint morePt = ptAtT(nextT);
68*c8dee2aaSAndroid Build Coastguard Worker if (approximately_equal_half(morePt.fX, cubicAtT.fX)
69*c8dee2aaSAndroid Build Coastguard Worker && approximately_equal_half(morePt.fY, cubicAtT.fY)) {
70*c8dee2aaSAndroid Build Coastguard Worker return -1; // binary search found no point at this axis intercept
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker double moreDist = (&morePt.fX)[xAxis] - axisIntercept;
73*c8dee2aaSAndroid Build Coastguard Worker if (calcDist > 0 ? calcDist <= moreDist : calcDist >= moreDist) {
74*c8dee2aaSAndroid Build Coastguard Worker continue;
75*c8dee2aaSAndroid Build Coastguard Worker }
76*c8dee2aaSAndroid Build Coastguard Worker t = nextT;
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker SkDPoint testAtT = ptAtT(t);
79*c8dee2aaSAndroid Build Coastguard Worker cubicAtT = testAtT;
80*c8dee2aaSAndroid Build Coastguard Worker calcPos = (&cubicAtT.fX)[xAxis];
81*c8dee2aaSAndroid Build Coastguard Worker calcDist = calcPos - axisIntercept;
82*c8dee2aaSAndroid Build Coastguard Worker } while (!approximately_equal(calcPos, axisIntercept));
83*c8dee2aaSAndroid Build Coastguard Worker return t;
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker // get the rough scale of the cubic; used to determine if curvature is extreme
calcPrecision() const87*c8dee2aaSAndroid Build Coastguard Worker double SkDCubic::calcPrecision() const {
88*c8dee2aaSAndroid Build Coastguard Worker return ((fPts[1] - fPts[0]).length()
89*c8dee2aaSAndroid Build Coastguard Worker + (fPts[2] - fPts[1]).length()
90*c8dee2aaSAndroid Build Coastguard Worker + (fPts[3] - fPts[2]).length()) / gPrecisionUnit;
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker /* classic one t subdivision */
interp_cubic_coords(const double * src,double * dst,double t)94*c8dee2aaSAndroid Build Coastguard Worker static void interp_cubic_coords(const double* src, double* dst, double t) {
95*c8dee2aaSAndroid Build Coastguard Worker double ab = SkDInterp(src[0], src[2], t);
96*c8dee2aaSAndroid Build Coastguard Worker double bc = SkDInterp(src[2], src[4], t);
97*c8dee2aaSAndroid Build Coastguard Worker double cd = SkDInterp(src[4], src[6], t);
98*c8dee2aaSAndroid Build Coastguard Worker double abc = SkDInterp(ab, bc, t);
99*c8dee2aaSAndroid Build Coastguard Worker double bcd = SkDInterp(bc, cd, t);
100*c8dee2aaSAndroid Build Coastguard Worker double abcd = SkDInterp(abc, bcd, t);
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker dst[0] = src[0];
103*c8dee2aaSAndroid Build Coastguard Worker dst[2] = ab;
104*c8dee2aaSAndroid Build Coastguard Worker dst[4] = abc;
105*c8dee2aaSAndroid Build Coastguard Worker dst[6] = abcd;
106*c8dee2aaSAndroid Build Coastguard Worker dst[8] = bcd;
107*c8dee2aaSAndroid Build Coastguard Worker dst[10] = cd;
108*c8dee2aaSAndroid Build Coastguard Worker dst[12] = src[6];
109*c8dee2aaSAndroid Build Coastguard Worker }
110*c8dee2aaSAndroid Build Coastguard Worker
chopAt(double t) const111*c8dee2aaSAndroid Build Coastguard Worker SkDCubicPair SkDCubic::chopAt(double t) const {
112*c8dee2aaSAndroid Build Coastguard Worker SkDCubicPair dst;
113*c8dee2aaSAndroid Build Coastguard Worker if (t == 0.5) {
114*c8dee2aaSAndroid Build Coastguard Worker dst.pts[0] = fPts[0];
115*c8dee2aaSAndroid Build Coastguard Worker dst.pts[1].fX = (fPts[0].fX + fPts[1].fX) / 2;
116*c8dee2aaSAndroid Build Coastguard Worker dst.pts[1].fY = (fPts[0].fY + fPts[1].fY) / 2;
117*c8dee2aaSAndroid Build Coastguard Worker dst.pts[2].fX = (fPts[0].fX + 2 * fPts[1].fX + fPts[2].fX) / 4;
118*c8dee2aaSAndroid Build Coastguard Worker dst.pts[2].fY = (fPts[0].fY + 2 * fPts[1].fY + fPts[2].fY) / 4;
119*c8dee2aaSAndroid Build Coastguard Worker dst.pts[3].fX = (fPts[0].fX + 3 * (fPts[1].fX + fPts[2].fX) + fPts[3].fX) / 8;
120*c8dee2aaSAndroid Build Coastguard Worker dst.pts[3].fY = (fPts[0].fY + 3 * (fPts[1].fY + fPts[2].fY) + fPts[3].fY) / 8;
121*c8dee2aaSAndroid Build Coastguard Worker dst.pts[4].fX = (fPts[1].fX + 2 * fPts[2].fX + fPts[3].fX) / 4;
122*c8dee2aaSAndroid Build Coastguard Worker dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4;
123*c8dee2aaSAndroid Build Coastguard Worker dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2;
124*c8dee2aaSAndroid Build Coastguard Worker dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2;
125*c8dee2aaSAndroid Build Coastguard Worker dst.pts[6] = fPts[3];
126*c8dee2aaSAndroid Build Coastguard Worker return dst;
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t);
129*c8dee2aaSAndroid Build Coastguard Worker interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t);
130*c8dee2aaSAndroid Build Coastguard Worker return dst;
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker
133*c8dee2aaSAndroid Build Coastguard Worker // TODO(skbug.com/14063) deduplicate this with SkBezierCubic::ConvertToPolynomial
Coefficients(const double * src,double * A,double * B,double * C,double * D)134*c8dee2aaSAndroid Build Coastguard Worker void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) {
135*c8dee2aaSAndroid Build Coastguard Worker *A = src[6]; // d
136*c8dee2aaSAndroid Build Coastguard Worker *B = src[4] * 3; // 3*c
137*c8dee2aaSAndroid Build Coastguard Worker *C = src[2] * 3; // 3*b
138*c8dee2aaSAndroid Build Coastguard Worker *D = src[0]; // a
139*c8dee2aaSAndroid Build Coastguard Worker *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d
140*c8dee2aaSAndroid Build Coastguard Worker *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c
141*c8dee2aaSAndroid Build Coastguard Worker *C -= 3 * *D; // C = -3*a + 3*b
142*c8dee2aaSAndroid Build Coastguard Worker }
143*c8dee2aaSAndroid Build Coastguard Worker
endsAreExtremaInXOrY() const144*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::endsAreExtremaInXOrY() const {
145*c8dee2aaSAndroid Build Coastguard Worker return (between(fPts[0].fX, fPts[1].fX, fPts[3].fX)
146*c8dee2aaSAndroid Build Coastguard Worker && between(fPts[0].fX, fPts[2].fX, fPts[3].fX))
147*c8dee2aaSAndroid Build Coastguard Worker || (between(fPts[0].fY, fPts[1].fY, fPts[3].fY)
148*c8dee2aaSAndroid Build Coastguard Worker && between(fPts[0].fY, fPts[2].fY, fPts[3].fY));
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker // Do a quick reject by rotating all points relative to a line formed by
152*c8dee2aaSAndroid Build Coastguard Worker // a pair of one cubic's points. If the 2nd cubic's points
153*c8dee2aaSAndroid Build Coastguard Worker // are on the line or on the opposite side from the 1st cubic's 'odd man', the
154*c8dee2aaSAndroid Build Coastguard Worker // curves at most intersect at the endpoints.
155*c8dee2aaSAndroid Build Coastguard Worker /* if returning true, check contains true if cubic's hull collapsed, making the cubic linear
156*c8dee2aaSAndroid Build Coastguard Worker if returning false, check contains true if the the cubic pair have only the end point in common
157*c8dee2aaSAndroid Build Coastguard Worker */
hullIntersects(const SkDPoint * pts,int ptCount,bool * isLinear) const158*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::hullIntersects(const SkDPoint* pts, int ptCount, bool* isLinear) const {
159*c8dee2aaSAndroid Build Coastguard Worker bool linear = true;
160*c8dee2aaSAndroid Build Coastguard Worker char hullOrder[4];
161*c8dee2aaSAndroid Build Coastguard Worker int hullCount = convexHull(hullOrder);
162*c8dee2aaSAndroid Build Coastguard Worker int end1 = hullOrder[0];
163*c8dee2aaSAndroid Build Coastguard Worker int hullIndex = 0;
164*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint* endPt[2];
165*c8dee2aaSAndroid Build Coastguard Worker endPt[0] = &fPts[end1];
166*c8dee2aaSAndroid Build Coastguard Worker do {
167*c8dee2aaSAndroid Build Coastguard Worker hullIndex = (hullIndex + 1) % hullCount;
168*c8dee2aaSAndroid Build Coastguard Worker int end2 = hullOrder[hullIndex];
169*c8dee2aaSAndroid Build Coastguard Worker endPt[1] = &fPts[end2];
170*c8dee2aaSAndroid Build Coastguard Worker double origX = endPt[0]->fX;
171*c8dee2aaSAndroid Build Coastguard Worker double origY = endPt[0]->fY;
172*c8dee2aaSAndroid Build Coastguard Worker double adj = endPt[1]->fX - origX;
173*c8dee2aaSAndroid Build Coastguard Worker double opp = endPt[1]->fY - origY;
174*c8dee2aaSAndroid Build Coastguard Worker int oddManMask = other_two(end1, end2);
175*c8dee2aaSAndroid Build Coastguard Worker int oddMan = end1 ^ oddManMask;
176*c8dee2aaSAndroid Build Coastguard Worker double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX) * opp;
177*c8dee2aaSAndroid Build Coastguard Worker int oddMan2 = end2 ^ oddManMask;
178*c8dee2aaSAndroid Build Coastguard Worker double sign2 = (fPts[oddMan2].fY - origY) * adj - (fPts[oddMan2].fX - origX) * opp;
179*c8dee2aaSAndroid Build Coastguard Worker if (sign * sign2 < 0) {
180*c8dee2aaSAndroid Build Coastguard Worker continue;
181*c8dee2aaSAndroid Build Coastguard Worker }
182*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero(sign)) {
183*c8dee2aaSAndroid Build Coastguard Worker sign = sign2;
184*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero(sign)) {
185*c8dee2aaSAndroid Build Coastguard Worker continue;
186*c8dee2aaSAndroid Build Coastguard Worker }
187*c8dee2aaSAndroid Build Coastguard Worker }
188*c8dee2aaSAndroid Build Coastguard Worker linear = false;
189*c8dee2aaSAndroid Build Coastguard Worker bool foundOutlier = false;
190*c8dee2aaSAndroid Build Coastguard Worker for (int n = 0; n < ptCount; ++n) {
191*c8dee2aaSAndroid Build Coastguard Worker double test = (pts[n].fY - origY) * adj - (pts[n].fX - origX) * opp;
192*c8dee2aaSAndroid Build Coastguard Worker if (test * sign > 0 && !precisely_zero(test)) {
193*c8dee2aaSAndroid Build Coastguard Worker foundOutlier = true;
194*c8dee2aaSAndroid Build Coastguard Worker break;
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker if (!foundOutlier) {
198*c8dee2aaSAndroid Build Coastguard Worker return false;
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker endPt[0] = endPt[1];
201*c8dee2aaSAndroid Build Coastguard Worker end1 = end2;
202*c8dee2aaSAndroid Build Coastguard Worker } while (hullIndex);
203*c8dee2aaSAndroid Build Coastguard Worker *isLinear = linear;
204*c8dee2aaSAndroid Build Coastguard Worker return true;
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker
hullIntersects(const SkDCubic & c2,bool * isLinear) const207*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::hullIntersects(const SkDCubic& c2, bool* isLinear) const {
208*c8dee2aaSAndroid Build Coastguard Worker return hullIntersects(c2.fPts, SkDCubic::kPointCount, isLinear);
209*c8dee2aaSAndroid Build Coastguard Worker }
210*c8dee2aaSAndroid Build Coastguard Worker
hullIntersects(const SkDQuad & quad,bool * isLinear) const211*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::hullIntersects(const SkDQuad& quad, bool* isLinear) const {
212*c8dee2aaSAndroid Build Coastguard Worker return hullIntersects(quad.fPts, SkDQuad::kPointCount, isLinear);
213*c8dee2aaSAndroid Build Coastguard Worker }
214*c8dee2aaSAndroid Build Coastguard Worker
hullIntersects(const SkDConic & conic,bool * isLinear) const215*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::hullIntersects(const SkDConic& conic, bool* isLinear) const {
216*c8dee2aaSAndroid Build Coastguard Worker
217*c8dee2aaSAndroid Build Coastguard Worker return hullIntersects(conic.fPts, isLinear);
218*c8dee2aaSAndroid Build Coastguard Worker }
219*c8dee2aaSAndroid Build Coastguard Worker
isLinear(int startIndex,int endIndex) const220*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::isLinear(int startIndex, int endIndex) const {
221*c8dee2aaSAndroid Build Coastguard Worker if (fPts[0].approximatelyDEqual(fPts[3])) {
222*c8dee2aaSAndroid Build Coastguard Worker return ((const SkDQuad *) this)->isLinear(0, 2);
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker SkLineParameters lineParameters;
225*c8dee2aaSAndroid Build Coastguard Worker lineParameters.cubicEndPoints(*this, startIndex, endIndex);
226*c8dee2aaSAndroid Build Coastguard Worker // FIXME: maybe it's possible to avoid this and compare non-normalized
227*c8dee2aaSAndroid Build Coastguard Worker lineParameters.normalize();
228*c8dee2aaSAndroid Build Coastguard Worker double tiniest = std::min(std::min(std::min(std::min(std::min(std::min(std::min(fPts[0].fX, fPts[0].fY),
229*c8dee2aaSAndroid Build Coastguard Worker fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
230*c8dee2aaSAndroid Build Coastguard Worker double largest = std::max(std::max(std::max(std::max(std::max(std::max(std::max(fPts[0].fX, fPts[0].fY),
231*c8dee2aaSAndroid Build Coastguard Worker fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
232*c8dee2aaSAndroid Build Coastguard Worker largest = std::max(largest, -tiniest);
233*c8dee2aaSAndroid Build Coastguard Worker double distance = lineParameters.controlPtDistance(*this, 1);
234*c8dee2aaSAndroid Build Coastguard Worker if (!approximately_zero_when_compared_to(distance, largest)) {
235*c8dee2aaSAndroid Build Coastguard Worker return false;
236*c8dee2aaSAndroid Build Coastguard Worker }
237*c8dee2aaSAndroid Build Coastguard Worker distance = lineParameters.controlPtDistance(*this, 2);
238*c8dee2aaSAndroid Build Coastguard Worker return approximately_zero_when_compared_to(distance, largest);
239*c8dee2aaSAndroid Build Coastguard Worker }
240*c8dee2aaSAndroid Build Coastguard Worker
241*c8dee2aaSAndroid Build Coastguard Worker // from http://www.cs.sunysb.edu/~qin/courses/geometry/4.pdf
242*c8dee2aaSAndroid Build Coastguard Worker // c(t) = a(1-t)^3 + 3bt(1-t)^2 + 3c(1-t)t^2 + dt^3
243*c8dee2aaSAndroid Build Coastguard Worker // c'(t) = -3a(1-t)^2 + 3b((1-t)^2 - 2t(1-t)) + 3c(2t(1-t) - t^2) + 3dt^2
244*c8dee2aaSAndroid Build Coastguard Worker // = 3(b-a)(1-t)^2 + 6(c-b)t(1-t) + 3(d-c)t^2
derivative_at_t(const double * src,double t)245*c8dee2aaSAndroid Build Coastguard Worker static double derivative_at_t(const double* src, double t) {
246*c8dee2aaSAndroid Build Coastguard Worker double one_t = 1 - t;
247*c8dee2aaSAndroid Build Coastguard Worker double a = src[0];
248*c8dee2aaSAndroid Build Coastguard Worker double b = src[2];
249*c8dee2aaSAndroid Build Coastguard Worker double c = src[4];
250*c8dee2aaSAndroid Build Coastguard Worker double d = src[6];
251*c8dee2aaSAndroid Build Coastguard Worker return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker
ComplexBreak(const SkPoint pointsPtr[4],SkScalar * t)254*c8dee2aaSAndroid Build Coastguard Worker int SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) {
255*c8dee2aaSAndroid Build Coastguard Worker SkDCubic cubic;
256*c8dee2aaSAndroid Build Coastguard Worker cubic.set(pointsPtr);
257*c8dee2aaSAndroid Build Coastguard Worker if (cubic.monotonicInX() && cubic.monotonicInY()) {
258*c8dee2aaSAndroid Build Coastguard Worker return 0;
259*c8dee2aaSAndroid Build Coastguard Worker }
260*c8dee2aaSAndroid Build Coastguard Worker double tt[2], ss[2];
261*c8dee2aaSAndroid Build Coastguard Worker SkCubicType cubicType = SkClassifyCubic(pointsPtr, tt, ss);
262*c8dee2aaSAndroid Build Coastguard Worker switch (cubicType) {
263*c8dee2aaSAndroid Build Coastguard Worker case SkCubicType::kLoop: {
264*c8dee2aaSAndroid Build Coastguard Worker const double &td = tt[0], &te = tt[1], &sd = ss[0], &se = ss[1];
265*c8dee2aaSAndroid Build Coastguard Worker if (roughly_between(0, td, sd) && roughly_between(0, te, se)) {
266*c8dee2aaSAndroid Build Coastguard Worker t[0] = static_cast<SkScalar>((td * se + te * sd) / (2 * sd * se));
267*c8dee2aaSAndroid Build Coastguard Worker return (int) (t[0] > 0 && t[0] < 1);
268*c8dee2aaSAndroid Build Coastguard Worker }
269*c8dee2aaSAndroid Build Coastguard Worker }
270*c8dee2aaSAndroid Build Coastguard Worker [[fallthrough]]; // fall through if no t value found
271*c8dee2aaSAndroid Build Coastguard Worker case SkCubicType::kSerpentine:
272*c8dee2aaSAndroid Build Coastguard Worker case SkCubicType::kLocalCusp:
273*c8dee2aaSAndroid Build Coastguard Worker case SkCubicType::kCuspAtInfinity: {
274*c8dee2aaSAndroid Build Coastguard Worker double inflectionTs[2];
275*c8dee2aaSAndroid Build Coastguard Worker int infTCount = cubic.findInflections(inflectionTs);
276*c8dee2aaSAndroid Build Coastguard Worker double maxCurvature[3];
277*c8dee2aaSAndroid Build Coastguard Worker int roots = cubic.findMaxCurvature(maxCurvature);
278*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_CUBIC_SPLIT
279*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s\n", __FUNCTION__);
280*c8dee2aaSAndroid Build Coastguard Worker cubic.dump();
281*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < infTCount; ++index) {
282*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("inflectionsTs[%d]=%1.9g ", index, inflectionTs[index]);
283*c8dee2aaSAndroid Build Coastguard Worker SkDPoint pt = cubic.ptAtT(inflectionTs[index]);
284*c8dee2aaSAndroid Build Coastguard Worker SkDVector dPt = cubic.dxdyAtT(inflectionTs[index]);
285*c8dee2aaSAndroid Build Coastguard Worker SkDLine perp = {{pt - dPt, pt + dPt}};
286*c8dee2aaSAndroid Build Coastguard Worker perp.dump();
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < roots; ++index) {
289*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("maxCurvature[%d]=%1.9g ", index, maxCurvature[index]);
290*c8dee2aaSAndroid Build Coastguard Worker SkDPoint pt = cubic.ptAtT(maxCurvature[index]);
291*c8dee2aaSAndroid Build Coastguard Worker SkDVector dPt = cubic.dxdyAtT(maxCurvature[index]);
292*c8dee2aaSAndroid Build Coastguard Worker SkDLine perp = {{pt - dPt, pt + dPt}};
293*c8dee2aaSAndroid Build Coastguard Worker perp.dump();
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker #endif
296*c8dee2aaSAndroid Build Coastguard Worker if (infTCount == 2) {
297*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < roots; ++index) {
298*c8dee2aaSAndroid Build Coastguard Worker if (between(inflectionTs[0], maxCurvature[index], inflectionTs[1])) {
299*c8dee2aaSAndroid Build Coastguard Worker t[0] = maxCurvature[index];
300*c8dee2aaSAndroid Build Coastguard Worker return (int) (t[0] > 0 && t[0] < 1);
301*c8dee2aaSAndroid Build Coastguard Worker }
302*c8dee2aaSAndroid Build Coastguard Worker }
303*c8dee2aaSAndroid Build Coastguard Worker } else {
304*c8dee2aaSAndroid Build Coastguard Worker int resultCount = 0;
305*c8dee2aaSAndroid Build Coastguard Worker // FIXME: constant found through experimentation -- maybe there's a better way....
306*c8dee2aaSAndroid Build Coastguard Worker double precision = cubic.calcPrecision() * 2;
307*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < roots; ++index) {
308*c8dee2aaSAndroid Build Coastguard Worker double testT = maxCurvature[index];
309*c8dee2aaSAndroid Build Coastguard Worker if (0 >= testT || testT >= 1) {
310*c8dee2aaSAndroid Build Coastguard Worker continue;
311*c8dee2aaSAndroid Build Coastguard Worker }
312*c8dee2aaSAndroid Build Coastguard Worker // don't call dxdyAtT since we want (0,0) results
313*c8dee2aaSAndroid Build Coastguard Worker SkDVector dPt = { derivative_at_t(&cubic.fPts[0].fX, testT),
314*c8dee2aaSAndroid Build Coastguard Worker derivative_at_t(&cubic.fPts[0].fY, testT) };
315*c8dee2aaSAndroid Build Coastguard Worker double dPtLen = dPt.length();
316*c8dee2aaSAndroid Build Coastguard Worker if (dPtLen < precision) {
317*c8dee2aaSAndroid Build Coastguard Worker t[resultCount++] = testT;
318*c8dee2aaSAndroid Build Coastguard Worker }
319*c8dee2aaSAndroid Build Coastguard Worker }
320*c8dee2aaSAndroid Build Coastguard Worker if (!resultCount && infTCount == 1) {
321*c8dee2aaSAndroid Build Coastguard Worker t[0] = inflectionTs[0];
322*c8dee2aaSAndroid Build Coastguard Worker resultCount = (int) (t[0] > 0 && t[0] < 1);
323*c8dee2aaSAndroid Build Coastguard Worker }
324*c8dee2aaSAndroid Build Coastguard Worker return resultCount;
325*c8dee2aaSAndroid Build Coastguard Worker }
326*c8dee2aaSAndroid Build Coastguard Worker break;
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker default:
329*c8dee2aaSAndroid Build Coastguard Worker break;
330*c8dee2aaSAndroid Build Coastguard Worker }
331*c8dee2aaSAndroid Build Coastguard Worker return 0;
332*c8dee2aaSAndroid Build Coastguard Worker }
333*c8dee2aaSAndroid Build Coastguard Worker
monotonicInX() const334*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::monotonicInX() const {
335*c8dee2aaSAndroid Build Coastguard Worker return precisely_between(fPts[0].fX, fPts[1].fX, fPts[3].fX)
336*c8dee2aaSAndroid Build Coastguard Worker && precisely_between(fPts[0].fX, fPts[2].fX, fPts[3].fX);
337*c8dee2aaSAndroid Build Coastguard Worker }
338*c8dee2aaSAndroid Build Coastguard Worker
monotonicInY() const339*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::monotonicInY() const {
340*c8dee2aaSAndroid Build Coastguard Worker return precisely_between(fPts[0].fY, fPts[1].fY, fPts[3].fY)
341*c8dee2aaSAndroid Build Coastguard Worker && precisely_between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker
otherPts(int index,const SkDPoint * o1Pts[kPointCount-1]) const344*c8dee2aaSAndroid Build Coastguard Worker void SkDCubic::otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const {
345*c8dee2aaSAndroid Build Coastguard Worker int offset = (int) !SkToBool(index);
346*c8dee2aaSAndroid Build Coastguard Worker o1Pts[0] = &fPts[offset];
347*c8dee2aaSAndroid Build Coastguard Worker o1Pts[1] = &fPts[++offset];
348*c8dee2aaSAndroid Build Coastguard Worker o1Pts[2] = &fPts[++offset];
349*c8dee2aaSAndroid Build Coastguard Worker }
350*c8dee2aaSAndroid Build Coastguard Worker
searchRoots(double extremeTs[6],int extrema,double axisIntercept,SearchAxis xAxis,double * validRoots) const351*c8dee2aaSAndroid Build Coastguard Worker int SkDCubic::searchRoots(double extremeTs[6], int extrema, double axisIntercept,
352*c8dee2aaSAndroid Build Coastguard Worker SearchAxis xAxis, double* validRoots) const {
353*c8dee2aaSAndroid Build Coastguard Worker extrema += findInflections(&extremeTs[extrema]);
354*c8dee2aaSAndroid Build Coastguard Worker extremeTs[extrema++] = 0;
355*c8dee2aaSAndroid Build Coastguard Worker extremeTs[extrema] = 1;
356*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(extrema < 6);
357*c8dee2aaSAndroid Build Coastguard Worker SkTQSort(extremeTs, extremeTs + extrema + 1);
358*c8dee2aaSAndroid Build Coastguard Worker int validCount = 0;
359*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < extrema; ) {
360*c8dee2aaSAndroid Build Coastguard Worker double min = extremeTs[index];
361*c8dee2aaSAndroid Build Coastguard Worker double max = extremeTs[++index];
362*c8dee2aaSAndroid Build Coastguard Worker if (min == max) {
363*c8dee2aaSAndroid Build Coastguard Worker continue;
364*c8dee2aaSAndroid Build Coastguard Worker }
365*c8dee2aaSAndroid Build Coastguard Worker double newT = binarySearch(min, max, axisIntercept, xAxis);
366*c8dee2aaSAndroid Build Coastguard Worker if (newT >= 0) {
367*c8dee2aaSAndroid Build Coastguard Worker if (validCount >= 3) {
368*c8dee2aaSAndroid Build Coastguard Worker return 0;
369*c8dee2aaSAndroid Build Coastguard Worker }
370*c8dee2aaSAndroid Build Coastguard Worker validRoots[validCount++] = newT;
371*c8dee2aaSAndroid Build Coastguard Worker }
372*c8dee2aaSAndroid Build Coastguard Worker }
373*c8dee2aaSAndroid Build Coastguard Worker return validCount;
374*c8dee2aaSAndroid Build Coastguard Worker }
375*c8dee2aaSAndroid Build Coastguard Worker
376*c8dee2aaSAndroid Build Coastguard Worker // cubic roots
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker static const double PI = 3.141592653589793;
379*c8dee2aaSAndroid Build Coastguard Worker
380*c8dee2aaSAndroid Build Coastguard Worker // from SkGeometry.cpp (and Numeric Solutions, 5.6)
381*c8dee2aaSAndroid Build Coastguard Worker // // TODO(skbug.com/14063) Deduplicate with SkCubics::RootsValidT
RootsValidT(double A,double B,double C,double D,double t[3])382*c8dee2aaSAndroid Build Coastguard Worker int SkDCubic::RootsValidT(double A, double B, double C, double D, double t[3]) {
383*c8dee2aaSAndroid Build Coastguard Worker double s[3];
384*c8dee2aaSAndroid Build Coastguard Worker int realRoots = RootsReal(A, B, C, D, s);
385*c8dee2aaSAndroid Build Coastguard Worker int foundRoots = SkDQuad::AddValidTs(s, realRoots, t);
386*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < realRoots; ++index) {
387*c8dee2aaSAndroid Build Coastguard Worker double tValue = s[index];
388*c8dee2aaSAndroid Build Coastguard Worker if (!approximately_one_or_less(tValue) && between(1, tValue, 1.00005)) {
389*c8dee2aaSAndroid Build Coastguard Worker for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
390*c8dee2aaSAndroid Build Coastguard Worker if (approximately_equal(t[idx2], 1)) {
391*c8dee2aaSAndroid Build Coastguard Worker goto nextRoot;
392*c8dee2aaSAndroid Build Coastguard Worker }
393*c8dee2aaSAndroid Build Coastguard Worker }
394*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(foundRoots < 3);
395*c8dee2aaSAndroid Build Coastguard Worker t[foundRoots++] = 1;
396*c8dee2aaSAndroid Build Coastguard Worker } else if (!approximately_zero_or_more(tValue) && between(-0.00005, tValue, 0)) {
397*c8dee2aaSAndroid Build Coastguard Worker for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
398*c8dee2aaSAndroid Build Coastguard Worker if (approximately_equal(t[idx2], 0)) {
399*c8dee2aaSAndroid Build Coastguard Worker goto nextRoot;
400*c8dee2aaSAndroid Build Coastguard Worker }
401*c8dee2aaSAndroid Build Coastguard Worker }
402*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(foundRoots < 3);
403*c8dee2aaSAndroid Build Coastguard Worker t[foundRoots++] = 0;
404*c8dee2aaSAndroid Build Coastguard Worker }
405*c8dee2aaSAndroid Build Coastguard Worker nextRoot:
406*c8dee2aaSAndroid Build Coastguard Worker ;
407*c8dee2aaSAndroid Build Coastguard Worker }
408*c8dee2aaSAndroid Build Coastguard Worker return foundRoots;
409*c8dee2aaSAndroid Build Coastguard Worker }
410*c8dee2aaSAndroid Build Coastguard Worker
411*c8dee2aaSAndroid Build Coastguard Worker // TODO(skbug.com/14063) Deduplicate with SkCubics::RootsReal
RootsReal(double A,double B,double C,double D,double s[3])412*c8dee2aaSAndroid Build Coastguard Worker int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) {
413*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
414*c8dee2aaSAndroid Build Coastguard Worker #if ONE_OFF_DEBUG && ONE_OFF_DEBUG_MATHEMATICA
415*c8dee2aaSAndroid Build Coastguard Worker // create a string mathematica understands
416*c8dee2aaSAndroid Build Coastguard Worker // GDB set print repe 15 # if repeated digits is a bother
417*c8dee2aaSAndroid Build Coastguard Worker // set print elements 400 # if line doesn't fit
418*c8dee2aaSAndroid Build Coastguard Worker char str[1024];
419*c8dee2aaSAndroid Build Coastguard Worker sk_bzero(str, sizeof(str));
420*c8dee2aaSAndroid Build Coastguard Worker snprintf(str, sizeof(str), "Solve[%1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]",
421*c8dee2aaSAndroid Build Coastguard Worker A, B, C, D);
422*c8dee2aaSAndroid Build Coastguard Worker SkPathOpsDebug::MathematicaIze(str, sizeof(str));
423*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s\n", str);
424*c8dee2aaSAndroid Build Coastguard Worker #endif
425*c8dee2aaSAndroid Build Coastguard Worker #endif
426*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero(A)
427*c8dee2aaSAndroid Build Coastguard Worker && approximately_zero_when_compared_to(A, B)
428*c8dee2aaSAndroid Build Coastguard Worker && approximately_zero_when_compared_to(A, C)
429*c8dee2aaSAndroid Build Coastguard Worker && approximately_zero_when_compared_to(A, D)) { // we're just a quadratic
430*c8dee2aaSAndroid Build Coastguard Worker return SkDQuad::RootsReal(B, C, D, s);
431*c8dee2aaSAndroid Build Coastguard Worker }
432*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero_when_compared_to(D, A)
433*c8dee2aaSAndroid Build Coastguard Worker && approximately_zero_when_compared_to(D, B)
434*c8dee2aaSAndroid Build Coastguard Worker && approximately_zero_when_compared_to(D, C)) { // 0 is one root
435*c8dee2aaSAndroid Build Coastguard Worker int num = SkDQuad::RootsReal(A, B, C, s);
436*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < num; ++i) {
437*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero(s[i])) {
438*c8dee2aaSAndroid Build Coastguard Worker return num;
439*c8dee2aaSAndroid Build Coastguard Worker }
440*c8dee2aaSAndroid Build Coastguard Worker }
441*c8dee2aaSAndroid Build Coastguard Worker s[num++] = 0;
442*c8dee2aaSAndroid Build Coastguard Worker return num;
443*c8dee2aaSAndroid Build Coastguard Worker }
444*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero(A + B + C + D)) { // 1 is one root
445*c8dee2aaSAndroid Build Coastguard Worker int num = SkDQuad::RootsReal(A, A + B, -D, s);
446*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < num; ++i) {
447*c8dee2aaSAndroid Build Coastguard Worker if (AlmostDequalUlps(s[i], 1)) {
448*c8dee2aaSAndroid Build Coastguard Worker return num;
449*c8dee2aaSAndroid Build Coastguard Worker }
450*c8dee2aaSAndroid Build Coastguard Worker }
451*c8dee2aaSAndroid Build Coastguard Worker s[num++] = 1;
452*c8dee2aaSAndroid Build Coastguard Worker return num;
453*c8dee2aaSAndroid Build Coastguard Worker }
454*c8dee2aaSAndroid Build Coastguard Worker double a, b, c;
455*c8dee2aaSAndroid Build Coastguard Worker {
456*c8dee2aaSAndroid Build Coastguard Worker double invA = 1 / A;
457*c8dee2aaSAndroid Build Coastguard Worker a = B * invA;
458*c8dee2aaSAndroid Build Coastguard Worker b = C * invA;
459*c8dee2aaSAndroid Build Coastguard Worker c = D * invA;
460*c8dee2aaSAndroid Build Coastguard Worker }
461*c8dee2aaSAndroid Build Coastguard Worker double a2 = a * a;
462*c8dee2aaSAndroid Build Coastguard Worker double Q = (a2 - b * 3) / 9;
463*c8dee2aaSAndroid Build Coastguard Worker double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
464*c8dee2aaSAndroid Build Coastguard Worker double R2 = R * R;
465*c8dee2aaSAndroid Build Coastguard Worker double Q3 = Q * Q * Q;
466*c8dee2aaSAndroid Build Coastguard Worker double R2MinusQ3 = R2 - Q3;
467*c8dee2aaSAndroid Build Coastguard Worker double adiv3 = a / 3;
468*c8dee2aaSAndroid Build Coastguard Worker double r;
469*c8dee2aaSAndroid Build Coastguard Worker double* roots = s;
470*c8dee2aaSAndroid Build Coastguard Worker if (R2MinusQ3 < 0) { // we have 3 real roots
471*c8dee2aaSAndroid Build Coastguard Worker // the divide/root can, due to finite precisions, be slightly outside of -1...1
472*c8dee2aaSAndroid Build Coastguard Worker double theta = acos(SkTPin(R / sqrt(Q3), -1., 1.));
473*c8dee2aaSAndroid Build Coastguard Worker double neg2RootQ = -2 * sqrt(Q);
474*c8dee2aaSAndroid Build Coastguard Worker
475*c8dee2aaSAndroid Build Coastguard Worker r = neg2RootQ * cos(theta / 3) - adiv3;
476*c8dee2aaSAndroid Build Coastguard Worker *roots++ = r;
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
479*c8dee2aaSAndroid Build Coastguard Worker if (!AlmostDequalUlps(s[0], r)) {
480*c8dee2aaSAndroid Build Coastguard Worker *roots++ = r;
481*c8dee2aaSAndroid Build Coastguard Worker }
482*c8dee2aaSAndroid Build Coastguard Worker r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
483*c8dee2aaSAndroid Build Coastguard Worker if (!AlmostDequalUlps(s[0], r) && (roots - s == 1 || !AlmostDequalUlps(s[1], r))) {
484*c8dee2aaSAndroid Build Coastguard Worker *roots++ = r;
485*c8dee2aaSAndroid Build Coastguard Worker }
486*c8dee2aaSAndroid Build Coastguard Worker } else { // we have 1 real root
487*c8dee2aaSAndroid Build Coastguard Worker double sqrtR2MinusQ3 = sqrt(R2MinusQ3);
488*c8dee2aaSAndroid Build Coastguard Worker A = fabs(R) + sqrtR2MinusQ3;
489*c8dee2aaSAndroid Build Coastguard Worker A = std::cbrt(A); // cube root
490*c8dee2aaSAndroid Build Coastguard Worker if (R > 0) {
491*c8dee2aaSAndroid Build Coastguard Worker A = -A;
492*c8dee2aaSAndroid Build Coastguard Worker }
493*c8dee2aaSAndroid Build Coastguard Worker if (A != 0) {
494*c8dee2aaSAndroid Build Coastguard Worker A += Q / A;
495*c8dee2aaSAndroid Build Coastguard Worker }
496*c8dee2aaSAndroid Build Coastguard Worker r = A - adiv3;
497*c8dee2aaSAndroid Build Coastguard Worker *roots++ = r;
498*c8dee2aaSAndroid Build Coastguard Worker if (AlmostDequalUlps((double) R2, (double) Q3)) {
499*c8dee2aaSAndroid Build Coastguard Worker r = -A / 2 - adiv3;
500*c8dee2aaSAndroid Build Coastguard Worker if (!AlmostDequalUlps(s[0], r)) {
501*c8dee2aaSAndroid Build Coastguard Worker *roots++ = r;
502*c8dee2aaSAndroid Build Coastguard Worker }
503*c8dee2aaSAndroid Build Coastguard Worker }
504*c8dee2aaSAndroid Build Coastguard Worker }
505*c8dee2aaSAndroid Build Coastguard Worker return static_cast<int>(roots - s);
506*c8dee2aaSAndroid Build Coastguard Worker }
507*c8dee2aaSAndroid Build Coastguard Worker
508*c8dee2aaSAndroid Build Coastguard Worker // OPTIMIZE? compute t^2, t(1-t), and (1-t)^2 and pass them to another version of derivative at t?
dxdyAtT(double t) const509*c8dee2aaSAndroid Build Coastguard Worker SkDVector SkDCubic::dxdyAtT(double t) const {
510*c8dee2aaSAndroid Build Coastguard Worker SkDVector result = { derivative_at_t(&fPts[0].fX, t), derivative_at_t(&fPts[0].fY, t) };
511*c8dee2aaSAndroid Build Coastguard Worker if (result.fX == 0 && result.fY == 0) {
512*c8dee2aaSAndroid Build Coastguard Worker if (t == 0) {
513*c8dee2aaSAndroid Build Coastguard Worker result = fPts[2] - fPts[0];
514*c8dee2aaSAndroid Build Coastguard Worker } else if (t == 1) {
515*c8dee2aaSAndroid Build Coastguard Worker result = fPts[3] - fPts[1];
516*c8dee2aaSAndroid Build Coastguard Worker } else {
517*c8dee2aaSAndroid Build Coastguard Worker // incomplete
518*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("!c");
519*c8dee2aaSAndroid Build Coastguard Worker }
520*c8dee2aaSAndroid Build Coastguard Worker if (result.fX == 0 && result.fY == 0 && zero_or_one(t)) {
521*c8dee2aaSAndroid Build Coastguard Worker result = fPts[3] - fPts[0];
522*c8dee2aaSAndroid Build Coastguard Worker }
523*c8dee2aaSAndroid Build Coastguard Worker }
524*c8dee2aaSAndroid Build Coastguard Worker return result;
525*c8dee2aaSAndroid Build Coastguard Worker }
526*c8dee2aaSAndroid Build Coastguard Worker
527*c8dee2aaSAndroid Build Coastguard Worker // OPTIMIZE? share code with formulate_F1DotF2
528*c8dee2aaSAndroid Build Coastguard Worker // e.g. https://stackoverflow.com/a/35927917
findInflections(double tValues[2]) const529*c8dee2aaSAndroid Build Coastguard Worker int SkDCubic::findInflections(double tValues[2]) const {
530*c8dee2aaSAndroid Build Coastguard Worker double Ax = fPts[1].fX - fPts[0].fX;
531*c8dee2aaSAndroid Build Coastguard Worker double Ay = fPts[1].fY - fPts[0].fY;
532*c8dee2aaSAndroid Build Coastguard Worker double Bx = fPts[2].fX - 2 * fPts[1].fX + fPts[0].fX;
533*c8dee2aaSAndroid Build Coastguard Worker double By = fPts[2].fY - 2 * fPts[1].fY + fPts[0].fY;
534*c8dee2aaSAndroid Build Coastguard Worker double Cx = fPts[3].fX + 3 * (fPts[1].fX - fPts[2].fX) - fPts[0].fX;
535*c8dee2aaSAndroid Build Coastguard Worker double Cy = fPts[3].fY + 3 * (fPts[1].fY - fPts[2].fY) - fPts[0].fY;
536*c8dee2aaSAndroid Build Coastguard Worker return SkDQuad::RootsValidT(Bx * Cy - By * Cx, Ax * Cy - Ay * Cx, Ax * By - Ay * Bx, tValues);
537*c8dee2aaSAndroid Build Coastguard Worker }
538*c8dee2aaSAndroid Build Coastguard Worker
formulate_F1DotF2(const double src[],double coeff[4])539*c8dee2aaSAndroid Build Coastguard Worker static void formulate_F1DotF2(const double src[], double coeff[4]) {
540*c8dee2aaSAndroid Build Coastguard Worker double a = src[2] - src[0];
541*c8dee2aaSAndroid Build Coastguard Worker double b = src[4] - 2 * src[2] + src[0];
542*c8dee2aaSAndroid Build Coastguard Worker double c = src[6] + 3 * (src[2] - src[4]) - src[0];
543*c8dee2aaSAndroid Build Coastguard Worker coeff[0] = c * c;
544*c8dee2aaSAndroid Build Coastguard Worker coeff[1] = 3 * b * c;
545*c8dee2aaSAndroid Build Coastguard Worker coeff[2] = 2 * b * b + c * a;
546*c8dee2aaSAndroid Build Coastguard Worker coeff[3] = a * b;
547*c8dee2aaSAndroid Build Coastguard Worker }
548*c8dee2aaSAndroid Build Coastguard Worker
549*c8dee2aaSAndroid Build Coastguard Worker /** SkDCubic'(t) = At^2 + Bt + C, where
550*c8dee2aaSAndroid Build Coastguard Worker A = 3(-a + 3(b - c) + d)
551*c8dee2aaSAndroid Build Coastguard Worker B = 6(a - 2b + c)
552*c8dee2aaSAndroid Build Coastguard Worker C = 3(b - a)
553*c8dee2aaSAndroid Build Coastguard Worker Solve for t, keeping only those that fit between 0 < t < 1
554*c8dee2aaSAndroid Build Coastguard Worker */
FindExtrema(const double src[],double tValues[2])555*c8dee2aaSAndroid Build Coastguard Worker int SkDCubic::FindExtrema(const double src[], double tValues[2]) {
556*c8dee2aaSAndroid Build Coastguard Worker // we divide A,B,C by 3 to simplify
557*c8dee2aaSAndroid Build Coastguard Worker double a = src[0];
558*c8dee2aaSAndroid Build Coastguard Worker double b = src[2];
559*c8dee2aaSAndroid Build Coastguard Worker double c = src[4];
560*c8dee2aaSAndroid Build Coastguard Worker double d = src[6];
561*c8dee2aaSAndroid Build Coastguard Worker double A = d - a + 3 * (b - c);
562*c8dee2aaSAndroid Build Coastguard Worker double B = 2 * (a - b - b + c);
563*c8dee2aaSAndroid Build Coastguard Worker double C = b - a;
564*c8dee2aaSAndroid Build Coastguard Worker
565*c8dee2aaSAndroid Build Coastguard Worker return SkDQuad::RootsValidT(A, B, C, tValues);
566*c8dee2aaSAndroid Build Coastguard Worker }
567*c8dee2aaSAndroid Build Coastguard Worker
568*c8dee2aaSAndroid Build Coastguard Worker /* from SkGeometry.cpp
569*c8dee2aaSAndroid Build Coastguard Worker Looking for F' dot F'' == 0
570*c8dee2aaSAndroid Build Coastguard Worker
571*c8dee2aaSAndroid Build Coastguard Worker A = b - a
572*c8dee2aaSAndroid Build Coastguard Worker B = c - 2b + a
573*c8dee2aaSAndroid Build Coastguard Worker C = d - 3c + 3b - a
574*c8dee2aaSAndroid Build Coastguard Worker
575*c8dee2aaSAndroid Build Coastguard Worker F' = 3Ct^2 + 6Bt + 3A
576*c8dee2aaSAndroid Build Coastguard Worker F'' = 6Ct + 6B
577*c8dee2aaSAndroid Build Coastguard Worker
578*c8dee2aaSAndroid Build Coastguard Worker F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
579*c8dee2aaSAndroid Build Coastguard Worker */
findMaxCurvature(double tValues[]) const580*c8dee2aaSAndroid Build Coastguard Worker int SkDCubic::findMaxCurvature(double tValues[]) const {
581*c8dee2aaSAndroid Build Coastguard Worker double coeffX[4], coeffY[4];
582*c8dee2aaSAndroid Build Coastguard Worker int i;
583*c8dee2aaSAndroid Build Coastguard Worker formulate_F1DotF2(&fPts[0].fX, coeffX);
584*c8dee2aaSAndroid Build Coastguard Worker formulate_F1DotF2(&fPts[0].fY, coeffY);
585*c8dee2aaSAndroid Build Coastguard Worker for (i = 0; i < 4; i++) {
586*c8dee2aaSAndroid Build Coastguard Worker coeffX[i] = coeffX[i] + coeffY[i];
587*c8dee2aaSAndroid Build Coastguard Worker }
588*c8dee2aaSAndroid Build Coastguard Worker return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues);
589*c8dee2aaSAndroid Build Coastguard Worker }
590*c8dee2aaSAndroid Build Coastguard Worker
ptAtT(double t) const591*c8dee2aaSAndroid Build Coastguard Worker SkDPoint SkDCubic::ptAtT(double t) const {
592*c8dee2aaSAndroid Build Coastguard Worker if (0 == t) {
593*c8dee2aaSAndroid Build Coastguard Worker return fPts[0];
594*c8dee2aaSAndroid Build Coastguard Worker }
595*c8dee2aaSAndroid Build Coastguard Worker if (1 == t) {
596*c8dee2aaSAndroid Build Coastguard Worker return fPts[3];
597*c8dee2aaSAndroid Build Coastguard Worker }
598*c8dee2aaSAndroid Build Coastguard Worker double one_t = 1 - t;
599*c8dee2aaSAndroid Build Coastguard Worker double one_t2 = one_t * one_t;
600*c8dee2aaSAndroid Build Coastguard Worker double a = one_t2 * one_t;
601*c8dee2aaSAndroid Build Coastguard Worker double b = 3 * one_t2 * t;
602*c8dee2aaSAndroid Build Coastguard Worker double t2 = t * t;
603*c8dee2aaSAndroid Build Coastguard Worker double c = 3 * one_t * t2;
604*c8dee2aaSAndroid Build Coastguard Worker double d = t2 * t;
605*c8dee2aaSAndroid Build Coastguard Worker SkDPoint result = {a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX + d * fPts[3].fX,
606*c8dee2aaSAndroid Build Coastguard Worker a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY + d * fPts[3].fY};
607*c8dee2aaSAndroid Build Coastguard Worker return result;
608*c8dee2aaSAndroid Build Coastguard Worker }
609*c8dee2aaSAndroid Build Coastguard Worker
610*c8dee2aaSAndroid Build Coastguard Worker /*
611*c8dee2aaSAndroid Build Coastguard Worker Given a cubic c, t1, and t2, find a small cubic segment.
612*c8dee2aaSAndroid Build Coastguard Worker
613*c8dee2aaSAndroid Build Coastguard Worker The new cubic is defined as points A, B, C, and D, where
614*c8dee2aaSAndroid Build Coastguard Worker s1 = 1 - t1
615*c8dee2aaSAndroid Build Coastguard Worker s2 = 1 - t2
616*c8dee2aaSAndroid Build Coastguard Worker A = c[0]*s1*s1*s1 + 3*c[1]*s1*s1*t1 + 3*c[2]*s1*t1*t1 + c[3]*t1*t1*t1
617*c8dee2aaSAndroid Build Coastguard Worker D = c[0]*s2*s2*s2 + 3*c[1]*s2*s2*t2 + 3*c[2]*s2*t2*t2 + c[3]*t2*t2*t2
618*c8dee2aaSAndroid Build Coastguard Worker
619*c8dee2aaSAndroid Build Coastguard Worker We don't have B or C. So We define two equations to isolate them.
620*c8dee2aaSAndroid Build Coastguard Worker First, compute two reference T values 1/3 and 2/3 from t1 to t2:
621*c8dee2aaSAndroid Build Coastguard Worker
622*c8dee2aaSAndroid Build Coastguard Worker c(at (2*t1 + t2)/3) == E
623*c8dee2aaSAndroid Build Coastguard Worker c(at (t1 + 2*t2)/3) == F
624*c8dee2aaSAndroid Build Coastguard Worker
625*c8dee2aaSAndroid Build Coastguard Worker Next, compute where those values must be if we know the values of B and C:
626*c8dee2aaSAndroid Build Coastguard Worker
627*c8dee2aaSAndroid Build Coastguard Worker _12 = A*2/3 + B*1/3
628*c8dee2aaSAndroid Build Coastguard Worker 12_ = A*1/3 + B*2/3
629*c8dee2aaSAndroid Build Coastguard Worker _23 = B*2/3 + C*1/3
630*c8dee2aaSAndroid Build Coastguard Worker 23_ = B*1/3 + C*2/3
631*c8dee2aaSAndroid Build Coastguard Worker _34 = C*2/3 + D*1/3
632*c8dee2aaSAndroid Build Coastguard Worker 34_ = C*1/3 + D*2/3
633*c8dee2aaSAndroid Build Coastguard Worker _123 = (A*2/3 + B*1/3)*2/3 + (B*2/3 + C*1/3)*1/3 = A*4/9 + B*4/9 + C*1/9
634*c8dee2aaSAndroid Build Coastguard Worker 123_ = (A*1/3 + B*2/3)*1/3 + (B*1/3 + C*2/3)*2/3 = A*1/9 + B*4/9 + C*4/9
635*c8dee2aaSAndroid Build Coastguard Worker _234 = (B*2/3 + C*1/3)*2/3 + (C*2/3 + D*1/3)*1/3 = B*4/9 + C*4/9 + D*1/9
636*c8dee2aaSAndroid Build Coastguard Worker 234_ = (B*1/3 + C*2/3)*1/3 + (C*1/3 + D*2/3)*2/3 = B*1/9 + C*4/9 + D*4/9
637*c8dee2aaSAndroid Build Coastguard Worker _1234 = (A*4/9 + B*4/9 + C*1/9)*2/3 + (B*4/9 + C*4/9 + D*1/9)*1/3
638*c8dee2aaSAndroid Build Coastguard Worker = A*8/27 + B*12/27 + C*6/27 + D*1/27
639*c8dee2aaSAndroid Build Coastguard Worker = E
640*c8dee2aaSAndroid Build Coastguard Worker 1234_ = (A*1/9 + B*4/9 + C*4/9)*1/3 + (B*1/9 + C*4/9 + D*4/9)*2/3
641*c8dee2aaSAndroid Build Coastguard Worker = A*1/27 + B*6/27 + C*12/27 + D*8/27
642*c8dee2aaSAndroid Build Coastguard Worker = F
643*c8dee2aaSAndroid Build Coastguard Worker E*27 = A*8 + B*12 + C*6 + D
644*c8dee2aaSAndroid Build Coastguard Worker F*27 = A + B*6 + C*12 + D*8
645*c8dee2aaSAndroid Build Coastguard Worker
646*c8dee2aaSAndroid Build Coastguard Worker Group the known values on one side:
647*c8dee2aaSAndroid Build Coastguard Worker
648*c8dee2aaSAndroid Build Coastguard Worker M = E*27 - A*8 - D = B*12 + C* 6
649*c8dee2aaSAndroid Build Coastguard Worker N = F*27 - A - D*8 = B* 6 + C*12
650*c8dee2aaSAndroid Build Coastguard Worker M*2 - N = B*18
651*c8dee2aaSAndroid Build Coastguard Worker N*2 - M = C*18
652*c8dee2aaSAndroid Build Coastguard Worker B = (M*2 - N)/18
653*c8dee2aaSAndroid Build Coastguard Worker C = (N*2 - M)/18
654*c8dee2aaSAndroid Build Coastguard Worker */
655*c8dee2aaSAndroid Build Coastguard Worker
interp_cubic_coords(const double * src,double t)656*c8dee2aaSAndroid Build Coastguard Worker static double interp_cubic_coords(const double* src, double t) {
657*c8dee2aaSAndroid Build Coastguard Worker double ab = SkDInterp(src[0], src[2], t);
658*c8dee2aaSAndroid Build Coastguard Worker double bc = SkDInterp(src[2], src[4], t);
659*c8dee2aaSAndroid Build Coastguard Worker double cd = SkDInterp(src[4], src[6], t);
660*c8dee2aaSAndroid Build Coastguard Worker double abc = SkDInterp(ab, bc, t);
661*c8dee2aaSAndroid Build Coastguard Worker double bcd = SkDInterp(bc, cd, t);
662*c8dee2aaSAndroid Build Coastguard Worker double abcd = SkDInterp(abc, bcd, t);
663*c8dee2aaSAndroid Build Coastguard Worker return abcd;
664*c8dee2aaSAndroid Build Coastguard Worker }
665*c8dee2aaSAndroid Build Coastguard Worker
subDivide(double t1,double t2) const666*c8dee2aaSAndroid Build Coastguard Worker SkDCubic SkDCubic::subDivide(double t1, double t2) const {
667*c8dee2aaSAndroid Build Coastguard Worker if (t1 == 0 || t2 == 1) {
668*c8dee2aaSAndroid Build Coastguard Worker if (t1 == 0 && t2 == 1) {
669*c8dee2aaSAndroid Build Coastguard Worker return *this;
670*c8dee2aaSAndroid Build Coastguard Worker }
671*c8dee2aaSAndroid Build Coastguard Worker SkDCubicPair pair = chopAt(t1 == 0 ? t2 : t1);
672*c8dee2aaSAndroid Build Coastguard Worker SkDCubic dst = t1 == 0 ? pair.first() : pair.second();
673*c8dee2aaSAndroid Build Coastguard Worker return dst;
674*c8dee2aaSAndroid Build Coastguard Worker }
675*c8dee2aaSAndroid Build Coastguard Worker SkDCubic dst;
676*c8dee2aaSAndroid Build Coastguard Worker double ax = dst[0].fX = interp_cubic_coords(&fPts[0].fX, t1);
677*c8dee2aaSAndroid Build Coastguard Worker double ay = dst[0].fY = interp_cubic_coords(&fPts[0].fY, t1);
678*c8dee2aaSAndroid Build Coastguard Worker double ex = interp_cubic_coords(&fPts[0].fX, (t1*2+t2)/3);
679*c8dee2aaSAndroid Build Coastguard Worker double ey = interp_cubic_coords(&fPts[0].fY, (t1*2+t2)/3);
680*c8dee2aaSAndroid Build Coastguard Worker double fx = interp_cubic_coords(&fPts[0].fX, (t1+t2*2)/3);
681*c8dee2aaSAndroid Build Coastguard Worker double fy = interp_cubic_coords(&fPts[0].fY, (t1+t2*2)/3);
682*c8dee2aaSAndroid Build Coastguard Worker double dx = dst[3].fX = interp_cubic_coords(&fPts[0].fX, t2);
683*c8dee2aaSAndroid Build Coastguard Worker double dy = dst[3].fY = interp_cubic_coords(&fPts[0].fY, t2);
684*c8dee2aaSAndroid Build Coastguard Worker double mx = ex * 27 - ax * 8 - dx;
685*c8dee2aaSAndroid Build Coastguard Worker double my = ey * 27 - ay * 8 - dy;
686*c8dee2aaSAndroid Build Coastguard Worker double nx = fx * 27 - ax - dx * 8;
687*c8dee2aaSAndroid Build Coastguard Worker double ny = fy * 27 - ay - dy * 8;
688*c8dee2aaSAndroid Build Coastguard Worker /* bx = */ dst[1].fX = (mx * 2 - nx) / 18;
689*c8dee2aaSAndroid Build Coastguard Worker /* by = */ dst[1].fY = (my * 2 - ny) / 18;
690*c8dee2aaSAndroid Build Coastguard Worker /* cx = */ dst[2].fX = (nx * 2 - mx) / 18;
691*c8dee2aaSAndroid Build Coastguard Worker /* cy = */ dst[2].fY = (ny * 2 - my) / 18;
692*c8dee2aaSAndroid Build Coastguard Worker // FIXME: call align() ?
693*c8dee2aaSAndroid Build Coastguard Worker return dst;
694*c8dee2aaSAndroid Build Coastguard Worker }
695*c8dee2aaSAndroid Build Coastguard Worker
subDivide(const SkDPoint & a,const SkDPoint & d,double t1,double t2,SkDPoint dst[2]) const696*c8dee2aaSAndroid Build Coastguard Worker void SkDCubic::subDivide(const SkDPoint& a, const SkDPoint& d,
697*c8dee2aaSAndroid Build Coastguard Worker double t1, double t2, SkDPoint dst[2]) const {
698*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(t1 != t2);
699*c8dee2aaSAndroid Build Coastguard Worker // this approach assumes that the control points computed directly are accurate enough
700*c8dee2aaSAndroid Build Coastguard Worker SkDCubic sub = subDivide(t1, t2);
701*c8dee2aaSAndroid Build Coastguard Worker dst[0] = sub[1] + (a - sub[0]);
702*c8dee2aaSAndroid Build Coastguard Worker dst[1] = sub[2] + (d - sub[3]);
703*c8dee2aaSAndroid Build Coastguard Worker if (t1 == 0 || t2 == 0) {
704*c8dee2aaSAndroid Build Coastguard Worker align(0, 1, t1 == 0 ? &dst[0] : &dst[1]);
705*c8dee2aaSAndroid Build Coastguard Worker }
706*c8dee2aaSAndroid Build Coastguard Worker if (t1 == 1 || t2 == 1) {
707*c8dee2aaSAndroid Build Coastguard Worker align(3, 2, t1 == 1 ? &dst[0] : &dst[1]);
708*c8dee2aaSAndroid Build Coastguard Worker }
709*c8dee2aaSAndroid Build Coastguard Worker if (AlmostBequalUlps(dst[0].fX, a.fX)) {
710*c8dee2aaSAndroid Build Coastguard Worker dst[0].fX = a.fX;
711*c8dee2aaSAndroid Build Coastguard Worker }
712*c8dee2aaSAndroid Build Coastguard Worker if (AlmostBequalUlps(dst[0].fY, a.fY)) {
713*c8dee2aaSAndroid Build Coastguard Worker dst[0].fY = a.fY;
714*c8dee2aaSAndroid Build Coastguard Worker }
715*c8dee2aaSAndroid Build Coastguard Worker if (AlmostBequalUlps(dst[1].fX, d.fX)) {
716*c8dee2aaSAndroid Build Coastguard Worker dst[1].fX = d.fX;
717*c8dee2aaSAndroid Build Coastguard Worker }
718*c8dee2aaSAndroid Build Coastguard Worker if (AlmostBequalUlps(dst[1].fY, d.fY)) {
719*c8dee2aaSAndroid Build Coastguard Worker dst[1].fY = d.fY;
720*c8dee2aaSAndroid Build Coastguard Worker }
721*c8dee2aaSAndroid Build Coastguard Worker }
722*c8dee2aaSAndroid Build Coastguard Worker
toFloatPoints(SkPoint * pts) const723*c8dee2aaSAndroid Build Coastguard Worker bool SkDCubic::toFloatPoints(SkPoint* pts) const {
724*c8dee2aaSAndroid Build Coastguard Worker const double* dCubic = &fPts[0].fX;
725*c8dee2aaSAndroid Build Coastguard Worker SkScalar* cubic = &pts[0].fX;
726*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < kPointCount * 2; ++index) {
727*c8dee2aaSAndroid Build Coastguard Worker cubic[index] = SkDoubleToScalar(dCubic[index]);
728*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarAbs(cubic[index]) < FLT_EPSILON_ORDERABLE_ERR) {
729*c8dee2aaSAndroid Build Coastguard Worker cubic[index] = 0;
730*c8dee2aaSAndroid Build Coastguard Worker }
731*c8dee2aaSAndroid Build Coastguard Worker }
732*c8dee2aaSAndroid Build Coastguard Worker return SkIsFinite(&pts->fX, kPointCount * 2);
733*c8dee2aaSAndroid Build Coastguard Worker }
734*c8dee2aaSAndroid Build Coastguard Worker
top(const SkDCubic & dCurve,double startT,double endT,SkDPoint * topPt) const735*c8dee2aaSAndroid Build Coastguard Worker double SkDCubic::top(const SkDCubic& dCurve, double startT, double endT, SkDPoint*topPt) const {
736*c8dee2aaSAndroid Build Coastguard Worker double extremeTs[2];
737*c8dee2aaSAndroid Build Coastguard Worker double topT = -1;
738*c8dee2aaSAndroid Build Coastguard Worker int roots = SkDCubic::FindExtrema(&fPts[0].fY, extremeTs);
739*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < roots; ++index) {
740*c8dee2aaSAndroid Build Coastguard Worker double t = startT + (endT - startT) * extremeTs[index];
741*c8dee2aaSAndroid Build Coastguard Worker SkDPoint mid = dCurve.ptAtT(t);
742*c8dee2aaSAndroid Build Coastguard Worker if (topPt->fY > mid.fY || (topPt->fY == mid.fY && topPt->fX > mid.fX)) {
743*c8dee2aaSAndroid Build Coastguard Worker topT = t;
744*c8dee2aaSAndroid Build Coastguard Worker *topPt = mid;
745*c8dee2aaSAndroid Build Coastguard Worker }
746*c8dee2aaSAndroid Build Coastguard Worker }
747*c8dee2aaSAndroid Build Coastguard Worker return topT;
748*c8dee2aaSAndroid Build Coastguard Worker }
749*c8dee2aaSAndroid Build Coastguard Worker
intersectRay(SkIntersections * i,const SkDLine & line) const750*c8dee2aaSAndroid Build Coastguard Worker int SkTCubic::intersectRay(SkIntersections* i, const SkDLine& line) const {
751*c8dee2aaSAndroid Build Coastguard Worker return i->intersectRay(fCubic, line);
752*c8dee2aaSAndroid Build Coastguard Worker }
753*c8dee2aaSAndroid Build Coastguard Worker
hullIntersects(const SkDQuad & quad,bool * isLinear) const754*c8dee2aaSAndroid Build Coastguard Worker bool SkTCubic::hullIntersects(const SkDQuad& quad, bool* isLinear) const {
755*c8dee2aaSAndroid Build Coastguard Worker return quad.hullIntersects(fCubic, isLinear);
756*c8dee2aaSAndroid Build Coastguard Worker }
757*c8dee2aaSAndroid Build Coastguard Worker
hullIntersects(const SkDConic & conic,bool * isLinear) const758*c8dee2aaSAndroid Build Coastguard Worker bool SkTCubic::hullIntersects(const SkDConic& conic, bool* isLinear) const {
759*c8dee2aaSAndroid Build Coastguard Worker return conic.hullIntersects(fCubic, isLinear);
760*c8dee2aaSAndroid Build Coastguard Worker }
761*c8dee2aaSAndroid Build Coastguard Worker
setBounds(SkDRect * rect) const762*c8dee2aaSAndroid Build Coastguard Worker void SkTCubic::setBounds(SkDRect* rect) const {
763*c8dee2aaSAndroid Build Coastguard Worker rect->setBounds(fCubic);
764*c8dee2aaSAndroid Build Coastguard Worker }
765