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