xref: /aosp_15_r20/external/skia/src/pathops/SkPathOpsQuad.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/SkPathOpsQuad.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkIntersections.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkLineParameters.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsConic.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsCubic.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsLine.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsRect.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsTypes.h"
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
18*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker // from blackpawn.com/texts/pointinpoly
pointInTriangle(const SkDPoint fPts[3],const SkDPoint & test)21*c8dee2aaSAndroid Build Coastguard Worker static bool pointInTriangle(const SkDPoint fPts[3], const SkDPoint& test) {
22*c8dee2aaSAndroid Build Coastguard Worker     SkDVector v0 = fPts[2] - fPts[0];
23*c8dee2aaSAndroid Build Coastguard Worker     SkDVector v1 = fPts[1] - fPts[0];
24*c8dee2aaSAndroid Build Coastguard Worker     SkDVector v2 = test - fPts[0];
25*c8dee2aaSAndroid Build Coastguard Worker     double dot00 = v0.dot(v0);
26*c8dee2aaSAndroid Build Coastguard Worker     double dot01 = v0.dot(v1);
27*c8dee2aaSAndroid Build Coastguard Worker     double dot02 = v0.dot(v2);
28*c8dee2aaSAndroid Build Coastguard Worker     double dot11 = v1.dot(v1);
29*c8dee2aaSAndroid Build Coastguard Worker     double dot12 = v1.dot(v2);
30*c8dee2aaSAndroid Build Coastguard Worker     // Compute barycentric coordinates
31*c8dee2aaSAndroid Build Coastguard Worker     double denom = dot00 * dot11 - dot01 * dot01;
32*c8dee2aaSAndroid Build Coastguard Worker     double u = dot11 * dot02 - dot01 * dot12;
33*c8dee2aaSAndroid Build Coastguard Worker     double v = dot00 * dot12 - dot01 * dot02;
34*c8dee2aaSAndroid Build Coastguard Worker     // Check if point is in triangle
35*c8dee2aaSAndroid Build Coastguard Worker     if (denom >= 0) {
36*c8dee2aaSAndroid Build Coastguard Worker         return u >= 0 && v >= 0 && u + v < denom;
37*c8dee2aaSAndroid Build Coastguard Worker     }
38*c8dee2aaSAndroid Build Coastguard Worker     return u <= 0 && v <= 0 && u + v > denom;
39*c8dee2aaSAndroid Build Coastguard Worker }
40*c8dee2aaSAndroid Build Coastguard Worker 
matchesEnd(const SkDPoint fPts[3],const SkDPoint & test)41*c8dee2aaSAndroid Build Coastguard Worker static bool matchesEnd(const SkDPoint fPts[3], const SkDPoint& test) {
42*c8dee2aaSAndroid Build Coastguard Worker     return fPts[0] == test || fPts[2] == test;
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker /* started with at_most_end_pts_in_common from SkDQuadIntersection.cpp */
46*c8dee2aaSAndroid Build Coastguard Worker // Do a quick reject by rotating all points relative to a line formed by
47*c8dee2aaSAndroid Build Coastguard Worker // a pair of one quad's points. If the 2nd quad's points
48*c8dee2aaSAndroid Build Coastguard Worker // are on the line or on the opposite side from the 1st quad's 'odd man', the
49*c8dee2aaSAndroid Build Coastguard Worker // curves at most intersect at the endpoints.
50*c8dee2aaSAndroid Build Coastguard Worker /* if returning true, check contains true if quad's hull collapsed, making the cubic linear
51*c8dee2aaSAndroid Build Coastguard Worker    if returning false, check contains true if the the quad pair have only the end point in common
52*c8dee2aaSAndroid Build Coastguard Worker */
hullIntersects(const SkDQuad & q2,bool * isLinear) const53*c8dee2aaSAndroid Build Coastguard Worker bool SkDQuad::hullIntersects(const SkDQuad& q2, bool* isLinear) const {
54*c8dee2aaSAndroid Build Coastguard Worker     bool linear = true;
55*c8dee2aaSAndroid Build Coastguard Worker     for (int oddMan = 0; oddMan < kPointCount; ++oddMan) {
56*c8dee2aaSAndroid Build Coastguard Worker         const SkDPoint* endPt[2];
57*c8dee2aaSAndroid Build Coastguard Worker         this->otherPts(oddMan, endPt);
58*c8dee2aaSAndroid Build Coastguard Worker         double origX = endPt[0]->fX;
59*c8dee2aaSAndroid Build Coastguard Worker         double origY = endPt[0]->fY;
60*c8dee2aaSAndroid Build Coastguard Worker         double adj = endPt[1]->fX - origX;
61*c8dee2aaSAndroid Build Coastguard Worker         double opp = endPt[1]->fY - origY;
62*c8dee2aaSAndroid Build Coastguard Worker         double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX) * opp;
63*c8dee2aaSAndroid Build Coastguard Worker         if (approximately_zero(sign)) {
64*c8dee2aaSAndroid Build Coastguard Worker             continue;
65*c8dee2aaSAndroid Build Coastguard Worker         }
66*c8dee2aaSAndroid Build Coastguard Worker         linear = false;
67*c8dee2aaSAndroid Build Coastguard Worker         bool foundOutlier = false;
68*c8dee2aaSAndroid Build Coastguard Worker         for (int n = 0; n < kPointCount; ++n) {
69*c8dee2aaSAndroid Build Coastguard Worker             double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
70*c8dee2aaSAndroid Build Coastguard Worker             if (test * sign > 0 && !precisely_zero(test)) {
71*c8dee2aaSAndroid Build Coastguard Worker                 foundOutlier = true;
72*c8dee2aaSAndroid Build Coastguard Worker                 break;
73*c8dee2aaSAndroid Build Coastguard Worker             }
74*c8dee2aaSAndroid Build Coastguard Worker         }
75*c8dee2aaSAndroid Build Coastguard Worker         if (!foundOutlier) {
76*c8dee2aaSAndroid Build Coastguard Worker             return false;
77*c8dee2aaSAndroid Build Coastguard Worker         }
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker     if (linear && !matchesEnd(fPts, q2.fPts[0]) && !matchesEnd(fPts, q2.fPts[2])) {
80*c8dee2aaSAndroid Build Coastguard Worker         // if the end point of the opposite quad is inside the hull that is nearly a line,
81*c8dee2aaSAndroid Build Coastguard Worker         // then representing the quad as a line may cause the intersection to be missed.
82*c8dee2aaSAndroid Build Coastguard Worker         // Check to see if the endpoint is in the triangle.
83*c8dee2aaSAndroid Build Coastguard Worker         if (pointInTriangle(fPts, q2.fPts[0]) || pointInTriangle(fPts, q2.fPts[2])) {
84*c8dee2aaSAndroid Build Coastguard Worker             linear = false;
85*c8dee2aaSAndroid Build Coastguard Worker         }
86*c8dee2aaSAndroid Build Coastguard Worker     }
87*c8dee2aaSAndroid Build Coastguard Worker     *isLinear = linear;
88*c8dee2aaSAndroid Build Coastguard Worker     return true;
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker 
hullIntersects(const SkDConic & conic,bool * isLinear) const91*c8dee2aaSAndroid Build Coastguard Worker bool SkDQuad::hullIntersects(const SkDConic& conic, bool* isLinear) const {
92*c8dee2aaSAndroid Build Coastguard Worker     return conic.hullIntersects(*this, isLinear);
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker 
hullIntersects(const SkDCubic & cubic,bool * isLinear) const95*c8dee2aaSAndroid Build Coastguard Worker bool SkDQuad::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
96*c8dee2aaSAndroid Build Coastguard Worker     return cubic.hullIntersects(*this, isLinear);
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker /* bit twiddling for finding the off curve index (x&~m is the pair in [0,1,2] excluding oddMan)
100*c8dee2aaSAndroid Build Coastguard Worker oddMan    opp   x=oddMan^opp  x=x-oddMan  m=x>>2   x&~m
101*c8dee2aaSAndroid Build Coastguard Worker     0       1         1            1         0       1
102*c8dee2aaSAndroid Build Coastguard Worker             2         2            2         0       2
103*c8dee2aaSAndroid Build Coastguard Worker     1       1         0           -1        -1       0
104*c8dee2aaSAndroid Build Coastguard Worker             2         3            2         0       2
105*c8dee2aaSAndroid Build Coastguard Worker     2       1         3            1         0       1
106*c8dee2aaSAndroid Build Coastguard Worker             2         0           -2        -1       0
107*c8dee2aaSAndroid Build Coastguard Worker */
otherPts(int oddMan,const SkDPoint * endPt[2]) const108*c8dee2aaSAndroid Build Coastguard Worker void SkDQuad::otherPts(int oddMan, const SkDPoint* endPt[2]) const {
109*c8dee2aaSAndroid Build Coastguard Worker     for (int opp = 1; opp < kPointCount; ++opp) {
110*c8dee2aaSAndroid Build Coastguard Worker         int end = (oddMan ^ opp) - oddMan;  // choose a value not equal to oddMan
111*c8dee2aaSAndroid Build Coastguard Worker         end &= ~(end >> 2);  // if the value went negative, set it to zero
112*c8dee2aaSAndroid Build Coastguard Worker         endPt[opp - 1] = &fPts[end];
113*c8dee2aaSAndroid Build Coastguard Worker     }
114*c8dee2aaSAndroid Build Coastguard Worker }
115*c8dee2aaSAndroid Build Coastguard Worker 
AddValidTs(double s[],int realRoots,double * t)116*c8dee2aaSAndroid Build Coastguard Worker int SkDQuad::AddValidTs(double s[], int realRoots, double* t) {
117*c8dee2aaSAndroid Build Coastguard Worker     int foundRoots = 0;
118*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < realRoots; ++index) {
119*c8dee2aaSAndroid Build Coastguard Worker         double tValue = s[index];
120*c8dee2aaSAndroid Build Coastguard Worker         if (approximately_zero_or_more(tValue) && approximately_one_or_less(tValue)) {
121*c8dee2aaSAndroid Build Coastguard Worker             if (approximately_less_than_zero(tValue)) {
122*c8dee2aaSAndroid Build Coastguard Worker                 tValue = 0;
123*c8dee2aaSAndroid Build Coastguard Worker             } else if (approximately_greater_than_one(tValue)) {
124*c8dee2aaSAndroid Build Coastguard Worker                 tValue = 1;
125*c8dee2aaSAndroid Build Coastguard Worker             }
126*c8dee2aaSAndroid Build Coastguard Worker             for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
127*c8dee2aaSAndroid Build Coastguard Worker                 if (approximately_equal(t[idx2], tValue)) {
128*c8dee2aaSAndroid Build Coastguard Worker                     goto nextRoot;
129*c8dee2aaSAndroid Build Coastguard Worker                 }
130*c8dee2aaSAndroid Build Coastguard Worker             }
131*c8dee2aaSAndroid Build Coastguard Worker             t[foundRoots++] = tValue;
132*c8dee2aaSAndroid Build Coastguard Worker         }
133*c8dee2aaSAndroid Build Coastguard Worker nextRoot:
134*c8dee2aaSAndroid Build Coastguard Worker         {}
135*c8dee2aaSAndroid Build Coastguard Worker     }
136*c8dee2aaSAndroid Build Coastguard Worker     return foundRoots;
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker // note: caller expects multiple results to be sorted smaller first
140*c8dee2aaSAndroid Build Coastguard Worker // note: http://en.wikipedia.org/wiki/Loss_of_significance has an interesting
141*c8dee2aaSAndroid Build Coastguard Worker //  analysis of the quadratic equation, suggesting why the following looks at
142*c8dee2aaSAndroid Build Coastguard Worker //  the sign of B -- and further suggesting that the greatest loss of precision
143*c8dee2aaSAndroid Build Coastguard Worker //  is in b squared less two a c
RootsValidT(double A,double B,double C,double t[2])144*c8dee2aaSAndroid Build Coastguard Worker int SkDQuad::RootsValidT(double A, double B, double C, double t[2]) {
145*c8dee2aaSAndroid Build Coastguard Worker     double s[2];
146*c8dee2aaSAndroid Build Coastguard Worker     int realRoots = RootsReal(A, B, C, s);
147*c8dee2aaSAndroid Build Coastguard Worker     int foundRoots = AddValidTs(s, realRoots, t);
148*c8dee2aaSAndroid Build Coastguard Worker     return foundRoots;
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker 
handle_zero(const double B,const double C,double s[2])151*c8dee2aaSAndroid Build Coastguard Worker static int handle_zero(const double B, const double C, double s[2]) {
152*c8dee2aaSAndroid Build Coastguard Worker     if (approximately_zero(B)) {
153*c8dee2aaSAndroid Build Coastguard Worker         s[0] = 0;
154*c8dee2aaSAndroid Build Coastguard Worker         return C == 0;
155*c8dee2aaSAndroid Build Coastguard Worker     }
156*c8dee2aaSAndroid Build Coastguard Worker     s[0] = -C / B;
157*c8dee2aaSAndroid Build Coastguard Worker     return 1;
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker 
160*c8dee2aaSAndroid Build Coastguard Worker /*
161*c8dee2aaSAndroid Build Coastguard Worker Numeric Solutions (5.6) suggests to solve the quadratic by computing
162*c8dee2aaSAndroid Build Coastguard Worker        Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C))
163*c8dee2aaSAndroid Build Coastguard Worker and using the roots
164*c8dee2aaSAndroid Build Coastguard Worker       t1 = Q / A
165*c8dee2aaSAndroid Build Coastguard Worker       t2 = C / Q
166*c8dee2aaSAndroid Build Coastguard Worker */
167*c8dee2aaSAndroid Build Coastguard Worker // this does not discard real roots <= 0 or >= 1
168*c8dee2aaSAndroid Build Coastguard Worker // TODO(skbug.com/14063) Deduplicate with SkQuads::RootsReal
RootsReal(const double A,const double B,const double C,double s[2])169*c8dee2aaSAndroid Build Coastguard Worker int SkDQuad::RootsReal(const double A, const double B, const double C, double s[2]) {
170*c8dee2aaSAndroid Build Coastguard Worker     if (!A) {
171*c8dee2aaSAndroid Build Coastguard Worker         return handle_zero(B, C, s);
172*c8dee2aaSAndroid Build Coastguard Worker     }
173*c8dee2aaSAndroid Build Coastguard Worker     const double p = B / (2 * A);
174*c8dee2aaSAndroid Build Coastguard Worker     const double q = C / A;
175*c8dee2aaSAndroid Build Coastguard Worker     if (approximately_zero(A) && (approximately_zero_inverse(p) || approximately_zero_inverse(q))) {
176*c8dee2aaSAndroid Build Coastguard Worker         return handle_zero(B, C, s);
177*c8dee2aaSAndroid Build Coastguard Worker     }
178*c8dee2aaSAndroid Build Coastguard Worker     /* normal form: x^2 + px + q = 0 */
179*c8dee2aaSAndroid Build Coastguard Worker     const double p2 = p * p;
180*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostDequalUlps(p2, q) && p2 < q) {
181*c8dee2aaSAndroid Build Coastguard Worker         return 0;
182*c8dee2aaSAndroid Build Coastguard Worker     }
183*c8dee2aaSAndroid Build Coastguard Worker     double sqrt_D = 0;
184*c8dee2aaSAndroid Build Coastguard Worker     if (p2 > q) {
185*c8dee2aaSAndroid Build Coastguard Worker         sqrt_D = sqrt(p2 - q);
186*c8dee2aaSAndroid Build Coastguard Worker     }
187*c8dee2aaSAndroid Build Coastguard Worker     s[0] = sqrt_D - p;
188*c8dee2aaSAndroid Build Coastguard Worker     s[1] = -sqrt_D - p;
189*c8dee2aaSAndroid Build Coastguard Worker     return 1 + !AlmostDequalUlps(s[0], s[1]);
190*c8dee2aaSAndroid Build Coastguard Worker }
191*c8dee2aaSAndroid Build Coastguard Worker 
isLinear(int startIndex,int endIndex) const192*c8dee2aaSAndroid Build Coastguard Worker bool SkDQuad::isLinear(int startIndex, int endIndex) const {
193*c8dee2aaSAndroid Build Coastguard Worker     SkLineParameters lineParameters;
194*c8dee2aaSAndroid Build Coastguard Worker     lineParameters.quadEndPoints(*this, startIndex, endIndex);
195*c8dee2aaSAndroid Build Coastguard Worker     // FIXME: maybe it's possible to avoid this and compare non-normalized
196*c8dee2aaSAndroid Build Coastguard Worker     lineParameters.normalize();
197*c8dee2aaSAndroid Build Coastguard Worker     double distance = lineParameters.controlPtDistance(*this);
198*c8dee2aaSAndroid Build Coastguard Worker     double tiniest = std::min(std::min(std::min(std::min(std::min(fPts[0].fX, fPts[0].fY),
199*c8dee2aaSAndroid Build Coastguard Worker             fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY);
200*c8dee2aaSAndroid Build Coastguard Worker     double largest = std::max(std::max(std::max(std::max(std::max(fPts[0].fX, fPts[0].fY),
201*c8dee2aaSAndroid Build Coastguard Worker             fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY);
202*c8dee2aaSAndroid Build Coastguard Worker     largest = std::max(largest, -tiniest);
203*c8dee2aaSAndroid Build Coastguard Worker     return approximately_zero_when_compared_to(distance, largest);
204*c8dee2aaSAndroid Build Coastguard Worker }
205*c8dee2aaSAndroid Build Coastguard Worker 
dxdyAtT(double t) const206*c8dee2aaSAndroid Build Coastguard Worker SkDVector SkDQuad::dxdyAtT(double t) const {
207*c8dee2aaSAndroid Build Coastguard Worker     double a = t - 1;
208*c8dee2aaSAndroid Build Coastguard Worker     double b = 1 - 2 * t;
209*c8dee2aaSAndroid Build Coastguard Worker     double c = t;
210*c8dee2aaSAndroid Build Coastguard Worker     SkDVector result = { a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX,
211*c8dee2aaSAndroid Build Coastguard Worker             a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY };
212*c8dee2aaSAndroid Build Coastguard Worker     if (result.fX == 0 && result.fY == 0) {
213*c8dee2aaSAndroid Build Coastguard Worker         if (zero_or_one(t)) {
214*c8dee2aaSAndroid Build Coastguard Worker             result = fPts[2] - fPts[0];
215*c8dee2aaSAndroid Build Coastguard Worker         } else {
216*c8dee2aaSAndroid Build Coastguard Worker             // incomplete
217*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("!q");
218*c8dee2aaSAndroid Build Coastguard Worker         }
219*c8dee2aaSAndroid Build Coastguard Worker     }
220*c8dee2aaSAndroid Build Coastguard Worker     return result;
221*c8dee2aaSAndroid Build Coastguard Worker }
222*c8dee2aaSAndroid Build Coastguard Worker 
223*c8dee2aaSAndroid Build Coastguard Worker // OPTIMIZE: assert if caller passes in t == 0 / t == 1 ?
ptAtT(double t) const224*c8dee2aaSAndroid Build Coastguard Worker SkDPoint SkDQuad::ptAtT(double t) const {
225*c8dee2aaSAndroid Build Coastguard Worker     if (0 == t) {
226*c8dee2aaSAndroid Build Coastguard Worker         return fPts[0];
227*c8dee2aaSAndroid Build Coastguard Worker     }
228*c8dee2aaSAndroid Build Coastguard Worker     if (1 == t) {
229*c8dee2aaSAndroid Build Coastguard Worker         return fPts[2];
230*c8dee2aaSAndroid Build Coastguard Worker     }
231*c8dee2aaSAndroid Build Coastguard Worker     double one_t = 1 - t;
232*c8dee2aaSAndroid Build Coastguard Worker     double a = one_t * one_t;
233*c8dee2aaSAndroid Build Coastguard Worker     double b = 2 * one_t * t;
234*c8dee2aaSAndroid Build Coastguard Worker     double c = t * t;
235*c8dee2aaSAndroid Build Coastguard Worker     SkDPoint result = { a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX,
236*c8dee2aaSAndroid Build Coastguard Worker             a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY };
237*c8dee2aaSAndroid Build Coastguard Worker     return result;
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker 
interp_quad_coords(const double * src,double t)240*c8dee2aaSAndroid Build Coastguard Worker static double interp_quad_coords(const double* src, double t) {
241*c8dee2aaSAndroid Build Coastguard Worker     if (0 == t) {
242*c8dee2aaSAndroid Build Coastguard Worker         return src[0];
243*c8dee2aaSAndroid Build Coastguard Worker     }
244*c8dee2aaSAndroid Build Coastguard Worker     if (1 == t) {
245*c8dee2aaSAndroid Build Coastguard Worker         return src[4];
246*c8dee2aaSAndroid Build Coastguard Worker     }
247*c8dee2aaSAndroid Build Coastguard Worker     double ab = SkDInterp(src[0], src[2], t);
248*c8dee2aaSAndroid Build Coastguard Worker     double bc = SkDInterp(src[2], src[4], t);
249*c8dee2aaSAndroid Build Coastguard Worker     double abc = SkDInterp(ab, bc, t);
250*c8dee2aaSAndroid Build Coastguard Worker     return abc;
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker 
monotonicInX() const253*c8dee2aaSAndroid Build Coastguard Worker bool SkDQuad::monotonicInX() const {
254*c8dee2aaSAndroid Build Coastguard Worker     return between(fPts[0].fX, fPts[1].fX, fPts[2].fX);
255*c8dee2aaSAndroid Build Coastguard Worker }
256*c8dee2aaSAndroid Build Coastguard Worker 
monotonicInY() const257*c8dee2aaSAndroid Build Coastguard Worker bool SkDQuad::monotonicInY() const {
258*c8dee2aaSAndroid Build Coastguard Worker     return between(fPts[0].fY, fPts[1].fY, fPts[2].fY);
259*c8dee2aaSAndroid Build Coastguard Worker }
260*c8dee2aaSAndroid Build Coastguard Worker 
261*c8dee2aaSAndroid Build Coastguard Worker /*
262*c8dee2aaSAndroid Build Coastguard Worker Given a quadratic q, t1, and t2, find a small quadratic segment.
263*c8dee2aaSAndroid Build Coastguard Worker 
264*c8dee2aaSAndroid Build Coastguard Worker The new quadratic is defined by A, B, and C, where
265*c8dee2aaSAndroid Build Coastguard Worker  A = c[0]*(1 - t1)*(1 - t1) + 2*c[1]*t1*(1 - t1) + c[2]*t1*t1
266*c8dee2aaSAndroid Build Coastguard Worker  C = c[3]*(1 - t1)*(1 - t1) + 2*c[2]*t1*(1 - t1) + c[1]*t1*t1
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker To find B, compute the point halfway between t1 and t2:
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker q(at (t1 + t2)/2) == D
271*c8dee2aaSAndroid Build Coastguard Worker 
272*c8dee2aaSAndroid Build Coastguard Worker Next, compute where D must be if we know the value of B:
273*c8dee2aaSAndroid Build Coastguard Worker 
274*c8dee2aaSAndroid Build Coastguard Worker _12 = A/2 + B/2
275*c8dee2aaSAndroid Build Coastguard Worker 12_ = B/2 + C/2
276*c8dee2aaSAndroid Build Coastguard Worker 123 = A/4 + B/2 + C/4
277*c8dee2aaSAndroid Build Coastguard Worker     = D
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker Group the known values on one side:
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker B   = D*2 - A/2 - C/2
282*c8dee2aaSAndroid Build Coastguard Worker */
283*c8dee2aaSAndroid Build Coastguard Worker 
284*c8dee2aaSAndroid Build Coastguard Worker // OPTIMIZE? : special case  t1 = 1 && t2 = 0
subDivide(double t1,double t2) const285*c8dee2aaSAndroid Build Coastguard Worker SkDQuad SkDQuad::subDivide(double t1, double t2) const {
286*c8dee2aaSAndroid Build Coastguard Worker     if (0 == t1 && 1 == t2) {
287*c8dee2aaSAndroid Build Coastguard Worker         return *this;
288*c8dee2aaSAndroid Build Coastguard Worker     }
289*c8dee2aaSAndroid Build Coastguard Worker     SkDQuad dst;
290*c8dee2aaSAndroid Build Coastguard Worker     double ax = dst[0].fX = interp_quad_coords(&fPts[0].fX, t1);
291*c8dee2aaSAndroid Build Coastguard Worker     double ay = dst[0].fY = interp_quad_coords(&fPts[0].fY, t1);
292*c8dee2aaSAndroid Build Coastguard Worker     double dx = interp_quad_coords(&fPts[0].fX, (t1 + t2) / 2);
293*c8dee2aaSAndroid Build Coastguard Worker     double dy = interp_quad_coords(&fPts[0].fY, (t1 + t2) / 2);
294*c8dee2aaSAndroid Build Coastguard Worker     double cx = dst[2].fX = interp_quad_coords(&fPts[0].fX, t2);
295*c8dee2aaSAndroid Build Coastguard Worker     double cy = dst[2].fY = interp_quad_coords(&fPts[0].fY, t2);
296*c8dee2aaSAndroid Build Coastguard Worker     /* bx = */ dst[1].fX = 2 * dx - (ax + cx) / 2;
297*c8dee2aaSAndroid Build Coastguard Worker     /* by = */ dst[1].fY = 2 * dy - (ay + cy) / 2;
298*c8dee2aaSAndroid Build Coastguard Worker     return dst;
299*c8dee2aaSAndroid Build Coastguard Worker }
300*c8dee2aaSAndroid Build Coastguard Worker 
align(int endIndex,SkDPoint * dstPt) const301*c8dee2aaSAndroid Build Coastguard Worker void SkDQuad::align(int endIndex, SkDPoint* dstPt) const {
302*c8dee2aaSAndroid Build Coastguard Worker     if (fPts[endIndex].fX == fPts[1].fX) {
303*c8dee2aaSAndroid Build Coastguard Worker         dstPt->fX = fPts[endIndex].fX;
304*c8dee2aaSAndroid Build Coastguard Worker     }
305*c8dee2aaSAndroid Build Coastguard Worker     if (fPts[endIndex].fY == fPts[1].fY) {
306*c8dee2aaSAndroid Build Coastguard Worker         dstPt->fY = fPts[endIndex].fY;
307*c8dee2aaSAndroid Build Coastguard Worker     }
308*c8dee2aaSAndroid Build Coastguard Worker }
309*c8dee2aaSAndroid Build Coastguard Worker 
subDivide(const SkDPoint & a,const SkDPoint & c,double t1,double t2) const310*c8dee2aaSAndroid Build Coastguard Worker SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2) const {
311*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(t1 != t2);
312*c8dee2aaSAndroid Build Coastguard Worker     SkDPoint b;
313*c8dee2aaSAndroid Build Coastguard Worker     SkDQuad sub = subDivide(t1, t2);
314*c8dee2aaSAndroid Build Coastguard Worker     SkDLine b0 = {{a, sub[1] + (a - sub[0])}};
315*c8dee2aaSAndroid Build Coastguard Worker     SkDLine b1 = {{c, sub[1] + (c - sub[2])}};
316*c8dee2aaSAndroid Build Coastguard Worker     SkIntersections i;
317*c8dee2aaSAndroid Build Coastguard Worker     i.intersectRay(b0, b1);
318*c8dee2aaSAndroid Build Coastguard Worker     if (i.used() == 1 && i[0][0] >= 0 && i[1][0] >= 0) {
319*c8dee2aaSAndroid Build Coastguard Worker         b = i.pt(0);
320*c8dee2aaSAndroid Build Coastguard Worker     } else {
321*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(i.used() <= 2);
322*c8dee2aaSAndroid Build Coastguard Worker         return SkDPoint::Mid(b0[1], b1[1]);
323*c8dee2aaSAndroid Build Coastguard Worker     }
324*c8dee2aaSAndroid Build Coastguard Worker     if (t1 == 0 || t2 == 0) {
325*c8dee2aaSAndroid Build Coastguard Worker         align(0, &b);
326*c8dee2aaSAndroid Build Coastguard Worker     }
327*c8dee2aaSAndroid Build Coastguard Worker     if (t1 == 1 || t2 == 1) {
328*c8dee2aaSAndroid Build Coastguard Worker         align(2, &b);
329*c8dee2aaSAndroid Build Coastguard Worker     }
330*c8dee2aaSAndroid Build Coastguard Worker     if (AlmostBequalUlps(b.fX, a.fX)) {
331*c8dee2aaSAndroid Build Coastguard Worker         b.fX = a.fX;
332*c8dee2aaSAndroid Build Coastguard Worker     } else if (AlmostBequalUlps(b.fX, c.fX)) {
333*c8dee2aaSAndroid Build Coastguard Worker         b.fX = c.fX;
334*c8dee2aaSAndroid Build Coastguard Worker     }
335*c8dee2aaSAndroid Build Coastguard Worker     if (AlmostBequalUlps(b.fY, a.fY)) {
336*c8dee2aaSAndroid Build Coastguard Worker         b.fY = a.fY;
337*c8dee2aaSAndroid Build Coastguard Worker     } else if (AlmostBequalUlps(b.fY, c.fY)) {
338*c8dee2aaSAndroid Build Coastguard Worker         b.fY = c.fY;
339*c8dee2aaSAndroid Build Coastguard Worker     }
340*c8dee2aaSAndroid Build Coastguard Worker     return b;
341*c8dee2aaSAndroid Build Coastguard Worker }
342*c8dee2aaSAndroid Build Coastguard Worker 
343*c8dee2aaSAndroid Build Coastguard Worker /* classic one t subdivision */
interp_quad_coords(const double * src,double * dst,double t)344*c8dee2aaSAndroid Build Coastguard Worker static void interp_quad_coords(const double* src, double* dst, double t) {
345*c8dee2aaSAndroid Build Coastguard Worker     double ab = SkDInterp(src[0], src[2], t);
346*c8dee2aaSAndroid Build Coastguard Worker     double bc = SkDInterp(src[2], src[4], t);
347*c8dee2aaSAndroid Build Coastguard Worker     dst[0] = src[0];
348*c8dee2aaSAndroid Build Coastguard Worker     dst[2] = ab;
349*c8dee2aaSAndroid Build Coastguard Worker     dst[4] = SkDInterp(ab, bc, t);
350*c8dee2aaSAndroid Build Coastguard Worker     dst[6] = bc;
351*c8dee2aaSAndroid Build Coastguard Worker     dst[8] = src[4];
352*c8dee2aaSAndroid Build Coastguard Worker }
353*c8dee2aaSAndroid Build Coastguard Worker 
chopAt(double t) const354*c8dee2aaSAndroid Build Coastguard Worker SkDQuadPair SkDQuad::chopAt(double t) const
355*c8dee2aaSAndroid Build Coastguard Worker {
356*c8dee2aaSAndroid Build Coastguard Worker     SkDQuadPair dst;
357*c8dee2aaSAndroid Build Coastguard Worker     interp_quad_coords(&fPts[0].fX, &dst.pts[0].fX, t);
358*c8dee2aaSAndroid Build Coastguard Worker     interp_quad_coords(&fPts[0].fY, &dst.pts[0].fY, t);
359*c8dee2aaSAndroid Build Coastguard Worker     return dst;
360*c8dee2aaSAndroid Build Coastguard Worker }
361*c8dee2aaSAndroid Build Coastguard Worker 
valid_unit_divide(double numer,double denom,double * ratio)362*c8dee2aaSAndroid Build Coastguard Worker static int valid_unit_divide(double numer, double denom, double* ratio)
363*c8dee2aaSAndroid Build Coastguard Worker {
364*c8dee2aaSAndroid Build Coastguard Worker     if (numer < 0) {
365*c8dee2aaSAndroid Build Coastguard Worker         numer = -numer;
366*c8dee2aaSAndroid Build Coastguard Worker         denom = -denom;
367*c8dee2aaSAndroid Build Coastguard Worker     }
368*c8dee2aaSAndroid Build Coastguard Worker     if (denom == 0 || numer == 0 || numer >= denom) {
369*c8dee2aaSAndroid Build Coastguard Worker         return 0;
370*c8dee2aaSAndroid Build Coastguard Worker     }
371*c8dee2aaSAndroid Build Coastguard Worker     double r = numer / denom;
372*c8dee2aaSAndroid Build Coastguard Worker     if (r == 0) {  // catch underflow if numer <<<< denom
373*c8dee2aaSAndroid Build Coastguard Worker         return 0;
374*c8dee2aaSAndroid Build Coastguard Worker     }
375*c8dee2aaSAndroid Build Coastguard Worker     *ratio = r;
376*c8dee2aaSAndroid Build Coastguard Worker     return 1;
377*c8dee2aaSAndroid Build Coastguard Worker }
378*c8dee2aaSAndroid Build Coastguard Worker 
379*c8dee2aaSAndroid Build Coastguard Worker /** Quad'(t) = At + B, where
380*c8dee2aaSAndroid Build Coastguard Worker     A = 2(a - 2b + c)
381*c8dee2aaSAndroid Build Coastguard Worker     B = 2(b - a)
382*c8dee2aaSAndroid Build Coastguard Worker     Solve for t, only if it fits between 0 < t < 1
383*c8dee2aaSAndroid Build Coastguard Worker */
FindExtrema(const double src[],double tValue[1])384*c8dee2aaSAndroid Build Coastguard Worker int SkDQuad::FindExtrema(const double src[], double tValue[1]) {
385*c8dee2aaSAndroid Build Coastguard Worker     /*  At + B == 0
386*c8dee2aaSAndroid Build Coastguard Worker         t = -B / A
387*c8dee2aaSAndroid Build Coastguard Worker     */
388*c8dee2aaSAndroid Build Coastguard Worker     double a = src[0];
389*c8dee2aaSAndroid Build Coastguard Worker     double b = src[2];
390*c8dee2aaSAndroid Build Coastguard Worker     double c = src[4];
391*c8dee2aaSAndroid Build Coastguard Worker     return valid_unit_divide(a - b, a - b - b + c, tValue);
392*c8dee2aaSAndroid Build Coastguard Worker }
393*c8dee2aaSAndroid Build Coastguard Worker 
394*c8dee2aaSAndroid Build Coastguard Worker /* Parameterization form, given A*t*t + 2*B*t*(1-t) + C*(1-t)*(1-t)
395*c8dee2aaSAndroid Build Coastguard Worker  *
396*c8dee2aaSAndroid Build Coastguard Worker  * a = A - 2*B +   C
397*c8dee2aaSAndroid Build Coastguard Worker  * b =     2*B - 2*C
398*c8dee2aaSAndroid Build Coastguard Worker  * c =             C
399*c8dee2aaSAndroid Build Coastguard Worker  */
SetABC(const double * quad,double * a,double * b,double * c)400*c8dee2aaSAndroid Build Coastguard Worker void SkDQuad::SetABC(const double* quad, double* a, double* b, double* c) {
401*c8dee2aaSAndroid Build Coastguard Worker     *a = quad[0];      // a = A
402*c8dee2aaSAndroid Build Coastguard Worker     *b = 2 * quad[2];  // b =     2*B
403*c8dee2aaSAndroid Build Coastguard Worker     *c = quad[4];      // c =             C
404*c8dee2aaSAndroid Build Coastguard Worker     *b -= *c;          // b =     2*B -   C
405*c8dee2aaSAndroid Build Coastguard Worker     *a -= *b;          // a = A - 2*B +   C
406*c8dee2aaSAndroid Build Coastguard Worker     *b -= *c;          // b =     2*B - 2*C
407*c8dee2aaSAndroid Build Coastguard Worker }
408*c8dee2aaSAndroid Build Coastguard Worker 
intersectRay(SkIntersections * i,const SkDLine & line) const409*c8dee2aaSAndroid Build Coastguard Worker int SkTQuad::intersectRay(SkIntersections* i, const SkDLine& line) const {
410*c8dee2aaSAndroid Build Coastguard Worker     return i->intersectRay(fQuad, line);
411*c8dee2aaSAndroid Build Coastguard Worker }
412*c8dee2aaSAndroid Build Coastguard Worker 
hullIntersects(const SkDConic & conic,bool * isLinear) const413*c8dee2aaSAndroid Build Coastguard Worker bool SkTQuad::hullIntersects(const SkDConic& conic, bool* isLinear) const  {
414*c8dee2aaSAndroid Build Coastguard Worker     return conic.hullIntersects(fQuad, isLinear);
415*c8dee2aaSAndroid Build Coastguard Worker }
416*c8dee2aaSAndroid Build Coastguard Worker 
hullIntersects(const SkDCubic & cubic,bool * isLinear) const417*c8dee2aaSAndroid Build Coastguard Worker bool SkTQuad::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
418*c8dee2aaSAndroid Build Coastguard Worker     return cubic.hullIntersects(fQuad, isLinear);
419*c8dee2aaSAndroid Build Coastguard Worker }
420*c8dee2aaSAndroid Build Coastguard Worker 
setBounds(SkDRect * rect) const421*c8dee2aaSAndroid Build Coastguard Worker void SkTQuad::setBounds(SkDRect* rect) const {
422*c8dee2aaSAndroid Build Coastguard Worker     rect->setBounds(fQuad);
423*c8dee2aaSAndroid Build Coastguard Worker }
424