1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 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/SkPathOpsConic.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCurve.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ciclass LineConicIntersections {
13cb93a386Sopenharmony_cipublic:
14cb93a386Sopenharmony_ci    enum PinTPoint {
15cb93a386Sopenharmony_ci        kPointUninitialized,
16cb93a386Sopenharmony_ci        kPointInitialized
17cb93a386Sopenharmony_ci    };
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ci    LineConicIntersections(const SkDConic& c, const SkDLine& l, SkIntersections* i)
20cb93a386Sopenharmony_ci        : fConic(c)
21cb93a386Sopenharmony_ci        , fLine(&l)
22cb93a386Sopenharmony_ci        , fIntersections(i)
23cb93a386Sopenharmony_ci        , fAllowNear(true) {
24cb93a386Sopenharmony_ci        i->setMax(4);  // allow short partial coincidence plus discrete intersection
25cb93a386Sopenharmony_ci    }
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ci    LineConicIntersections(const SkDConic& c)
28cb93a386Sopenharmony_ci        : fConic(c)
29cb93a386Sopenharmony_ci        SkDEBUGPARAMS(fLine(nullptr))
30cb93a386Sopenharmony_ci        SkDEBUGPARAMS(fIntersections(nullptr))
31cb93a386Sopenharmony_ci        SkDEBUGPARAMS(fAllowNear(false)) {
32cb93a386Sopenharmony_ci    }
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    void allowNear(bool allow) {
35cb93a386Sopenharmony_ci        fAllowNear = allow;
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci    void checkCoincident() {
39cb93a386Sopenharmony_ci        int last = fIntersections->used() - 1;
40cb93a386Sopenharmony_ci        for (int index = 0; index < last; ) {
41cb93a386Sopenharmony_ci            double conicMidT = ((*fIntersections)[0][index] + (*fIntersections)[0][index + 1]) / 2;
42cb93a386Sopenharmony_ci            SkDPoint conicMidPt = fConic.ptAtT(conicMidT);
43cb93a386Sopenharmony_ci            double t = fLine->nearPoint(conicMidPt, nullptr);
44cb93a386Sopenharmony_ci            if (t < 0) {
45cb93a386Sopenharmony_ci                ++index;
46cb93a386Sopenharmony_ci                continue;
47cb93a386Sopenharmony_ci            }
48cb93a386Sopenharmony_ci            if (fIntersections->isCoincident(index)) {
49cb93a386Sopenharmony_ci                fIntersections->removeOne(index);
50cb93a386Sopenharmony_ci                --last;
51cb93a386Sopenharmony_ci            } else if (fIntersections->isCoincident(index + 1)) {
52cb93a386Sopenharmony_ci                fIntersections->removeOne(index + 1);
53cb93a386Sopenharmony_ci                --last;
54cb93a386Sopenharmony_ci            } else {
55cb93a386Sopenharmony_ci                fIntersections->setCoincident(index++);
56cb93a386Sopenharmony_ci            }
57cb93a386Sopenharmony_ci            fIntersections->setCoincident(index);
58cb93a386Sopenharmony_ci        }
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci#ifdef SK_DEBUG
62cb93a386Sopenharmony_ci    static bool close_to(double a, double b, const double c[3]) {
63cb93a386Sopenharmony_ci        double max = std::max(-std::min(std::min(c[0], c[1]), c[2]), std::max(std::max(c[0], c[1]), c[2]));
64cb93a386Sopenharmony_ci        return approximately_zero_when_compared_to(a - b, max);
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci#endif
67cb93a386Sopenharmony_ci    int horizontalIntersect(double axisIntercept, double roots[2]) {
68cb93a386Sopenharmony_ci        double conicVals[] = { fConic[0].fY, fConic[1].fY, fConic[2].fY };
69cb93a386Sopenharmony_ci        return this->validT(conicVals, axisIntercept, roots);
70cb93a386Sopenharmony_ci    }
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci    int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) {
73cb93a386Sopenharmony_ci        this->addExactHorizontalEndPoints(left, right, axisIntercept);
74cb93a386Sopenharmony_ci        if (fAllowNear) {
75cb93a386Sopenharmony_ci            this->addNearHorizontalEndPoints(left, right, axisIntercept);
76cb93a386Sopenharmony_ci        }
77cb93a386Sopenharmony_ci        double roots[2];
78cb93a386Sopenharmony_ci        int count = this->horizontalIntersect(axisIntercept, roots);
79cb93a386Sopenharmony_ci        for (int index = 0; index < count; ++index) {
80cb93a386Sopenharmony_ci            double conicT = roots[index];
81cb93a386Sopenharmony_ci            SkDPoint pt = fConic.ptAtT(conicT);
82cb93a386Sopenharmony_ci            SkDEBUGCODE(double conicVals[] = { fConic[0].fY, fConic[1].fY, fConic[2].fY });
83cb93a386Sopenharmony_ci            SkOPOBJASSERT(fIntersections, close_to(pt.fY, axisIntercept, conicVals));
84cb93a386Sopenharmony_ci            double lineT = (pt.fX - left) / (right - left);
85cb93a386Sopenharmony_ci            if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized)
86cb93a386Sopenharmony_ci                    && this->uniqueAnswer(conicT, pt)) {
87cb93a386Sopenharmony_ci                fIntersections->insert(conicT, lineT, pt);
88cb93a386Sopenharmony_ci            }
89cb93a386Sopenharmony_ci        }
90cb93a386Sopenharmony_ci        if (flipped) {
91cb93a386Sopenharmony_ci            fIntersections->flip();
92cb93a386Sopenharmony_ci        }
93cb93a386Sopenharmony_ci        this->checkCoincident();
94cb93a386Sopenharmony_ci        return fIntersections->used();
95cb93a386Sopenharmony_ci    }
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci    int intersect() {
98cb93a386Sopenharmony_ci        this->addExactEndPoints();
99cb93a386Sopenharmony_ci        if (fAllowNear) {
100cb93a386Sopenharmony_ci            this->addNearEndPoints();
101cb93a386Sopenharmony_ci        }
102cb93a386Sopenharmony_ci        double rootVals[2];
103cb93a386Sopenharmony_ci        int roots = this->intersectRay(rootVals);
104cb93a386Sopenharmony_ci        for (int index = 0; index < roots; ++index) {
105cb93a386Sopenharmony_ci            double conicT = rootVals[index];
106cb93a386Sopenharmony_ci            double lineT = this->findLineT(conicT);
107cb93a386Sopenharmony_ci#ifdef SK_DEBUG
108cb93a386Sopenharmony_ci            if (!fIntersections->globalState()
109cb93a386Sopenharmony_ci                    || !fIntersections->globalState()->debugSkipAssert()) {
110cb93a386Sopenharmony_ci                SkDEBUGCODE(SkDPoint conicPt = fConic.ptAtT(conicT));
111cb93a386Sopenharmony_ci                SkDEBUGCODE(SkDPoint linePt = fLine->ptAtT(lineT));
112cb93a386Sopenharmony_ci                SkASSERT(conicPt.approximatelyDEqual(linePt));
113cb93a386Sopenharmony_ci            }
114cb93a386Sopenharmony_ci#endif
115cb93a386Sopenharmony_ci            SkDPoint pt;
116cb93a386Sopenharmony_ci            if (this->pinTs(&conicT, &lineT, &pt, kPointUninitialized)
117cb93a386Sopenharmony_ci                    && this->uniqueAnswer(conicT, pt)) {
118cb93a386Sopenharmony_ci                fIntersections->insert(conicT, lineT, pt);
119cb93a386Sopenharmony_ci            }
120cb93a386Sopenharmony_ci        }
121cb93a386Sopenharmony_ci        this->checkCoincident();
122cb93a386Sopenharmony_ci        return fIntersections->used();
123cb93a386Sopenharmony_ci    }
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci    int intersectRay(double roots[2]) {
126cb93a386Sopenharmony_ci        double adj = (*fLine)[1].fX - (*fLine)[0].fX;
127cb93a386Sopenharmony_ci        double opp = (*fLine)[1].fY - (*fLine)[0].fY;
128cb93a386Sopenharmony_ci        double r[3];
129cb93a386Sopenharmony_ci        for (int n = 0; n < 3; ++n) {
130cb93a386Sopenharmony_ci            r[n] = (fConic[n].fY - (*fLine)[0].fY) * adj - (fConic[n].fX - (*fLine)[0].fX) * opp;
131cb93a386Sopenharmony_ci        }
132cb93a386Sopenharmony_ci        return this->validT(r, 0, roots);
133cb93a386Sopenharmony_ci    }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    int validT(double r[3], double axisIntercept, double roots[2]) {
136cb93a386Sopenharmony_ci        double A = r[2];
137cb93a386Sopenharmony_ci        double B = r[1] * fConic.fWeight - axisIntercept * fConic.fWeight + axisIntercept;
138cb93a386Sopenharmony_ci        double C = r[0];
139cb93a386Sopenharmony_ci        A += C - 2 * B;  // A = a + c - 2*(b*w - xCept*w + xCept)
140cb93a386Sopenharmony_ci        B -= C;  // B = b*w - w * xCept + xCept - a
141cb93a386Sopenharmony_ci        C -= axisIntercept;
142cb93a386Sopenharmony_ci        return SkDQuad::RootsValidT(A, 2 * B, C, roots);
143cb93a386Sopenharmony_ci    }
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci    int verticalIntersect(double axisIntercept, double roots[2]) {
146cb93a386Sopenharmony_ci        double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX };
147cb93a386Sopenharmony_ci        return this->validT(conicVals, axisIntercept, roots);
148cb93a386Sopenharmony_ci    }
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci    int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
151cb93a386Sopenharmony_ci        this->addExactVerticalEndPoints(top, bottom, axisIntercept);
152cb93a386Sopenharmony_ci        if (fAllowNear) {
153cb93a386Sopenharmony_ci            this->addNearVerticalEndPoints(top, bottom, axisIntercept);
154cb93a386Sopenharmony_ci        }
155cb93a386Sopenharmony_ci        double roots[2];
156cb93a386Sopenharmony_ci        int count = this->verticalIntersect(axisIntercept, roots);
157cb93a386Sopenharmony_ci        for (int index = 0; index < count; ++index) {
158cb93a386Sopenharmony_ci            double conicT = roots[index];
159cb93a386Sopenharmony_ci            SkDPoint pt = fConic.ptAtT(conicT);
160cb93a386Sopenharmony_ci            SkDEBUGCODE(double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX });
161cb93a386Sopenharmony_ci            SkOPOBJASSERT(fIntersections, close_to(pt.fX, axisIntercept, conicVals));
162cb93a386Sopenharmony_ci            double lineT = (pt.fY - top) / (bottom - top);
163cb93a386Sopenharmony_ci            if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized)
164cb93a386Sopenharmony_ci                    && this->uniqueAnswer(conicT, pt)) {
165cb93a386Sopenharmony_ci                fIntersections->insert(conicT, lineT, pt);
166cb93a386Sopenharmony_ci            }
167cb93a386Sopenharmony_ci        }
168cb93a386Sopenharmony_ci        if (flipped) {
169cb93a386Sopenharmony_ci            fIntersections->flip();
170cb93a386Sopenharmony_ci        }
171cb93a386Sopenharmony_ci        this->checkCoincident();
172cb93a386Sopenharmony_ci        return fIntersections->used();
173cb93a386Sopenharmony_ci    }
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ciprotected:
176cb93a386Sopenharmony_ci// OPTIMIZE: Functions of the form add .. points are indentical to the conic routines.
177cb93a386Sopenharmony_ci    // add endpoints first to get zero and one t values exactly
178cb93a386Sopenharmony_ci    void addExactEndPoints() {
179cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic::kPointLast) {
180cb93a386Sopenharmony_ci            double lineT = fLine->exactPoint(fConic[cIndex]);
181cb93a386Sopenharmony_ci            if (lineT < 0) {
182cb93a386Sopenharmony_ci                continue;
183cb93a386Sopenharmony_ci            }
184cb93a386Sopenharmony_ci            double conicT = (double) (cIndex >> 1);
185cb93a386Sopenharmony_ci            fIntersections->insert(conicT, lineT, fConic[cIndex]);
186cb93a386Sopenharmony_ci        }
187cb93a386Sopenharmony_ci    }
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci    void addNearEndPoints() {
190cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic::kPointLast) {
191cb93a386Sopenharmony_ci            double conicT = (double) (cIndex >> 1);
192cb93a386Sopenharmony_ci            if (fIntersections->hasT(conicT)) {
193cb93a386Sopenharmony_ci                continue;
194cb93a386Sopenharmony_ci            }
195cb93a386Sopenharmony_ci            double lineT = fLine->nearPoint(fConic[cIndex], nullptr);
196cb93a386Sopenharmony_ci            if (lineT < 0) {
197cb93a386Sopenharmony_ci                continue;
198cb93a386Sopenharmony_ci            }
199cb93a386Sopenharmony_ci            fIntersections->insert(conicT, lineT, fConic[cIndex]);
200cb93a386Sopenharmony_ci        }
201cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
202cb93a386Sopenharmony_ci    }
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci    void addLineNearEndPoints() {
205cb93a386Sopenharmony_ci        for (int lIndex = 0; lIndex < 2; ++lIndex) {
206cb93a386Sopenharmony_ci            double lineT = (double) lIndex;
207cb93a386Sopenharmony_ci            if (fIntersections->hasOppT(lineT)) {
208cb93a386Sopenharmony_ci                continue;
209cb93a386Sopenharmony_ci            }
210cb93a386Sopenharmony_ci            double conicT = ((SkDCurve*) &fConic)->nearPoint(SkPath::kConic_Verb,
211cb93a386Sopenharmony_ci                (*fLine)[lIndex], (*fLine)[!lIndex]);
212cb93a386Sopenharmony_ci            if (conicT < 0) {
213cb93a386Sopenharmony_ci                continue;
214cb93a386Sopenharmony_ci            }
215cb93a386Sopenharmony_ci            fIntersections->insert(conicT, lineT, (*fLine)[lIndex]);
216cb93a386Sopenharmony_ci        }
217cb93a386Sopenharmony_ci    }
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_ci    void addExactHorizontalEndPoints(double left, double right, double y) {
220cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic::kPointLast) {
221cb93a386Sopenharmony_ci            double lineT = SkDLine::ExactPointH(fConic[cIndex], left, right, y);
222cb93a386Sopenharmony_ci            if (lineT < 0) {
223cb93a386Sopenharmony_ci                continue;
224cb93a386Sopenharmony_ci            }
225cb93a386Sopenharmony_ci            double conicT = (double) (cIndex >> 1);
226cb93a386Sopenharmony_ci            fIntersections->insert(conicT, lineT, fConic[cIndex]);
227cb93a386Sopenharmony_ci        }
228cb93a386Sopenharmony_ci    }
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    void addNearHorizontalEndPoints(double left, double right, double y) {
231cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic::kPointLast) {
232cb93a386Sopenharmony_ci            double conicT = (double) (cIndex >> 1);
233cb93a386Sopenharmony_ci            if (fIntersections->hasT(conicT)) {
234cb93a386Sopenharmony_ci                continue;
235cb93a386Sopenharmony_ci            }
236cb93a386Sopenharmony_ci            double lineT = SkDLine::NearPointH(fConic[cIndex], left, right, y);
237cb93a386Sopenharmony_ci            if (lineT < 0) {
238cb93a386Sopenharmony_ci                continue;
239cb93a386Sopenharmony_ci            }
240cb93a386Sopenharmony_ci            fIntersections->insert(conicT, lineT, fConic[cIndex]);
241cb93a386Sopenharmony_ci        }
242cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
243cb93a386Sopenharmony_ci    }
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    void addExactVerticalEndPoints(double top, double bottom, double x) {
246cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic::kPointLast) {
247cb93a386Sopenharmony_ci            double lineT = SkDLine::ExactPointV(fConic[cIndex], top, bottom, x);
248cb93a386Sopenharmony_ci            if (lineT < 0) {
249cb93a386Sopenharmony_ci                continue;
250cb93a386Sopenharmony_ci            }
251cb93a386Sopenharmony_ci            double conicT = (double) (cIndex >> 1);
252cb93a386Sopenharmony_ci            fIntersections->insert(conicT, lineT, fConic[cIndex]);
253cb93a386Sopenharmony_ci        }
254cb93a386Sopenharmony_ci    }
255cb93a386Sopenharmony_ci
256cb93a386Sopenharmony_ci    void addNearVerticalEndPoints(double top, double bottom, double x) {
257cb93a386Sopenharmony_ci        for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic::kPointLast) {
258cb93a386Sopenharmony_ci            double conicT = (double) (cIndex >> 1);
259cb93a386Sopenharmony_ci            if (fIntersections->hasT(conicT)) {
260cb93a386Sopenharmony_ci                continue;
261cb93a386Sopenharmony_ci            }
262cb93a386Sopenharmony_ci            double lineT = SkDLine::NearPointV(fConic[cIndex], top, bottom, x);
263cb93a386Sopenharmony_ci            if (lineT < 0) {
264cb93a386Sopenharmony_ci                continue;
265cb93a386Sopenharmony_ci            }
266cb93a386Sopenharmony_ci            fIntersections->insert(conicT, lineT, fConic[cIndex]);
267cb93a386Sopenharmony_ci        }
268cb93a386Sopenharmony_ci        this->addLineNearEndPoints();
269cb93a386Sopenharmony_ci    }
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci    double findLineT(double t) {
272cb93a386Sopenharmony_ci        SkDPoint xy = fConic.ptAtT(t);
273cb93a386Sopenharmony_ci        double dx = (*fLine)[1].fX - (*fLine)[0].fX;
274cb93a386Sopenharmony_ci        double dy = (*fLine)[1].fY - (*fLine)[0].fY;
275cb93a386Sopenharmony_ci        if (fabs(dx) > fabs(dy)) {
276cb93a386Sopenharmony_ci            return (xy.fX - (*fLine)[0].fX) / dx;
277cb93a386Sopenharmony_ci        }
278cb93a386Sopenharmony_ci        return (xy.fY - (*fLine)[0].fY) / dy;
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci    bool pinTs(double* conicT, double* lineT, SkDPoint* pt, PinTPoint ptSet) {
282cb93a386Sopenharmony_ci        if (!approximately_one_or_less_double(*lineT)) {
283cb93a386Sopenharmony_ci            return false;
284cb93a386Sopenharmony_ci        }
285cb93a386Sopenharmony_ci        if (!approximately_zero_or_more_double(*lineT)) {
286cb93a386Sopenharmony_ci            return false;
287cb93a386Sopenharmony_ci        }
288cb93a386Sopenharmony_ci        double qT = *conicT = SkPinT(*conicT);
289cb93a386Sopenharmony_ci        double lT = *lineT = SkPinT(*lineT);
290cb93a386Sopenharmony_ci        if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT != 1)) {
291cb93a386Sopenharmony_ci            *pt = (*fLine).ptAtT(lT);
292cb93a386Sopenharmony_ci        } else if (ptSet == kPointUninitialized) {
293cb93a386Sopenharmony_ci            *pt = fConic.ptAtT(qT);
294cb93a386Sopenharmony_ci        }
295cb93a386Sopenharmony_ci        SkPoint gridPt = pt->asSkPoint();
296cb93a386Sopenharmony_ci        if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[0].asSkPoint())) {
297cb93a386Sopenharmony_ci            *pt = (*fLine)[0];
298cb93a386Sopenharmony_ci            *lineT = 0;
299cb93a386Sopenharmony_ci        } else if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[1].asSkPoint())) {
300cb93a386Sopenharmony_ci            *pt = (*fLine)[1];
301cb93a386Sopenharmony_ci            *lineT = 1;
302cb93a386Sopenharmony_ci        }
303cb93a386Sopenharmony_ci        if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[1][0], *lineT)) {
304cb93a386Sopenharmony_ci            return false;
305cb93a386Sopenharmony_ci        }
306cb93a386Sopenharmony_ci        if (gridPt == fConic[0].asSkPoint()) {
307cb93a386Sopenharmony_ci            *pt = fConic[0];
308cb93a386Sopenharmony_ci            *conicT = 0;
309cb93a386Sopenharmony_ci        } else if (gridPt == fConic[2].asSkPoint()) {
310cb93a386Sopenharmony_ci            *pt = fConic[2];
311cb93a386Sopenharmony_ci            *conicT = 1;
312cb93a386Sopenharmony_ci        }
313cb93a386Sopenharmony_ci        return true;
314cb93a386Sopenharmony_ci    }
315cb93a386Sopenharmony_ci
316cb93a386Sopenharmony_ci    bool uniqueAnswer(double conicT, const SkDPoint& pt) {
317cb93a386Sopenharmony_ci        for (int inner = 0; inner < fIntersections->used(); ++inner) {
318cb93a386Sopenharmony_ci            if (fIntersections->pt(inner) != pt) {
319cb93a386Sopenharmony_ci                continue;
320cb93a386Sopenharmony_ci            }
321cb93a386Sopenharmony_ci            double existingConicT = (*fIntersections)[0][inner];
322cb93a386Sopenharmony_ci            if (conicT == existingConicT) {
323cb93a386Sopenharmony_ci                return false;
324cb93a386Sopenharmony_ci            }
325cb93a386Sopenharmony_ci            // check if midway on conic is also same point. If so, discard this
326cb93a386Sopenharmony_ci            double conicMidT = (existingConicT + conicT) / 2;
327cb93a386Sopenharmony_ci            SkDPoint conicMidPt = fConic.ptAtT(conicMidT);
328cb93a386Sopenharmony_ci            if (conicMidPt.approximatelyEqual(pt)) {
329cb93a386Sopenharmony_ci                return false;
330cb93a386Sopenharmony_ci            }
331cb93a386Sopenharmony_ci        }
332cb93a386Sopenharmony_ci#if ONE_OFF_DEBUG
333cb93a386Sopenharmony_ci        SkDPoint qPt = fConic.ptAtT(conicT);
334cb93a386Sopenharmony_ci        SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY,
335cb93a386Sopenharmony_ci                qPt.fX, qPt.fY);
336cb93a386Sopenharmony_ci#endif
337cb93a386Sopenharmony_ci        return true;
338cb93a386Sopenharmony_ci    }
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ciprivate:
341cb93a386Sopenharmony_ci    const SkDConic& fConic;
342cb93a386Sopenharmony_ci    const SkDLine* fLine;
343cb93a386Sopenharmony_ci    SkIntersections* fIntersections;
344cb93a386Sopenharmony_ci    bool fAllowNear;
345cb93a386Sopenharmony_ci};
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ciint SkIntersections::horizontal(const SkDConic& conic, double left, double right, double y,
348cb93a386Sopenharmony_ci                                bool flipped) {
349cb93a386Sopenharmony_ci    SkDLine line = {{{ left, y }, { right, y }}};
350cb93a386Sopenharmony_ci    LineConicIntersections c(conic, line, this);
351cb93a386Sopenharmony_ci    return c.horizontalIntersect(y, left, right, flipped);
352cb93a386Sopenharmony_ci}
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_ciint SkIntersections::vertical(const SkDConic& conic, double top, double bottom, double x,
355cb93a386Sopenharmony_ci                              bool flipped) {
356cb93a386Sopenharmony_ci    SkDLine line = {{{ x, top }, { x, bottom }}};
357cb93a386Sopenharmony_ci    LineConicIntersections c(conic, line, this);
358cb93a386Sopenharmony_ci    return c.verticalIntersect(x, top, bottom, flipped);
359cb93a386Sopenharmony_ci}
360cb93a386Sopenharmony_ci
361cb93a386Sopenharmony_ciint SkIntersections::intersect(const SkDConic& conic, const SkDLine& line) {
362cb93a386Sopenharmony_ci    LineConicIntersections c(conic, line, this);
363cb93a386Sopenharmony_ci    c.allowNear(fAllowNear);
364cb93a386Sopenharmony_ci    return c.intersect();
365cb93a386Sopenharmony_ci}
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ciint SkIntersections::intersectRay(const SkDConic& conic, const SkDLine& line) {
368cb93a386Sopenharmony_ci    LineConicIntersections c(conic, line, this);
369cb93a386Sopenharmony_ci    fUsed = c.intersectRay(fT[0]);
370cb93a386Sopenharmony_ci    for (int index = 0; index < fUsed; ++index) {
371cb93a386Sopenharmony_ci        fPt[index] = conic.ptAtT(fT[0][index]);
372cb93a386Sopenharmony_ci    }
373cb93a386Sopenharmony_ci    return fUsed;
374cb93a386Sopenharmony_ci}
375cb93a386Sopenharmony_ci
376cb93a386Sopenharmony_ciint SkIntersections::HorizontalIntercept(const SkDConic& conic, SkScalar y, double* roots) {
377cb93a386Sopenharmony_ci    LineConicIntersections c(conic);
378cb93a386Sopenharmony_ci    return c.horizontalIntersect(y, roots);
379cb93a386Sopenharmony_ci}
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ciint SkIntersections::VerticalIntercept(const SkDConic& conic, SkScalar x, double* roots) {
382cb93a386Sopenharmony_ci    LineConicIntersections c(conic);
383cb93a386Sopenharmony_ci    return c.verticalIntersect(x, roots);
384cb93a386Sopenharmony_ci}
385