xref: /aosp_15_r20/external/skia/src/pathops/SkPathOpsCubic.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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