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/SkPathOpsCubic.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCurve.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci/*
13cb93a386Sopenharmony_ciFind the interection of a line and cubic by solving for valid t values.
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ciAnalogous to line-quadratic intersection, solve line-cubic intersection by
16cb93a386Sopenharmony_cirepresenting the cubic as:
17cb93a386Sopenharmony_ci  x = a(1-t)^3 + 2b(1-t)^2t + c(1-t)t^2 + dt^3
18cb93a386Sopenharmony_ci  y = e(1-t)^3 + 2f(1-t)^2t + g(1-t)t^2 + ht^3
19cb93a386Sopenharmony_ciand the line as:
20cb93a386Sopenharmony_ci  y = i*x + j  (if the line is more horizontal)
21cb93a386Sopenharmony_cior:
22cb93a386Sopenharmony_ci  x = i*y + j  (if the line is more vertical)
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ciThen using Mathematica, solve for the values of t where the cubic intersects the
25cb93a386Sopenharmony_ciline:
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ci  (in) Resultant[
28cb93a386Sopenharmony_ci        a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - x,
29cb93a386Sopenharmony_ci        e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - i*x - j, x]
30cb93a386Sopenharmony_ci  (out) -e     +   j     +
31cb93a386Sopenharmony_ci       3 e t   - 3 f t   -
32cb93a386Sopenharmony_ci       3 e t^2 + 6 f t^2 - 3 g t^2 +
33cb93a386Sopenharmony_ci         e t^3 - 3 f t^3 + 3 g t^3 - h t^3 +
34cb93a386Sopenharmony_ci     i ( a     -
35cb93a386Sopenharmony_ci       3 a t + 3 b t +
36cb93a386Sopenharmony_ci       3 a t^2 - 6 b t^2 + 3 c t^2 -
37cb93a386Sopenharmony_ci         a t^3 + 3 b t^3 - 3 c t^3 + d t^3 )
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ciif i goes to infinity, we can rewrite the line in terms of x. Mathematica:
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci  (in) Resultant[
42cb93a386Sopenharmony_ci        a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - i*y - j,
43cb93a386Sopenharmony_ci        e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y,       y]
44cb93a386Sopenharmony_ci  (out)  a     -   j     -
45cb93a386Sopenharmony_ci       3 a t   + 3 b t   +
46cb93a386Sopenharmony_ci       3 a t^2 - 6 b t^2 + 3 c t^2 -
47cb93a386Sopenharmony_ci         a t^3 + 3 b t^3 - 3 c t^3 + d t^3 -
48cb93a386Sopenharmony_ci     i ( e     -
49cb93a386Sopenharmony_ci       3 e t   + 3 f t   +
50cb93a386Sopenharmony_ci       3 e t^2 - 6 f t^2 + 3 g t^2 -
51cb93a386Sopenharmony_ci         e t^3 + 3 f t^3 - 3 g t^3 + h t^3 )
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ciSolving this with Mathematica produces an expression with hundreds of terms;
54cb93a386Sopenharmony_ciinstead, use Numeric Solutions recipe to solve the cubic.
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ciThe near-horizontal case, in terms of:  Ax^3 + Bx^2 + Cx + D == 0
57cb93a386Sopenharmony_ci    A =   (-(-e + 3*f - 3*g + h) + i*(-a + 3*b - 3*c + d)     )
58cb93a386Sopenharmony_ci    B = 3*(-( e - 2*f +   g    ) + i*( a - 2*b +   c    )     )
59cb93a386Sopenharmony_ci    C = 3*(-(-e +   f          ) + i*(-a +   b          )     )
60cb93a386Sopenharmony_ci    D =   (-( e                ) + i*( a                ) + j )
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ciThe near-vertical case, in terms of:  Ax^3 + Bx^2 + Cx + D == 0
63cb93a386Sopenharmony_ci    A =   ( (-a + 3*b - 3*c + d) - i*(-e + 3*f - 3*g + h)     )
64cb93a386Sopenharmony_ci    B = 3*( ( a - 2*b +   c    ) - i*( e - 2*f +   g    )     )
65cb93a386Sopenharmony_ci    C = 3*( (-a +   b          ) - i*(-e +   f          )     )
66cb93a386Sopenharmony_ci    D =   ( ( a                ) - i*( e                ) - j )
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ciFor horizontal lines:
69cb93a386Sopenharmony_ci(in) Resultant[
70cb93a386Sopenharmony_ci      a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - j,
71cb93a386Sopenharmony_ci      e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y]
72cb93a386Sopenharmony_ci(out)  e     -   j     -
73cb93a386Sopenharmony_ci     3 e t   + 3 f t   +
74cb93a386Sopenharmony_ci     3 e t^2 - 6 f t^2 + 3 g t^2 -
75cb93a386Sopenharmony_ci       e t^3 + 3 f t^3 - 3 g t^3 + h t^3
76cb93a386Sopenharmony_ci */
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ciclass LineCubicIntersections {
79cb93a386Sopenharmony_cipublic:
80cb93a386Sopenharmony_ci    enum PinTPoint {
81cb93a386Sopenharmony_ci        kPointUninitialized,
82cb93a386Sopenharmony_ci        kPointInitialized
83cb93a386Sopenharmony_ci    };
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci    LineCubicIntersections(const SkDCubic& c, const SkDLine& l, SkIntersections* i)
86cb93a386Sopenharmony_ci        : fCubic(c)
87cb93a386Sopenharmony_ci        , fLine(l)
88cb93a386Sopenharmony_ci        , fIntersections(i)
89cb93a386Sopenharmony_ci        , fAllowNear(true) {
90cb93a386Sopenharmony_ci        i->setMax(4);
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    void allowNear(bool allow) {
94cb93a386Sopenharmony_ci        fAllowNear = allow;
95cb93a386Sopenharmony_ci    }
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci    void checkCoincident() {
98cb93a386Sopenharmony_ci        int last = fIntersections->used() - 1;
99cb93a386Sopenharmony_ci        for (int index = 0; index < last; ) {
100cb93a386Sopenharmony_ci            double cubicMidT = ((*fIntersections)[0][index] + (*fIntersections)[0][index + 1]) / 2;
101cb93a386Sopenharmony_ci            SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT);
102cb93a386Sopenharmony_ci            double t = fLine.nearPoint(cubicMidPt, nullptr);
103cb93a386Sopenharmony_ci            if (t < 0) {
104cb93a386Sopenharmony_ci                ++index;
105cb93a386Sopenharmony_ci                continue;
106cb93a386Sopenharmony_ci            }
107cb93a386Sopenharmony_ci            if (fIntersections->isCoincident(index)) {
108cb93a386Sopenharmony_ci                fIntersections->removeOne(index);
109cb93a386Sopenharmony_ci                --last;
110cb93a386Sopenharmony_ci            } else if (fIntersections->isCoincident(index + 1)) {
111cb93a386Sopenharmony_ci                fIntersections->removeOne(index + 1);
112cb93a386Sopenharmony_ci                --last;
113cb93a386Sopenharmony_ci            } else {
114cb93a386Sopenharmony_ci                fIntersections->setCoincident(index++);
115cb93a386Sopenharmony_ci            }
116cb93a386Sopenharmony_ci            fIntersections->setCoincident(index);
117cb93a386Sopenharmony_ci        }
118cb93a386Sopenharmony_ci    }
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci    // see parallel routine in line quadratic intersections
121cb93a386Sopenharmony_ci    int intersectRay(double roots[3]) {
122cb93a386Sopenharmony_ci        double adj = fLine[1].fX - fLine[0].fX;
123cb93a386Sopenharmony_ci        double opp = fLine[1].fY - fLine[0].fY;
124cb93a386Sopenharmony_ci        SkDCubic c;
125cb93a386Sopenharmony_ci        SkDEBUGCODE(c.fDebugGlobalState = fIntersections->globalState());
126cb93a386Sopenharmony_ci        for (int n = 0; n < 4; ++n) {
127cb93a386Sopenharmony_ci            c[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine[0].fX) * opp;
128cb93a386Sopenharmony_ci        }
129cb93a386Sopenharmony_ci        double A, B, C, D;
130cb93a386Sopenharmony_ci        SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D);
131cb93a386Sopenharmony_ci        int count = SkDCubic::RootsValidT(A, B, C, D, roots);
132cb93a386Sopenharmony_ci        for (int index = 0; index < count; ++index) {
133cb93a386Sopenharmony_ci            SkDPoint calcPt = c.ptAtT(roots[index]);
134cb93a386Sopenharmony_ci            if (!approximately_zero(calcPt.fX)) {
135cb93a386Sopenharmony_ci                for (int n = 0; n < 4; ++n) {
136cb93a386Sopenharmony_ci                    c[n].fY = (fCubic[n].fY - fLine[0].fY) * opp
137cb93a386Sopenharmony_ci                            + (fCubic[n].fX - fLine[0].fX) * adj;
138cb93a386Sopenharmony_ci                }
139cb93a386Sopenharmony_ci                double extremeTs[6];
140cb93a386Sopenharmony_ci                int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs);
141cb93a386Sopenharmony_ci                count = c.searchRoots(extremeTs, extrema, 0, SkDCubic::kXAxis, roots);
142cb93a386Sopenharmony_ci                break;
143cb93a386Sopenharmony_ci            }
144cb93a386Sopenharmony_ci        }
145cb93a386Sopenharmony_ci        return count;
146cb93a386Sopenharmony_ci    }
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_ci    int intersect() {
149cb93a386Sopenharmony_ci        addExactEndPoints();
150cb93a386Sopenharmony_ci        if (fAllowNear) {
151cb93a386Sopenharmony_ci            addNearEndPoints();
152cb93a386Sopenharmony_ci        }
153cb93a386Sopenharmony_ci        double rootVals[3];
154cb93a386Sopenharmony_ci        int roots = intersectRay(rootVals);
155cb93a386Sopenharmony_ci        for (int index = 0; index < roots; ++index) {
156cb93a386Sopenharmony_ci            double cubicT = rootVals[index];
157cb93a386Sopenharmony_ci            double lineT = findLineT(cubicT);
158cb93a386Sopenharmony_ci            SkDPoint pt;
159cb93a386Sopenharmony_ci            if (pinTs(&cubicT, &lineT, &pt, kPointUninitialized) && uniqueAnswer(cubicT, pt)) {
160cb93a386Sopenharmony_ci                fIntersections->insert(cubicT, lineT, pt);
161cb93a386Sopenharmony_ci            }
162cb93a386Sopenharmony_ci        }
163cb93a386Sopenharmony_ci        checkCoincident();
164cb93a386Sopenharmony_ci        return fIntersections->used();
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    static int HorizontalIntersect(const SkDCubic& c, double axisIntercept, double roots[3]) {
168cb93a386Sopenharmony_ci        double A, B, C, D;
169cb93a386Sopenharmony_ci        SkDCubic::Coefficients(&c[0].fY, &A, &B, &C, &D);
170cb93a386Sopenharmony_ci        D -= axisIntercept;
171cb93a386Sopenharmony_ci        int count = SkDCubic::RootsValidT(A, B, C, D, roots);
172cb93a386Sopenharmony_ci        for (int index = 0; index < count; ++index) {
173cb93a386Sopenharmony_ci            SkDPoint calcPt = c.ptAtT(roots[index]);
174cb93a386Sopenharmony_ci            if (!approximately_equal(calcPt.fY, axisIntercept)) {
175cb93a386Sopenharmony_ci                double extremeTs[6];
176cb93a386Sopenharmony_ci                int extrema = SkDCubic::FindExtrema(&c[0].fY, extremeTs);
177cb93a386Sopenharmony_ci                count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kYAxis, roots);
178cb93a386Sopenharmony_ci                break;
179cb93a386Sopenharmony_ci            }
180cb93a386Sopenharmony_ci        }
181cb93a386Sopenharmony_ci        return count;
182cb93a386Sopenharmony_ci    }
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ci    int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) {
185cb93a386Sopenharmony_ci        addExactHorizontalEndPoints(left, right, axisIntercept);
186cb93a386Sopenharmony_ci        if (fAllowNear) {
187cb93a386Sopenharmony_ci            addNearHorizontalEndPoints(left, right, axisIntercept);
188cb93a386Sopenharmony_ci        }
189cb93a386Sopenharmony_ci        double roots[3];
190cb93a386Sopenharmony_ci        int count = HorizontalIntersect(fCubic, axisIntercept, roots);
191cb93a386Sopenharmony_ci        for (int index = 0; index < count; ++index) {
192cb93a386Sopenharmony_ci            double cubicT = roots[index];
193cb93a386Sopenharmony_ci            SkDPoint pt = { fCubic.ptAtT(cubicT).fX,  axisIntercept };
194cb93a386Sopenharmony_ci            double lineT = (pt.fX - left) / (right - left);
195cb93a386Sopenharmony_ci            if (pinTs(&cubicT, &lineT, &pt, kPointInitialized) && uniqueAnswer(cubicT, pt)) {
196cb93a386Sopenharmony_ci                fIntersections->insert(cubicT, lineT, pt);
197cb93a386Sopenharmony_ci            }
198cb93a386Sopenharmony_ci        }
199cb93a386Sopenharmony_ci        if (flipped) {
200cb93a386Sopenharmony_ci            fIntersections->flip();
201cb93a386Sopenharmony_ci        }
202cb93a386Sopenharmony_ci        checkCoincident();
203cb93a386Sopenharmony_ci        return fIntersections->used();
204cb93a386Sopenharmony_ci    }
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_ci        bool uniqueAnswer(double cubicT, const SkDPoint& pt) {
207cb93a386Sopenharmony_ci            for (int inner = 0; inner < fIntersections->used(); ++inner) {
208cb93a386Sopenharmony_ci                if (fIntersections->pt(inner) != pt) {
209cb93a386Sopenharmony_ci                    continue;
210cb93a386Sopenharmony_ci                }
211cb93a386Sopenharmony_ci                double existingCubicT = (*fIntersections)[0][inner];
212cb93a386Sopenharmony_ci                if (cubicT == existingCubicT) {
213cb93a386Sopenharmony_ci                    return false;
214cb93a386Sopenharmony_ci                }
215cb93a386Sopenharmony_ci                // check if midway on cubic is also same point. If so, discard this
216cb93a386Sopenharmony_ci                double cubicMidT = (existingCubicT + cubicT) / 2;
217cb93a386Sopenharmony_ci                SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT);
218cb93a386Sopenharmony_ci                if (cubicMidPt.approximatelyEqual(pt)) {
219cb93a386Sopenharmony_ci                    return false;
220cb93a386Sopenharmony_ci                }
221cb93a386Sopenharmony_ci            }
222cb93a386Sopenharmony_ci#if ONE_OFF_DEBUG
223cb93a386Sopenharmony_ci            SkDPoint cPt = fCubic.ptAtT(cubicT);
224cb93a386Sopenharmony_ci            SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY,
225cb93a386Sopenharmony_ci                    cPt.fX, cPt.fY);
226cb93a386Sopenharmony_ci#endif
227cb93a386Sopenharmony_ci            return true;
228cb93a386Sopenharmony_ci        }
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    static int VerticalIntersect(const SkDCubic& c, double axisIntercept, double roots[3]) {
231cb93a386Sopenharmony_ci        double A, B, C, D;
232cb93a386Sopenharmony_ci        SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D);
233cb93a386Sopenharmony_ci        D -= axisIntercept;
234cb93a386Sopenharmony_ci        int count = SkDCubic::RootsValidT(A, B, C, D, roots);
235cb93a386Sopenharmony_ci        for (int index = 0; index < count; ++index) {
236cb93a386Sopenharmony_ci            SkDPoint calcPt = c.ptAtT(roots[index]);
237cb93a386Sopenharmony_ci            if (!approximately_equal(calcPt.fX, axisIntercept)) {
238cb93a386Sopenharmony_ci                double extremeTs[6];
239cb93a386Sopenharmony_ci                int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs);
240cb93a386Sopenharmony_ci                count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kXAxis, roots);
241cb93a386Sopenharmony_ci                break;
242cb93a386Sopenharmony_ci            }
243cb93a386Sopenharmony_ci        }
244cb93a386Sopenharmony_ci        return count;
245cb93a386Sopenharmony_ci    }
246cb93a386Sopenharmony_ci
247cb93a386Sopenharmony_ci    int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
248cb93a386Sopenharmony_ci        addExactVerticalEndPoints(top, bottom, axisIntercept);
249cb93a386Sopenharmony_ci        if (fAllowNear) {
250cb93a386Sopenharmony_ci            addNearVerticalEndPoints(top, bottom, axisIntercept);
251cb93a386Sopenharmony_ci        }
252cb93a386Sopenharmony_ci        double roots[3];
253cb93a386Sopenharmony_ci        int count = VerticalIntersect(fCubic, axisIntercept, roots);
254cb93a386Sopenharmony_ci        for (int index = 0; index < count; ++index) {
255cb93a386Sopenharmony_ci            double cubicT = roots[index];
256cb93a386Sopenharmony_ci            SkDPoint pt = { axisIntercept, fCubic.ptAtT(cubicT).fY };
257cb93a386Sopenharmony_ci            double lineT = (pt.fY - top) / (bottom - top);
258cb93a386Sopenharmony_ci            if (pinTs(&cubicT, &lineT, &pt, kPointInitialized) && uniqueAnswer(cubicT, pt)) {
259cb93a386Sopenharmony_ci                fIntersections->insert(cubicT, lineT, pt);
260cb93a386Sopenharmony_ci            }
261cb93a386Sopenharmony_ci        }
262cb93a386Sopenharmony_ci        if (flipped) {
263cb93a386Sopenharmony_ci            fIntersections->flip();
264cb93a386Sopenharmony_ci        }
265cb93a386Sopenharmony_ci        checkCoincident();
266cb93a386Sopenharmony_ci        return fIntersections->used();
267cb93a386Sopenharmony_ci    }
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci    protected:
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci    void addExactEndPoints() {
272cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < 4; cIndex += 3) {
273cb93a386Sopenharmony_ci            double lineT = fLine.exactPoint(fCubic[cIndex]);
274cb93a386Sopenharmony_ci            if (lineT < 0) {
275cb93a386Sopenharmony_ci                continue;
276cb93a386Sopenharmony_ci            }
277cb93a386Sopenharmony_ci            double cubicT = (double) (cIndex >> 1);
278cb93a386Sopenharmony_ci            fIntersections->insert(cubicT, lineT, fCubic[cIndex]);
279cb93a386Sopenharmony_ci        }
280cb93a386Sopenharmony_ci    }
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_ci    /* Note that this does not look for endpoints of the line that are near the cubic.
283cb93a386Sopenharmony_ci       These points are found later when check ends looks for missing points */
284cb93a386Sopenharmony_ci    void addNearEndPoints() {
285cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < 4; cIndex += 3) {
286cb93a386Sopenharmony_ci            double cubicT = (double) (cIndex >> 1);
287cb93a386Sopenharmony_ci            if (fIntersections->hasT(cubicT)) {
288cb93a386Sopenharmony_ci                continue;
289cb93a386Sopenharmony_ci            }
290cb93a386Sopenharmony_ci            double lineT = fLine.nearPoint(fCubic[cIndex], nullptr);
291cb93a386Sopenharmony_ci            if (lineT < 0) {
292cb93a386Sopenharmony_ci                continue;
293cb93a386Sopenharmony_ci            }
294cb93a386Sopenharmony_ci            fIntersections->insert(cubicT, lineT, fCubic[cIndex]);
295cb93a386Sopenharmony_ci        }
296cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
297cb93a386Sopenharmony_ci    }
298cb93a386Sopenharmony_ci
299cb93a386Sopenharmony_ci    void addLineNearEndPoints() {
300cb93a386Sopenharmony_ci        for (int lIndex = 0; lIndex < 2; ++lIndex) {
301cb93a386Sopenharmony_ci            double lineT = (double) lIndex;
302cb93a386Sopenharmony_ci            if (fIntersections->hasOppT(lineT)) {
303cb93a386Sopenharmony_ci                continue;
304cb93a386Sopenharmony_ci            }
305cb93a386Sopenharmony_ci            double cubicT = ((SkDCurve*) &fCubic)->nearPoint(SkPath::kCubic_Verb,
306cb93a386Sopenharmony_ci                fLine[lIndex], fLine[!lIndex]);
307cb93a386Sopenharmony_ci            if (cubicT < 0) {
308cb93a386Sopenharmony_ci                continue;
309cb93a386Sopenharmony_ci            }
310cb93a386Sopenharmony_ci            fIntersections->insert(cubicT, lineT, fLine[lIndex]);
311cb93a386Sopenharmony_ci        }
312cb93a386Sopenharmony_ci    }
313cb93a386Sopenharmony_ci
314cb93a386Sopenharmony_ci    void addExactHorizontalEndPoints(double left, double right, double y) {
315cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < 4; cIndex += 3) {
316cb93a386Sopenharmony_ci            double lineT = SkDLine::ExactPointH(fCubic[cIndex], left, right, y);
317cb93a386Sopenharmony_ci            if (lineT < 0) {
318cb93a386Sopenharmony_ci                continue;
319cb93a386Sopenharmony_ci            }
320cb93a386Sopenharmony_ci            double cubicT = (double) (cIndex >> 1);
321cb93a386Sopenharmony_ci            fIntersections->insert(cubicT, lineT, fCubic[cIndex]);
322cb93a386Sopenharmony_ci        }
323cb93a386Sopenharmony_ci    }
324cb93a386Sopenharmony_ci
325cb93a386Sopenharmony_ci    void addNearHorizontalEndPoints(double left, double right, double y) {
326cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < 4; cIndex += 3) {
327cb93a386Sopenharmony_ci            double cubicT = (double) (cIndex >> 1);
328cb93a386Sopenharmony_ci            if (fIntersections->hasT(cubicT)) {
329cb93a386Sopenharmony_ci                continue;
330cb93a386Sopenharmony_ci            }
331cb93a386Sopenharmony_ci            double lineT = SkDLine::NearPointH(fCubic[cIndex], left, right, y);
332cb93a386Sopenharmony_ci            if (lineT < 0) {
333cb93a386Sopenharmony_ci                continue;
334cb93a386Sopenharmony_ci            }
335cb93a386Sopenharmony_ci            fIntersections->insert(cubicT, lineT, fCubic[cIndex]);
336cb93a386Sopenharmony_ci        }
337cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
338cb93a386Sopenharmony_ci    }
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ci    void addExactVerticalEndPoints(double top, double bottom, double x) {
341cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < 4; cIndex += 3) {
342cb93a386Sopenharmony_ci            double lineT = SkDLine::ExactPointV(fCubic[cIndex], top, bottom, x);
343cb93a386Sopenharmony_ci            if (lineT < 0) {
344cb93a386Sopenharmony_ci                continue;
345cb93a386Sopenharmony_ci            }
346cb93a386Sopenharmony_ci            double cubicT = (double) (cIndex >> 1);
347cb93a386Sopenharmony_ci            fIntersections->insert(cubicT, lineT, fCubic[cIndex]);
348cb93a386Sopenharmony_ci        }
349cb93a386Sopenharmony_ci    }
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_ci    void addNearVerticalEndPoints(double top, double bottom, double x) {
352cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < 4; cIndex += 3) {
353cb93a386Sopenharmony_ci            double cubicT = (double) (cIndex >> 1);
354cb93a386Sopenharmony_ci            if (fIntersections->hasT(cubicT)) {
355cb93a386Sopenharmony_ci                continue;
356cb93a386Sopenharmony_ci            }
357cb93a386Sopenharmony_ci            double lineT = SkDLine::NearPointV(fCubic[cIndex], top, bottom, x);
358cb93a386Sopenharmony_ci            if (lineT < 0) {
359cb93a386Sopenharmony_ci                continue;
360cb93a386Sopenharmony_ci            }
361cb93a386Sopenharmony_ci            fIntersections->insert(cubicT, lineT, fCubic[cIndex]);
362cb93a386Sopenharmony_ci        }
363cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
364cb93a386Sopenharmony_ci    }
365cb93a386Sopenharmony_ci
366cb93a386Sopenharmony_ci    double findLineT(double t) {
367cb93a386Sopenharmony_ci        SkDPoint xy = fCubic.ptAtT(t);
368cb93a386Sopenharmony_ci        double dx = fLine[1].fX - fLine[0].fX;
369cb93a386Sopenharmony_ci        double dy = fLine[1].fY - fLine[0].fY;
370cb93a386Sopenharmony_ci        if (fabs(dx) > fabs(dy)) {
371cb93a386Sopenharmony_ci            return (xy.fX - fLine[0].fX) / dx;
372cb93a386Sopenharmony_ci        }
373cb93a386Sopenharmony_ci        return (xy.fY - fLine[0].fY) / dy;
374cb93a386Sopenharmony_ci    }
375cb93a386Sopenharmony_ci
376cb93a386Sopenharmony_ci    bool pinTs(double* cubicT, double* lineT, SkDPoint* pt, PinTPoint ptSet) {
377cb93a386Sopenharmony_ci        if (!approximately_one_or_less(*lineT)) {
378cb93a386Sopenharmony_ci            return false;
379cb93a386Sopenharmony_ci        }
380cb93a386Sopenharmony_ci        if (!approximately_zero_or_more(*lineT)) {
381cb93a386Sopenharmony_ci            return false;
382cb93a386Sopenharmony_ci        }
383cb93a386Sopenharmony_ci        double cT = *cubicT = SkPinT(*cubicT);
384cb93a386Sopenharmony_ci        double lT = *lineT = SkPinT(*lineT);
385cb93a386Sopenharmony_ci        SkDPoint lPt = fLine.ptAtT(lT);
386cb93a386Sopenharmony_ci        SkDPoint cPt = fCubic.ptAtT(cT);
387cb93a386Sopenharmony_ci        if (!lPt.roughlyEqual(cPt)) {
388cb93a386Sopenharmony_ci            return false;
389cb93a386Sopenharmony_ci        }
390cb93a386Sopenharmony_ci        // FIXME: if points are roughly equal but not approximately equal, need to do
391cb93a386Sopenharmony_ci        // a binary search like quad/quad intersection to find more precise t values
392cb93a386Sopenharmony_ci        if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && cT != 0 && cT != 1)) {
393cb93a386Sopenharmony_ci            *pt = lPt;
394cb93a386Sopenharmony_ci        } else if (ptSet == kPointUninitialized) {
395cb93a386Sopenharmony_ci            *pt = cPt;
396cb93a386Sopenharmony_ci        }
397cb93a386Sopenharmony_ci        SkPoint gridPt = pt->asSkPoint();
398cb93a386Sopenharmony_ci        if (gridPt == fLine[0].asSkPoint()) {
399cb93a386Sopenharmony_ci            *lineT = 0;
400cb93a386Sopenharmony_ci        } else if (gridPt == fLine[1].asSkPoint()) {
401cb93a386Sopenharmony_ci            *lineT = 1;
402cb93a386Sopenharmony_ci        }
403cb93a386Sopenharmony_ci        if (gridPt == fCubic[0].asSkPoint() && approximately_equal(*cubicT, 0)) {
404cb93a386Sopenharmony_ci            *cubicT = 0;
405cb93a386Sopenharmony_ci        } else if (gridPt == fCubic[3].asSkPoint() && approximately_equal(*cubicT, 1)) {
406cb93a386Sopenharmony_ci            *cubicT = 1;
407cb93a386Sopenharmony_ci        }
408cb93a386Sopenharmony_ci        return true;
409cb93a386Sopenharmony_ci    }
410cb93a386Sopenharmony_ci
411cb93a386Sopenharmony_ciprivate:
412cb93a386Sopenharmony_ci    const SkDCubic& fCubic;
413cb93a386Sopenharmony_ci    const SkDLine& fLine;
414cb93a386Sopenharmony_ci    SkIntersections* fIntersections;
415cb93a386Sopenharmony_ci    bool fAllowNear;
416cb93a386Sopenharmony_ci};
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_ciint SkIntersections::horizontal(const SkDCubic& cubic, double left, double right, double y,
419cb93a386Sopenharmony_ci        bool flipped) {
420cb93a386Sopenharmony_ci    SkDLine line = {{{ left, y }, { right, y }}};
421cb93a386Sopenharmony_ci    LineCubicIntersections c(cubic, line, this);
422cb93a386Sopenharmony_ci    return c.horizontalIntersect(y, left, right, flipped);
423cb93a386Sopenharmony_ci}
424cb93a386Sopenharmony_ci
425cb93a386Sopenharmony_ciint SkIntersections::vertical(const SkDCubic& cubic, double top, double bottom, double x,
426cb93a386Sopenharmony_ci        bool flipped) {
427cb93a386Sopenharmony_ci    SkDLine line = {{{ x, top }, { x, bottom }}};
428cb93a386Sopenharmony_ci    LineCubicIntersections c(cubic, line, this);
429cb93a386Sopenharmony_ci    return c.verticalIntersect(x, top, bottom, flipped);
430cb93a386Sopenharmony_ci}
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ciint SkIntersections::intersect(const SkDCubic& cubic, const SkDLine& line) {
433cb93a386Sopenharmony_ci    LineCubicIntersections c(cubic, line, this);
434cb93a386Sopenharmony_ci    c.allowNear(fAllowNear);
435cb93a386Sopenharmony_ci    return c.intersect();
436cb93a386Sopenharmony_ci}
437cb93a386Sopenharmony_ci
438cb93a386Sopenharmony_ciint SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) {
439cb93a386Sopenharmony_ci    LineCubicIntersections c(cubic, line, this);
440cb93a386Sopenharmony_ci    fUsed = c.intersectRay(fT[0]);
441cb93a386Sopenharmony_ci    for (int index = 0; index < fUsed; ++index) {
442cb93a386Sopenharmony_ci        fPt[index] = cubic.ptAtT(fT[0][index]);
443cb93a386Sopenharmony_ci    }
444cb93a386Sopenharmony_ci    return fUsed;
445cb93a386Sopenharmony_ci}
446cb93a386Sopenharmony_ci
447cb93a386Sopenharmony_ci// SkDCubic accessors to Intersection utilities
448cb93a386Sopenharmony_ci
449cb93a386Sopenharmony_ciint SkDCubic::horizontalIntersect(double yIntercept, double roots[3]) const {
450cb93a386Sopenharmony_ci    return LineCubicIntersections::HorizontalIntersect(*this, yIntercept, roots);
451cb93a386Sopenharmony_ci}
452cb93a386Sopenharmony_ci
453cb93a386Sopenharmony_ciint SkDCubic::verticalIntersect(double xIntercept, double roots[3]) const {
454cb93a386Sopenharmony_ci    return LineCubicIntersections::VerticalIntersect(*this, xIntercept, roots);
455cb93a386Sopenharmony_ci}
456