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