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