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/SkPathOpsCurve.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsQuad.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci/*
13cb93a386Sopenharmony_ciFind the interection of a line and quadratic by solving for valid t values.
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ciFrom http://stackoverflow.com/questions/1853637/how-to-find-the-mathematical-function-defining-a-bezier-curve
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci"A Bezier curve is a parametric function. A quadratic Bezier curve (i.e. three
18cb93a386Sopenharmony_cicontrol points) can be expressed as: F(t) = A(1 - t)^2 + B(1 - t)t + Ct^2 where
19cb93a386Sopenharmony_ciA, B and C are points and t goes from zero to one.
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ciThis will give you two equations:
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ci  x = a(1 - t)^2 + b(1 - t)t + ct^2
24cb93a386Sopenharmony_ci  y = d(1 - t)^2 + e(1 - t)t + ft^2
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ciIf you add for instance the line equation (y = kx + m) to that, you'll end up
27cb93a386Sopenharmony_ciwith three equations and three unknowns (x, y and t)."
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ciSimilar to above, the quadratic is represented as
30cb93a386Sopenharmony_ci  x = a(1-t)^2 + 2b(1-t)t + ct^2
31cb93a386Sopenharmony_ci  y = d(1-t)^2 + 2e(1-t)t + ft^2
32cb93a386Sopenharmony_ciand the line as
33cb93a386Sopenharmony_ci  y = g*x + h
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ciUsing Mathematica, solve for the values of t where the quadratic intersects the
36cb93a386Sopenharmony_ciline:
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci  (in)  t1 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - x,
39cb93a386Sopenharmony_ci                       d*(1 - t)^2 + 2*e*(1 - t)*t  + f*t^2 - g*x - h, x]
40cb93a386Sopenharmony_ci  (out) -d + h + 2 d t - 2 e t - d t^2 + 2 e t^2 - f t^2 +
41cb93a386Sopenharmony_ci         g  (a - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2)
42cb93a386Sopenharmony_ci  (in)  Solve[t1 == 0, t]
43cb93a386Sopenharmony_ci  (out) {
44cb93a386Sopenharmony_ci    {t -> (-2 d + 2 e +   2 a g - 2 b g    -
45cb93a386Sopenharmony_ci      Sqrt[(2 d - 2 e -   2 a g + 2 b g)^2 -
46cb93a386Sopenharmony_ci          4 (-d + 2 e - f + a g - 2 b g    + c g) (-d + a g + h)]) /
47cb93a386Sopenharmony_ci         (2 (-d + 2 e - f + a g - 2 b g    + c g))
48cb93a386Sopenharmony_ci         },
49cb93a386Sopenharmony_ci    {t -> (-2 d + 2 e +   2 a g - 2 b g    +
50cb93a386Sopenharmony_ci      Sqrt[(2 d - 2 e -   2 a g + 2 b g)^2 -
51cb93a386Sopenharmony_ci          4 (-d + 2 e - f + a g - 2 b g    + c g) (-d + a g + h)]) /
52cb93a386Sopenharmony_ci         (2 (-d + 2 e - f + a g - 2 b g    + c g))
53cb93a386Sopenharmony_ci         }
54cb93a386Sopenharmony_ci        }
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ciUsing the results above (when the line tends towards horizontal)
57cb93a386Sopenharmony_ci       A =   (-(d - 2*e + f) + g*(a - 2*b + c)     )
58cb93a386Sopenharmony_ci       B = 2*( (d -   e    ) - g*(a -   b    )     )
59cb93a386Sopenharmony_ci       C =   (-(d          ) + g*(a          ) + h )
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ciIf g goes to infinity, we can rewrite the line in terms of x.
62cb93a386Sopenharmony_ci  x = g'*y + h'
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciAnd solve accordingly in Mathematica:
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci  (in)  t2 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - g'*y - h',
67cb93a386Sopenharmony_ci                       d*(1 - t)^2 + 2*e*(1 - t)*t  + f*t^2 - y, y]
68cb93a386Sopenharmony_ci  (out)  a - h' - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2 -
69cb93a386Sopenharmony_ci         g'  (d - 2 d t + 2 e t + d t^2 - 2 e t^2 + f t^2)
70cb93a386Sopenharmony_ci  (in)  Solve[t2 == 0, t]
71cb93a386Sopenharmony_ci  (out) {
72cb93a386Sopenharmony_ci    {t -> (2 a - 2 b -   2 d g' + 2 e g'    -
73cb93a386Sopenharmony_ci    Sqrt[(-2 a + 2 b +   2 d g' - 2 e g')^2 -
74cb93a386Sopenharmony_ci          4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')]) /
75cb93a386Sopenharmony_ci         (2 (a - 2 b + c - d g' + 2 e g' - f g'))
76cb93a386Sopenharmony_ci         },
77cb93a386Sopenharmony_ci    {t -> (2 a - 2 b -   2 d g' + 2 e g'    +
78cb93a386Sopenharmony_ci    Sqrt[(-2 a + 2 b +   2 d g' - 2 e g')^2 -
79cb93a386Sopenharmony_ci          4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')])/
80cb93a386Sopenharmony_ci         (2 (a - 2 b + c - d g' + 2 e g' - f g'))
81cb93a386Sopenharmony_ci         }
82cb93a386Sopenharmony_ci        }
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ciThus, if the slope of the line tends towards vertical, we use:
85cb93a386Sopenharmony_ci       A =   ( (a - 2*b + c) - g'*(d  - 2*e + f)      )
86cb93a386Sopenharmony_ci       B = 2*(-(a -   b    ) + g'*(d  -   e    )      )
87cb93a386Sopenharmony_ci       C =   ( (a          ) - g'*(d           ) - h' )
88cb93a386Sopenharmony_ci */
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ciclass LineQuadraticIntersections {
91cb93a386Sopenharmony_cipublic:
92cb93a386Sopenharmony_ci    enum PinTPoint {
93cb93a386Sopenharmony_ci        kPointUninitialized,
94cb93a386Sopenharmony_ci        kPointInitialized
95cb93a386Sopenharmony_ci    };
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci    LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersections* i)
98cb93a386Sopenharmony_ci        : fQuad(q)
99cb93a386Sopenharmony_ci        , fLine(&l)
100cb93a386Sopenharmony_ci        , fIntersections(i)
101cb93a386Sopenharmony_ci        , fAllowNear(true) {
102cb93a386Sopenharmony_ci        i->setMax(5);  // allow short partial coincidence plus discrete intersections
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci    LineQuadraticIntersections(const SkDQuad& q)
106cb93a386Sopenharmony_ci        : fQuad(q)
107cb93a386Sopenharmony_ci        SkDEBUGPARAMS(fLine(nullptr))
108cb93a386Sopenharmony_ci        SkDEBUGPARAMS(fIntersections(nullptr))
109cb93a386Sopenharmony_ci        SkDEBUGPARAMS(fAllowNear(false)) {
110cb93a386Sopenharmony_ci    }
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    void allowNear(bool allow) {
113cb93a386Sopenharmony_ci        fAllowNear = allow;
114cb93a386Sopenharmony_ci    }
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci    void checkCoincident() {
117cb93a386Sopenharmony_ci        int last = fIntersections->used() - 1;
118cb93a386Sopenharmony_ci        for (int index = 0; index < last; ) {
119cb93a386Sopenharmony_ci            double quadMidT = ((*fIntersections)[0][index] + (*fIntersections)[0][index + 1]) / 2;
120cb93a386Sopenharmony_ci            SkDPoint quadMidPt = fQuad.ptAtT(quadMidT);
121cb93a386Sopenharmony_ci            double t = fLine->nearPoint(quadMidPt, nullptr);
122cb93a386Sopenharmony_ci            if (t < 0) {
123cb93a386Sopenharmony_ci                ++index;
124cb93a386Sopenharmony_ci                continue;
125cb93a386Sopenharmony_ci            }
126cb93a386Sopenharmony_ci            if (fIntersections->isCoincident(index)) {
127cb93a386Sopenharmony_ci                fIntersections->removeOne(index);
128cb93a386Sopenharmony_ci                --last;
129cb93a386Sopenharmony_ci            } else if (fIntersections->isCoincident(index + 1)) {
130cb93a386Sopenharmony_ci                fIntersections->removeOne(index + 1);
131cb93a386Sopenharmony_ci                --last;
132cb93a386Sopenharmony_ci            } else {
133cb93a386Sopenharmony_ci                fIntersections->setCoincident(index++);
134cb93a386Sopenharmony_ci            }
135cb93a386Sopenharmony_ci            fIntersections->setCoincident(index);
136cb93a386Sopenharmony_ci        }
137cb93a386Sopenharmony_ci    }
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    int intersectRay(double roots[2]) {
140cb93a386Sopenharmony_ci    /*
141cb93a386Sopenharmony_ci        solve by rotating line+quad so line is horizontal, then finding the roots
142cb93a386Sopenharmony_ci        set up matrix to rotate quad to x-axis
143cb93a386Sopenharmony_ci        |cos(a) -sin(a)|
144cb93a386Sopenharmony_ci        |sin(a)  cos(a)|
145cb93a386Sopenharmony_ci        note that cos(a) = A(djacent) / Hypoteneuse
146cb93a386Sopenharmony_ci                  sin(a) = O(pposite) / Hypoteneuse
147cb93a386Sopenharmony_ci        since we are computing Ts, we can ignore hypoteneuse, the scale factor:
148cb93a386Sopenharmony_ci        |  A     -O    |
149cb93a386Sopenharmony_ci        |  O      A    |
150cb93a386Sopenharmony_ci        A = line[1].fX - line[0].fX (adjacent side of the right triangle)
151cb93a386Sopenharmony_ci        O = line[1].fY - line[0].fY (opposite side of the right triangle)
152cb93a386Sopenharmony_ci        for each of the three points (e.g. n = 0 to 2)
153cb93a386Sopenharmony_ci        quad[n].fY' = (quad[n].fY - line[0].fY) * A - (quad[n].fX - line[0].fX) * O
154cb93a386Sopenharmony_ci    */
155cb93a386Sopenharmony_ci        double adj = (*fLine)[1].fX - (*fLine)[0].fX;
156cb93a386Sopenharmony_ci        double opp = (*fLine)[1].fY - (*fLine)[0].fY;
157cb93a386Sopenharmony_ci        double r[3];
158cb93a386Sopenharmony_ci        for (int n = 0; n < 3; ++n) {
159cb93a386Sopenharmony_ci            r[n] = (fQuad[n].fY - (*fLine)[0].fY) * adj - (fQuad[n].fX - (*fLine)[0].fX) * opp;
160cb93a386Sopenharmony_ci        }
161cb93a386Sopenharmony_ci        double A = r[2];
162cb93a386Sopenharmony_ci        double B = r[1];
163cb93a386Sopenharmony_ci        double C = r[0];
164cb93a386Sopenharmony_ci        A += C - 2 * B;  // A = a - 2*b + c
165cb93a386Sopenharmony_ci        B -= C;  // B = -(b - c)
166cb93a386Sopenharmony_ci        return SkDQuad::RootsValidT(A, 2 * B, C, roots);
167cb93a386Sopenharmony_ci    }
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci    int intersect() {
170cb93a386Sopenharmony_ci        addExactEndPoints();
171cb93a386Sopenharmony_ci        if (fAllowNear) {
172cb93a386Sopenharmony_ci            addNearEndPoints();
173cb93a386Sopenharmony_ci        }
174cb93a386Sopenharmony_ci        double rootVals[2];
175cb93a386Sopenharmony_ci        int roots = intersectRay(rootVals);
176cb93a386Sopenharmony_ci        for (int index = 0; index < roots; ++index) {
177cb93a386Sopenharmony_ci            double quadT = rootVals[index];
178cb93a386Sopenharmony_ci            double lineT = findLineT(quadT);
179cb93a386Sopenharmony_ci            SkDPoint pt;
180cb93a386Sopenharmony_ci            if (pinTs(&quadT, &lineT, &pt, kPointUninitialized) && uniqueAnswer(quadT, pt)) {
181cb93a386Sopenharmony_ci                fIntersections->insert(quadT, lineT, pt);
182cb93a386Sopenharmony_ci            }
183cb93a386Sopenharmony_ci        }
184cb93a386Sopenharmony_ci        checkCoincident();
185cb93a386Sopenharmony_ci        return fIntersections->used();
186cb93a386Sopenharmony_ci    }
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci    int horizontalIntersect(double axisIntercept, double roots[2]) {
189cb93a386Sopenharmony_ci        double D = fQuad[2].fY;  // f
190cb93a386Sopenharmony_ci        double E = fQuad[1].fY;  // e
191cb93a386Sopenharmony_ci        double F = fQuad[0].fY;  // d
192cb93a386Sopenharmony_ci        D += F - 2 * E;         // D = d - 2*e + f
193cb93a386Sopenharmony_ci        E -= F;                 // E = -(d - e)
194cb93a386Sopenharmony_ci        F -= axisIntercept;
195cb93a386Sopenharmony_ci        return SkDQuad::RootsValidT(D, 2 * E, F, roots);
196cb93a386Sopenharmony_ci    }
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ci    int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) {
199cb93a386Sopenharmony_ci        addExactHorizontalEndPoints(left, right, axisIntercept);
200cb93a386Sopenharmony_ci        if (fAllowNear) {
201cb93a386Sopenharmony_ci            addNearHorizontalEndPoints(left, right, axisIntercept);
202cb93a386Sopenharmony_ci        }
203cb93a386Sopenharmony_ci        double rootVals[2];
204cb93a386Sopenharmony_ci        int roots = horizontalIntersect(axisIntercept, rootVals);
205cb93a386Sopenharmony_ci        for (int index = 0; index < roots; ++index) {
206cb93a386Sopenharmony_ci            double quadT = rootVals[index];
207cb93a386Sopenharmony_ci            SkDPoint pt = fQuad.ptAtT(quadT);
208cb93a386Sopenharmony_ci            double lineT = (pt.fX - left) / (right - left);
209cb93a386Sopenharmony_ci            if (pinTs(&quadT, &lineT, &pt, kPointInitialized) && uniqueAnswer(quadT, pt)) {
210cb93a386Sopenharmony_ci                fIntersections->insert(quadT, lineT, pt);
211cb93a386Sopenharmony_ci            }
212cb93a386Sopenharmony_ci        }
213cb93a386Sopenharmony_ci        if (flipped) {
214cb93a386Sopenharmony_ci            fIntersections->flip();
215cb93a386Sopenharmony_ci        }
216cb93a386Sopenharmony_ci        checkCoincident();
217cb93a386Sopenharmony_ci        return fIntersections->used();
218cb93a386Sopenharmony_ci    }
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    bool uniqueAnswer(double quadT, const SkDPoint& pt) {
221cb93a386Sopenharmony_ci        for (int inner = 0; inner < fIntersections->used(); ++inner) {
222cb93a386Sopenharmony_ci            if (fIntersections->pt(inner) != pt) {
223cb93a386Sopenharmony_ci                continue;
224cb93a386Sopenharmony_ci            }
225cb93a386Sopenharmony_ci            double existingQuadT = (*fIntersections)[0][inner];
226cb93a386Sopenharmony_ci            if (quadT == existingQuadT) {
227cb93a386Sopenharmony_ci                return false;
228cb93a386Sopenharmony_ci            }
229cb93a386Sopenharmony_ci            // check if midway on quad is also same point. If so, discard this
230cb93a386Sopenharmony_ci            double quadMidT = (existingQuadT + quadT) / 2;
231cb93a386Sopenharmony_ci            SkDPoint quadMidPt = fQuad.ptAtT(quadMidT);
232cb93a386Sopenharmony_ci            if (quadMidPt.approximatelyEqual(pt)) {
233cb93a386Sopenharmony_ci                return false;
234cb93a386Sopenharmony_ci            }
235cb93a386Sopenharmony_ci        }
236cb93a386Sopenharmony_ci#if ONE_OFF_DEBUG
237cb93a386Sopenharmony_ci        SkDPoint qPt = fQuad.ptAtT(quadT);
238cb93a386Sopenharmony_ci        SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY,
239cb93a386Sopenharmony_ci                qPt.fX, qPt.fY);
240cb93a386Sopenharmony_ci#endif
241cb93a386Sopenharmony_ci        return true;
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci    int verticalIntersect(double axisIntercept, double roots[2]) {
245cb93a386Sopenharmony_ci        double D = fQuad[2].fX;  // f
246cb93a386Sopenharmony_ci        double E = fQuad[1].fX;  // e
247cb93a386Sopenharmony_ci        double F = fQuad[0].fX;  // d
248cb93a386Sopenharmony_ci        D += F - 2 * E;         // D = d - 2*e + f
249cb93a386Sopenharmony_ci        E -= F;                 // E = -(d - e)
250cb93a386Sopenharmony_ci        F -= axisIntercept;
251cb93a386Sopenharmony_ci        return SkDQuad::RootsValidT(D, 2 * E, F, roots);
252cb93a386Sopenharmony_ci    }
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci    int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
255cb93a386Sopenharmony_ci        addExactVerticalEndPoints(top, bottom, axisIntercept);
256cb93a386Sopenharmony_ci        if (fAllowNear) {
257cb93a386Sopenharmony_ci            addNearVerticalEndPoints(top, bottom, axisIntercept);
258cb93a386Sopenharmony_ci        }
259cb93a386Sopenharmony_ci        double rootVals[2];
260cb93a386Sopenharmony_ci        int roots = verticalIntersect(axisIntercept, rootVals);
261cb93a386Sopenharmony_ci        for (int index = 0; index < roots; ++index) {
262cb93a386Sopenharmony_ci            double quadT = rootVals[index];
263cb93a386Sopenharmony_ci            SkDPoint pt = fQuad.ptAtT(quadT);
264cb93a386Sopenharmony_ci            double lineT = (pt.fY - top) / (bottom - top);
265cb93a386Sopenharmony_ci            if (pinTs(&quadT, &lineT, &pt, kPointInitialized) && uniqueAnswer(quadT, pt)) {
266cb93a386Sopenharmony_ci                fIntersections->insert(quadT, lineT, pt);
267cb93a386Sopenharmony_ci            }
268cb93a386Sopenharmony_ci        }
269cb93a386Sopenharmony_ci        if (flipped) {
270cb93a386Sopenharmony_ci            fIntersections->flip();
271cb93a386Sopenharmony_ci        }
272cb93a386Sopenharmony_ci        checkCoincident();
273cb93a386Sopenharmony_ci        return fIntersections->used();
274cb93a386Sopenharmony_ci    }
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ciprotected:
277cb93a386Sopenharmony_ci    // add endpoints first to get zero and one t values exactly
278cb93a386Sopenharmony_ci    void addExactEndPoints() {
279cb93a386Sopenharmony_ci        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
280cb93a386Sopenharmony_ci            double lineT = fLine->exactPoint(fQuad[qIndex]);
281cb93a386Sopenharmony_ci            if (lineT < 0) {
282cb93a386Sopenharmony_ci                continue;
283cb93a386Sopenharmony_ci            }
284cb93a386Sopenharmony_ci            double quadT = (double) (qIndex >> 1);
285cb93a386Sopenharmony_ci            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
286cb93a386Sopenharmony_ci        }
287cb93a386Sopenharmony_ci    }
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    void addNearEndPoints() {
290cb93a386Sopenharmony_ci        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
291cb93a386Sopenharmony_ci            double quadT = (double) (qIndex >> 1);
292cb93a386Sopenharmony_ci            if (fIntersections->hasT(quadT)) {
293cb93a386Sopenharmony_ci                continue;
294cb93a386Sopenharmony_ci            }
295cb93a386Sopenharmony_ci            double lineT = fLine->nearPoint(fQuad[qIndex], nullptr);
296cb93a386Sopenharmony_ci            if (lineT < 0) {
297cb93a386Sopenharmony_ci                continue;
298cb93a386Sopenharmony_ci            }
299cb93a386Sopenharmony_ci            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
300cb93a386Sopenharmony_ci        }
301cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
302cb93a386Sopenharmony_ci    }
303cb93a386Sopenharmony_ci
304cb93a386Sopenharmony_ci    void addLineNearEndPoints() {
305cb93a386Sopenharmony_ci        for (int lIndex = 0; lIndex < 2; ++lIndex) {
306cb93a386Sopenharmony_ci            double lineT = (double) lIndex;
307cb93a386Sopenharmony_ci            if (fIntersections->hasOppT(lineT)) {
308cb93a386Sopenharmony_ci                continue;
309cb93a386Sopenharmony_ci            }
310cb93a386Sopenharmony_ci            double quadT = ((SkDCurve*) &fQuad)->nearPoint(SkPath::kQuad_Verb,
311cb93a386Sopenharmony_ci                    (*fLine)[lIndex], (*fLine)[!lIndex]);
312cb93a386Sopenharmony_ci            if (quadT < 0) {
313cb93a386Sopenharmony_ci                continue;
314cb93a386Sopenharmony_ci            }
315cb93a386Sopenharmony_ci            fIntersections->insert(quadT, lineT, (*fLine)[lIndex]);
316cb93a386Sopenharmony_ci        }
317cb93a386Sopenharmony_ci    }
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_ci    void addExactHorizontalEndPoints(double left, double right, double y) {
320cb93a386Sopenharmony_ci        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
321cb93a386Sopenharmony_ci            double lineT = SkDLine::ExactPointH(fQuad[qIndex], left, right, y);
322cb93a386Sopenharmony_ci            if (lineT < 0) {
323cb93a386Sopenharmony_ci                continue;
324cb93a386Sopenharmony_ci            }
325cb93a386Sopenharmony_ci            double quadT = (double) (qIndex >> 1);
326cb93a386Sopenharmony_ci            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
327cb93a386Sopenharmony_ci        }
328cb93a386Sopenharmony_ci    }
329cb93a386Sopenharmony_ci
330cb93a386Sopenharmony_ci    void addNearHorizontalEndPoints(double left, double right, double y) {
331cb93a386Sopenharmony_ci        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
332cb93a386Sopenharmony_ci            double quadT = (double) (qIndex >> 1);
333cb93a386Sopenharmony_ci            if (fIntersections->hasT(quadT)) {
334cb93a386Sopenharmony_ci                continue;
335cb93a386Sopenharmony_ci            }
336cb93a386Sopenharmony_ci            double lineT = SkDLine::NearPointH(fQuad[qIndex], left, right, y);
337cb93a386Sopenharmony_ci            if (lineT < 0) {
338cb93a386Sopenharmony_ci                continue;
339cb93a386Sopenharmony_ci            }
340cb93a386Sopenharmony_ci            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
341cb93a386Sopenharmony_ci        }
342cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
343cb93a386Sopenharmony_ci    }
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_ci    void addExactVerticalEndPoints(double top, double bottom, double x) {
346cb93a386Sopenharmony_ci        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
347cb93a386Sopenharmony_ci            double lineT = SkDLine::ExactPointV(fQuad[qIndex], top, bottom, x);
348cb93a386Sopenharmony_ci            if (lineT < 0) {
349cb93a386Sopenharmony_ci                continue;
350cb93a386Sopenharmony_ci            }
351cb93a386Sopenharmony_ci            double quadT = (double) (qIndex >> 1);
352cb93a386Sopenharmony_ci            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
353cb93a386Sopenharmony_ci        }
354cb93a386Sopenharmony_ci    }
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci    void addNearVerticalEndPoints(double top, double bottom, double x) {
357cb93a386Sopenharmony_ci        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
358cb93a386Sopenharmony_ci            double quadT = (double) (qIndex >> 1);
359cb93a386Sopenharmony_ci            if (fIntersections->hasT(quadT)) {
360cb93a386Sopenharmony_ci                continue;
361cb93a386Sopenharmony_ci            }
362cb93a386Sopenharmony_ci            double lineT = SkDLine::NearPointV(fQuad[qIndex], top, bottom, x);
363cb93a386Sopenharmony_ci            if (lineT < 0) {
364cb93a386Sopenharmony_ci                continue;
365cb93a386Sopenharmony_ci            }
366cb93a386Sopenharmony_ci            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
367cb93a386Sopenharmony_ci        }
368cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
369cb93a386Sopenharmony_ci    }
370cb93a386Sopenharmony_ci
371cb93a386Sopenharmony_ci    double findLineT(double t) {
372cb93a386Sopenharmony_ci        SkDPoint xy = fQuad.ptAtT(t);
373cb93a386Sopenharmony_ci        double dx = (*fLine)[1].fX - (*fLine)[0].fX;
374cb93a386Sopenharmony_ci        double dy = (*fLine)[1].fY - (*fLine)[0].fY;
375cb93a386Sopenharmony_ci        if (fabs(dx) > fabs(dy)) {
376cb93a386Sopenharmony_ci            return (xy.fX - (*fLine)[0].fX) / dx;
377cb93a386Sopenharmony_ci        }
378cb93a386Sopenharmony_ci        return (xy.fY - (*fLine)[0].fY) / dy;
379cb93a386Sopenharmony_ci    }
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ci    bool pinTs(double* quadT, double* lineT, SkDPoint* pt, PinTPoint ptSet) {
382cb93a386Sopenharmony_ci        if (!approximately_one_or_less_double(*lineT)) {
383cb93a386Sopenharmony_ci            return false;
384cb93a386Sopenharmony_ci        }
385cb93a386Sopenharmony_ci        if (!approximately_zero_or_more_double(*lineT)) {
386cb93a386Sopenharmony_ci            return false;
387cb93a386Sopenharmony_ci        }
388cb93a386Sopenharmony_ci        double qT = *quadT = SkPinT(*quadT);
389cb93a386Sopenharmony_ci        double lT = *lineT = SkPinT(*lineT);
390cb93a386Sopenharmony_ci        if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT != 1)) {
391cb93a386Sopenharmony_ci            *pt = (*fLine).ptAtT(lT);
392cb93a386Sopenharmony_ci        } else if (ptSet == kPointUninitialized) {
393cb93a386Sopenharmony_ci            *pt = fQuad.ptAtT(qT);
394cb93a386Sopenharmony_ci        }
395cb93a386Sopenharmony_ci        SkPoint gridPt = pt->asSkPoint();
396cb93a386Sopenharmony_ci        if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[0].asSkPoint())) {
397cb93a386Sopenharmony_ci            *pt = (*fLine)[0];
398cb93a386Sopenharmony_ci            *lineT = 0;
399cb93a386Sopenharmony_ci        } else if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[1].asSkPoint())) {
400cb93a386Sopenharmony_ci            *pt = (*fLine)[1];
401cb93a386Sopenharmony_ci            *lineT = 1;
402cb93a386Sopenharmony_ci        }
403cb93a386Sopenharmony_ci        if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[1][0], *lineT)) {
404cb93a386Sopenharmony_ci            return false;
405cb93a386Sopenharmony_ci        }
406cb93a386Sopenharmony_ci        if (gridPt == fQuad[0].asSkPoint()) {
407cb93a386Sopenharmony_ci            *pt = fQuad[0];
408cb93a386Sopenharmony_ci            *quadT = 0;
409cb93a386Sopenharmony_ci        } else if (gridPt == fQuad[2].asSkPoint()) {
410cb93a386Sopenharmony_ci            *pt = fQuad[2];
411cb93a386Sopenharmony_ci            *quadT = 1;
412cb93a386Sopenharmony_ci        }
413cb93a386Sopenharmony_ci        return true;
414cb93a386Sopenharmony_ci    }
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ciprivate:
417cb93a386Sopenharmony_ci    const SkDQuad& fQuad;
418cb93a386Sopenharmony_ci    const SkDLine* fLine;
419cb93a386Sopenharmony_ci    SkIntersections* fIntersections;
420cb93a386Sopenharmony_ci    bool fAllowNear;
421cb93a386Sopenharmony_ci};
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ciint SkIntersections::horizontal(const SkDQuad& quad, double left, double right, double y,
424cb93a386Sopenharmony_ci                                bool flipped) {
425cb93a386Sopenharmony_ci    SkDLine line = {{{ left, y }, { right, y }}};
426cb93a386Sopenharmony_ci    LineQuadraticIntersections q(quad, line, this);
427cb93a386Sopenharmony_ci    return q.horizontalIntersect(y, left, right, flipped);
428cb93a386Sopenharmony_ci}
429cb93a386Sopenharmony_ci
430cb93a386Sopenharmony_ciint SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, double x,
431cb93a386Sopenharmony_ci                              bool flipped) {
432cb93a386Sopenharmony_ci    SkDLine line = {{{ x, top }, { x, bottom }}};
433cb93a386Sopenharmony_ci    LineQuadraticIntersections q(quad, line, this);
434cb93a386Sopenharmony_ci    return q.verticalIntersect(x, top, bottom, flipped);
435cb93a386Sopenharmony_ci}
436cb93a386Sopenharmony_ci
437cb93a386Sopenharmony_ciint SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) {
438cb93a386Sopenharmony_ci    LineQuadraticIntersections q(quad, line, this);
439cb93a386Sopenharmony_ci    q.allowNear(fAllowNear);
440cb93a386Sopenharmony_ci    return q.intersect();
441cb93a386Sopenharmony_ci}
442cb93a386Sopenharmony_ci
443cb93a386Sopenharmony_ciint SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) {
444cb93a386Sopenharmony_ci    LineQuadraticIntersections q(quad, line, this);
445cb93a386Sopenharmony_ci    fUsed = q.intersectRay(fT[0]);
446cb93a386Sopenharmony_ci    for (int index = 0; index < fUsed; ++index) {
447cb93a386Sopenharmony_ci        fPt[index] = quad.ptAtT(fT[0][index]);
448cb93a386Sopenharmony_ci    }
449cb93a386Sopenharmony_ci    return fUsed;
450cb93a386Sopenharmony_ci}
451cb93a386Sopenharmony_ci
452cb93a386Sopenharmony_ciint SkIntersections::HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots) {
453cb93a386Sopenharmony_ci    LineQuadraticIntersections q(quad);
454cb93a386Sopenharmony_ci    return q.horizontalIntersect(y, roots);
455cb93a386Sopenharmony_ci}
456cb93a386Sopenharmony_ci
457cb93a386Sopenharmony_ciint SkIntersections::VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots) {
458cb93a386Sopenharmony_ci    LineQuadraticIntersections q(quad);
459cb93a386Sopenharmony_ci    return q.verticalIntersect(x, roots);
460cb93a386Sopenharmony_ci}
461cb93a386Sopenharmony_ci
462cb93a386Sopenharmony_ci// SkDQuad accessors to Intersection utilities
463cb93a386Sopenharmony_ci
464cb93a386Sopenharmony_ciint SkDQuad::horizontalIntersect(double yIntercept, double roots[2]) const {
465cb93a386Sopenharmony_ci    return SkIntersections::HorizontalIntercept(*this, yIntercept, roots);
466cb93a386Sopenharmony_ci}
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_ciint SkDQuad::verticalIntersect(double xIntercept, double roots[2]) const {
469cb93a386Sopenharmony_ci    return SkIntersections::VerticalIntercept(*this, xIntercept, roots);
470cb93a386Sopenharmony_ci}
471