xref: /aosp_15_r20/external/skia/src/pathops/SkPathOpsCurve.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #ifndef SkPathOpsCurve_DEFINE
8 #define SkPathOpsCurve_DEFINE
9 
10 #include "include/core/SkPath.h"
11 #include "include/core/SkPoint.h"
12 #include "include/core/SkScalar.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/base/SkDebug.h"
15 #include "src/pathops/SkIntersections.h"
16 #include "src/pathops/SkPathOpsConic.h"
17 #include "src/pathops/SkPathOpsCubic.h"
18 #include "src/pathops/SkPathOpsLine.h"
19 #include "src/pathops/SkPathOpsPoint.h"
20 #include "src/pathops/SkPathOpsQuad.h"
21 #include "src/pathops/SkPathOpsTypes.h"
22 
23 struct SkPathOpsBounds;
24 
25 struct SkOpCurve {
26     SkPoint fPts[4];
27     SkScalar fWeight;
SkDEBUGCODESkOpCurve28     SkDEBUGCODE(SkPath::Verb fVerb;)
29 
30     const SkPoint& operator[](int n) const {
31         SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb));
32         return fPts[n];
33     }
34 
35     void dump() const;
36 
setSkOpCurve37     void set(const SkDQuad& quad) {
38         for (int index = 0; index < SkDQuad::kPointCount; ++index) {
39             fPts[index] = quad[index].asSkPoint();
40         }
41         SkDEBUGCODE(fWeight = 1);
42         SkDEBUGCODE(fVerb = SkPath::kQuad_Verb);
43     }
44 
setSkOpCurve45     void set(const SkDCubic& cubic) {
46         for (int index = 0; index < SkDCubic::kPointCount; ++index) {
47             fPts[index] = cubic[index].asSkPoint();
48         }
49         SkDEBUGCODE(fWeight = 1);
50         SkDEBUGCODE(fVerb = SkPath::kCubic_Verb);
51     }
52 
53 };
54 
55 struct SkDCurve {
56     union {
57         SkDLine fLine;
58         SkDQuad fQuad;
59         SkDConic fConic;
60         SkDCubic fCubic;
61     };
SkDEBUGCODESkDCurve62     SkDEBUGCODE(SkPath::Verb fVerb;)
63 
64     const SkDPoint& operator[](int n) const {
65         SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb));
66         return fCubic[n];
67     }
68 
69     SkDPoint& operator[](int n) {
70         SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb));
71         return fCubic[n];
72     }
73 
74     SkDPoint conicTop(const SkPoint curve[3], SkScalar curveWeight,
75                       double s, double e, double* topT);
76     SkDPoint cubicTop(const SkPoint curve[4], SkScalar , double s, double e, double* topT);
77     void dump() const;
78     void dumpID(int ) const;
79     SkDPoint lineTop(const SkPoint[2], SkScalar , double , double , double* topT);
80     double nearPoint(SkPath::Verb verb, const SkDPoint& xy, const SkDPoint& opp) const;
81     SkDPoint quadTop(const SkPoint curve[3], SkScalar , double s, double e, double* topT);
82 
83     void setConicBounds(const SkPoint curve[3], SkScalar curveWeight,
84                         double s, double e, SkPathOpsBounds* );
85     void setCubicBounds(const SkPoint curve[4], SkScalar ,
86                         double s, double e, SkPathOpsBounds* );
87     void setQuadBounds(const SkPoint curve[3], SkScalar ,
88                        double s, double e, SkPathOpsBounds*);
89 };
90 
91 class SkDCurveSweep {
92 public:
isCurve()93     bool isCurve() const { return fIsCurve; }
isOrdered()94     bool isOrdered() const { return fOrdered; }
95     void setCurveHullSweep(SkPath::Verb verb);
96 
97     SkDCurve fCurve;
98     SkDVector fSweep[2];
99 private:
100     bool fIsCurve;
101     bool fOrdered;  // cleared when a cubic's control point isn't between the sweep vectors
102 
103 };
104 
105 extern SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar cWeight,
106     double tStart, double tEnd, double* topT);
107 
dline_xy_at_t(const SkPoint a[2],SkScalar,double t)108 static SkDPoint dline_xy_at_t(const SkPoint a[2], SkScalar , double t) {
109     SkDLine line;
110     line.set(a);
111     return line.ptAtT(t);
112 }
113 
dquad_xy_at_t(const SkPoint a[3],SkScalar,double t)114 static SkDPoint dquad_xy_at_t(const SkPoint a[3], SkScalar , double t) {
115     SkDQuad quad;
116     quad.set(a);
117     return quad.ptAtT(t);
118 }
119 
dconic_xy_at_t(const SkPoint a[3],SkScalar weight,double t)120 static SkDPoint dconic_xy_at_t(const SkPoint a[3], SkScalar weight, double t) {
121     SkDConic conic;
122     conic.set(a, weight);
123     return conic.ptAtT(t);
124 }
125 
dcubic_xy_at_t(const SkPoint a[4],SkScalar,double t)126 static SkDPoint dcubic_xy_at_t(const SkPoint a[4], SkScalar , double t) {
127     SkDCubic cubic;
128     cubic.set(a);
129     return cubic.ptAtT(t);
130 }
131 
132 static SkDPoint (* const CurveDPointAtT[])(const SkPoint[], SkScalar , double ) = {
133     nullptr,
134     dline_xy_at_t,
135     dquad_xy_at_t,
136     dconic_xy_at_t,
137     dcubic_xy_at_t
138 };
139 
ddline_xy_at_t(const SkDCurve & c,double t)140 static SkDPoint ddline_xy_at_t(const SkDCurve& c, double t) {
141     return c.fLine.ptAtT(t);
142 }
143 
ddquad_xy_at_t(const SkDCurve & c,double t)144 static SkDPoint ddquad_xy_at_t(const SkDCurve& c, double t) {
145     return c.fQuad.ptAtT(t);
146 }
147 
ddconic_xy_at_t(const SkDCurve & c,double t)148 static SkDPoint ddconic_xy_at_t(const SkDCurve& c, double t) {
149     return c.fConic.ptAtT(t);
150 }
151 
ddcubic_xy_at_t(const SkDCurve & c,double t)152 static SkDPoint ddcubic_xy_at_t(const SkDCurve& c, double t) {
153     return c.fCubic.ptAtT(t);
154 }
155 
156 static SkDPoint (* const CurveDDPointAtT[])(const SkDCurve& , double ) = {
157     nullptr,
158     ddline_xy_at_t,
159     ddquad_xy_at_t,
160     ddconic_xy_at_t,
161     ddcubic_xy_at_t
162 };
163 
fline_xy_at_t(const SkPoint a[2],SkScalar weight,double t)164 static SkPoint fline_xy_at_t(const SkPoint a[2], SkScalar weight, double t) {
165     return dline_xy_at_t(a, weight, t).asSkPoint();
166 }
167 
fquad_xy_at_t(const SkPoint a[3],SkScalar weight,double t)168 static SkPoint fquad_xy_at_t(const SkPoint a[3], SkScalar weight, double t) {
169     return dquad_xy_at_t(a, weight, t).asSkPoint();
170 }
171 
fconic_xy_at_t(const SkPoint a[3],SkScalar weight,double t)172 static SkPoint fconic_xy_at_t(const SkPoint a[3], SkScalar weight, double t) {
173     return dconic_xy_at_t(a, weight, t).asSkPoint();
174 }
175 
fcubic_xy_at_t(const SkPoint a[4],SkScalar weight,double t)176 static SkPoint fcubic_xy_at_t(const SkPoint a[4], SkScalar weight, double t) {
177     return dcubic_xy_at_t(a, weight, t).asSkPoint();
178 }
179 
180 static SkPoint (* const CurvePointAtT[])(const SkPoint[], SkScalar , double ) = {
181     nullptr,
182     fline_xy_at_t,
183     fquad_xy_at_t,
184     fconic_xy_at_t,
185     fcubic_xy_at_t
186 };
187 
dline_dxdy_at_t(const SkPoint a[2],SkScalar,double)188 static SkDVector dline_dxdy_at_t(const SkPoint a[2], SkScalar , double ) {
189     SkDLine line;
190     line.set(a);
191     return line[1] - line[0];
192 }
193 
dquad_dxdy_at_t(const SkPoint a[3],SkScalar,double t)194 static SkDVector dquad_dxdy_at_t(const SkPoint a[3], SkScalar , double t) {
195     SkDQuad quad;
196     quad.set(a);
197     return quad.dxdyAtT(t);
198 }
199 
dconic_dxdy_at_t(const SkPoint a[3],SkScalar weight,double t)200 static SkDVector dconic_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) {
201     SkDConic conic;
202     conic.set(a, weight);
203     return conic.dxdyAtT(t);
204 }
205 
dcubic_dxdy_at_t(const SkPoint a[4],SkScalar,double t)206 static SkDVector dcubic_dxdy_at_t(const SkPoint a[4], SkScalar , double t) {
207     SkDCubic cubic;
208     cubic.set(a);
209     return cubic.dxdyAtT(t);
210 }
211 
212 static SkDVector (* const CurveDSlopeAtT[])(const SkPoint[], SkScalar , double ) = {
213     nullptr,
214     dline_dxdy_at_t,
215     dquad_dxdy_at_t,
216     dconic_dxdy_at_t,
217     dcubic_dxdy_at_t
218 };
219 
ddline_dxdy_at_t(const SkDCurve & c,double)220 static SkDVector ddline_dxdy_at_t(const SkDCurve& c, double ) {
221     return c.fLine.fPts[1] - c.fLine.fPts[0];
222 }
223 
ddquad_dxdy_at_t(const SkDCurve & c,double t)224 static SkDVector ddquad_dxdy_at_t(const SkDCurve& c, double t) {
225     return c.fQuad.dxdyAtT(t);
226 }
227 
ddconic_dxdy_at_t(const SkDCurve & c,double t)228 static SkDVector ddconic_dxdy_at_t(const SkDCurve& c, double t) {
229     return c.fConic.dxdyAtT(t);
230 }
231 
ddcubic_dxdy_at_t(const SkDCurve & c,double t)232 static SkDVector ddcubic_dxdy_at_t(const SkDCurve& c, double t) {
233     return c.fCubic.dxdyAtT(t);
234 }
235 
236 static SkDVector (* const CurveDDSlopeAtT[])(const SkDCurve& , double ) = {
237     nullptr,
238     ddline_dxdy_at_t,
239     ddquad_dxdy_at_t,
240     ddconic_dxdy_at_t,
241     ddcubic_dxdy_at_t
242 };
243 
fline_dxdy_at_t(const SkPoint a[2],SkScalar,double)244 static SkVector fline_dxdy_at_t(const SkPoint a[2], SkScalar , double ) {
245     return a[1] - a[0];
246 }
247 
fquad_dxdy_at_t(const SkPoint a[3],SkScalar weight,double t)248 static SkVector fquad_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) {
249     return dquad_dxdy_at_t(a, weight, t).asSkVector();
250 }
251 
fconic_dxdy_at_t(const SkPoint a[3],SkScalar weight,double t)252 static SkVector fconic_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) {
253     return dconic_dxdy_at_t(a, weight, t).asSkVector();
254 }
255 
fcubic_dxdy_at_t(const SkPoint a[4],SkScalar weight,double t)256 static SkVector fcubic_dxdy_at_t(const SkPoint a[4], SkScalar weight, double t) {
257     return dcubic_dxdy_at_t(a, weight, t).asSkVector();
258 }
259 
260 static SkVector (* const CurveSlopeAtT[])(const SkPoint[], SkScalar , double ) = {
261     nullptr,
262     fline_dxdy_at_t,
263     fquad_dxdy_at_t,
264     fconic_dxdy_at_t,
265     fcubic_dxdy_at_t
266 };
267 
line_is_vertical(const SkPoint a[2],SkScalar,double startT,double endT)268 static bool line_is_vertical(const SkPoint a[2], SkScalar , double startT, double endT) {
269     SkDLine line;
270     line.set(a);
271     SkDPoint dst[2] = { line.ptAtT(startT), line.ptAtT(endT) };
272     return AlmostEqualUlps(dst[0].fX, dst[1].fX);
273 }
274 
quad_is_vertical(const SkPoint a[3],SkScalar,double startT,double endT)275 static bool quad_is_vertical(const SkPoint a[3], SkScalar , double startT, double endT) {
276     SkDQuad quad;
277     quad.set(a);
278     SkDQuad dst = quad.subDivide(startT, endT);
279     return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
280 }
281 
conic_is_vertical(const SkPoint a[3],SkScalar weight,double startT,double endT)282 static bool conic_is_vertical(const SkPoint a[3], SkScalar weight, double startT, double endT) {
283     SkDConic conic;
284     conic.set(a, weight);
285     SkDConic dst = conic.subDivide(startT, endT);
286     return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX);
287 }
288 
cubic_is_vertical(const SkPoint a[4],SkScalar,double startT,double endT)289 static bool cubic_is_vertical(const SkPoint a[4], SkScalar , double startT, double endT) {
290     SkDCubic cubic;
291     cubic.set(a);
292     SkDCubic dst = cubic.subDivide(startT, endT);
293     return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX)
294             && AlmostEqualUlps(dst[2].fX, dst[3].fX);
295 }
296 
297 static bool (* const CurveIsVertical[])(const SkPoint[], SkScalar , double , double) = {
298     nullptr,
299     line_is_vertical,
300     quad_is_vertical,
301     conic_is_vertical,
302     cubic_is_vertical
303 };
304 
line_intersect_ray(const SkPoint a[2],SkScalar,const SkDLine & ray,SkIntersections * i)305 static void line_intersect_ray(const SkPoint a[2], SkScalar , const SkDLine& ray,
306         SkIntersections* i) {
307     SkDLine line;
308     line.set(a);
309     i->intersectRay(line, ray);
310 }
311 
quad_intersect_ray(const SkPoint a[3],SkScalar,const SkDLine & ray,SkIntersections * i)312 static void quad_intersect_ray(const SkPoint a[3], SkScalar , const SkDLine& ray,
313         SkIntersections* i) {
314     SkDQuad quad;
315     quad.set(a);
316     i->intersectRay(quad, ray);
317 }
318 
conic_intersect_ray(const SkPoint a[3],SkScalar weight,const SkDLine & ray,SkIntersections * i)319 static void conic_intersect_ray(const SkPoint a[3], SkScalar weight, const SkDLine& ray,
320         SkIntersections* i) {
321     SkDConic conic;
322     conic.set(a, weight);
323     i->intersectRay(conic, ray);
324 }
325 
cubic_intersect_ray(const SkPoint a[4],SkScalar,const SkDLine & ray,SkIntersections * i)326 static void cubic_intersect_ray(const SkPoint a[4], SkScalar , const SkDLine& ray,
327         SkIntersections* i) {
328     SkDCubic cubic;
329     cubic.set(a);
330     i->intersectRay(cubic, ray);
331 }
332 
333 static void (* const CurveIntersectRay[])(const SkPoint[] , SkScalar , const SkDLine& ,
334         SkIntersections* ) = {
335     nullptr,
336     line_intersect_ray,
337     quad_intersect_ray,
338     conic_intersect_ray,
339     cubic_intersect_ray
340 };
341 
dline_intersect_ray(const SkDCurve & c,const SkDLine & ray,SkIntersections * i)342 static void dline_intersect_ray(const SkDCurve& c, const SkDLine& ray,  SkIntersections* i) {
343     i->intersectRay(c.fLine, ray);
344 }
345 
dquad_intersect_ray(const SkDCurve & c,const SkDLine & ray,SkIntersections * i)346 static void dquad_intersect_ray(const SkDCurve& c, const SkDLine& ray, SkIntersections* i) {
347     i->intersectRay(c.fQuad, ray);
348 }
349 
dconic_intersect_ray(const SkDCurve & c,const SkDLine & ray,SkIntersections * i)350 static void dconic_intersect_ray(const SkDCurve& c, const SkDLine& ray, SkIntersections* i) {
351     i->intersectRay(c.fConic, ray);
352 }
353 
dcubic_intersect_ray(const SkDCurve & c,const SkDLine & ray,SkIntersections * i)354 static void dcubic_intersect_ray(const SkDCurve& c, const SkDLine& ray, SkIntersections* i) {
355     i->intersectRay(c.fCubic, ray);
356 }
357 
358 static void (* const CurveDIntersectRay[])(const SkDCurve& , const SkDLine& , SkIntersections* ) = {
359     nullptr,
360     dline_intersect_ray,
361     dquad_intersect_ray,
362     dconic_intersect_ray,
363     dcubic_intersect_ray
364 };
365 
line_intercept_h(const SkPoint a[2],SkScalar,SkScalar y,double * roots)366 static int line_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) {
367     if (a[0].fY == a[1].fY) {
368         return false;
369     }
370     SkDLine line;
371     roots[0] = SkIntersections::HorizontalIntercept(line.set(a), y);
372     return between(0, roots[0], 1);
373 }
374 
line_intercept_v(const SkPoint a[2],SkScalar,SkScalar x,double * roots)375 static int line_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) {
376     if (a[0].fX == a[1].fX) {
377         return false;
378     }
379     SkDLine line;
380     roots[0] = SkIntersections::VerticalIntercept(line.set(a), x);
381     return between(0, roots[0], 1);
382 }
383 
quad_intercept_h(const SkPoint a[2],SkScalar,SkScalar y,double * roots)384 static int quad_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) {
385     SkDQuad quad;
386     return SkIntersections::HorizontalIntercept(quad.set(a), y, roots);
387 }
388 
quad_intercept_v(const SkPoint a[2],SkScalar,SkScalar x,double * roots)389 static int quad_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) {
390     SkDQuad quad;
391     return SkIntersections::VerticalIntercept(quad.set(a), x, roots);
392 }
393 
conic_intercept_h(const SkPoint a[2],SkScalar w,SkScalar y,double * roots)394 static int conic_intercept_h(const SkPoint a[2], SkScalar w, SkScalar y, double* roots) {
395     SkDConic conic;
396     return SkIntersections::HorizontalIntercept(conic.set(a, w), y, roots);
397 }
398 
conic_intercept_v(const SkPoint a[2],SkScalar w,SkScalar x,double * roots)399 static int conic_intercept_v(const SkPoint a[2], SkScalar w, SkScalar x, double* roots) {
400     SkDConic conic;
401     return SkIntersections::VerticalIntercept(conic.set(a, w), x, roots);
402 }
403 
cubic_intercept_h(const SkPoint a[3],SkScalar,SkScalar y,double * roots)404 static int cubic_intercept_h(const SkPoint a[3], SkScalar , SkScalar y, double* roots) {
405     SkDCubic cubic;
406     return cubic.set(a).horizontalIntersect(y, roots);
407 }
408 
cubic_intercept_v(const SkPoint a[3],SkScalar,SkScalar x,double * roots)409 static int cubic_intercept_v(const SkPoint a[3], SkScalar , SkScalar x, double* roots) {
410     SkDCubic cubic;
411     return cubic.set(a).verticalIntersect(x, roots);
412 }
413 
414 static int (* const CurveIntercept[])(const SkPoint[] , SkScalar , SkScalar , double* ) = {
415     nullptr,
416     nullptr,
417     line_intercept_h,
418     line_intercept_v,
419     quad_intercept_h,
420     quad_intercept_v,
421     conic_intercept_h,
422     conic_intercept_v,
423     cubic_intercept_h,
424     cubic_intercept_v,
425 };
426 
427 #endif
428