xref: /aosp_15_r20/external/skia/src/pathops/SkLineParameters.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 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 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkLineParameters_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkLineParameters_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsCubic.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsLine.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsQuad.h"
14*c8dee2aaSAndroid Build Coastguard Worker 
15*c8dee2aaSAndroid Build Coastguard Worker // Sources
16*c8dee2aaSAndroid Build Coastguard Worker // computer-aided design - volume 22 number 9 november 1990 pp 538 - 549
17*c8dee2aaSAndroid Build Coastguard Worker // online at http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker // This turns a line segment into a parameterized line, of the form
20*c8dee2aaSAndroid Build Coastguard Worker // ax + by + c = 0
21*c8dee2aaSAndroid Build Coastguard Worker // When a^2 + b^2 == 1, the line is normalized.
22*c8dee2aaSAndroid Build Coastguard Worker // The distance to the line for (x, y) is d(x,y) = ax + by + c
23*c8dee2aaSAndroid Build Coastguard Worker //
24*c8dee2aaSAndroid Build Coastguard Worker // Note that the distances below are not necessarily normalized. To get the true
25*c8dee2aaSAndroid Build Coastguard Worker // distance, it's necessary to either call normalize() after xxxEndPoints(), or
26*c8dee2aaSAndroid Build Coastguard Worker // divide the result of xxxDistance() by sqrt(normalSquared())
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker class SkLineParameters {
29*c8dee2aaSAndroid Build Coastguard Worker public:
30*c8dee2aaSAndroid Build Coastguard Worker 
cubicEndPoints(const SkDCubic & pts)31*c8dee2aaSAndroid Build Coastguard Worker     bool cubicEndPoints(const SkDCubic& pts) {
32*c8dee2aaSAndroid Build Coastguard Worker         int endIndex = 1;
33*c8dee2aaSAndroid Build Coastguard Worker         cubicEndPoints(pts, 0, endIndex);
34*c8dee2aaSAndroid Build Coastguard Worker         if (dy() != 0) {
35*c8dee2aaSAndroid Build Coastguard Worker             return true;
36*c8dee2aaSAndroid Build Coastguard Worker         }
37*c8dee2aaSAndroid Build Coastguard Worker         if (dx() == 0) {
38*c8dee2aaSAndroid Build Coastguard Worker             cubicEndPoints(pts, 0, ++endIndex);
39*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(endIndex == 2);
40*c8dee2aaSAndroid Build Coastguard Worker             if (dy() != 0) {
41*c8dee2aaSAndroid Build Coastguard Worker                 return true;
42*c8dee2aaSAndroid Build Coastguard Worker             }
43*c8dee2aaSAndroid Build Coastguard Worker             if (dx() == 0) {
44*c8dee2aaSAndroid Build Coastguard Worker                 cubicEndPoints(pts, 0, ++endIndex);  // line
45*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(endIndex == 3);
46*c8dee2aaSAndroid Build Coastguard Worker                 return false;
47*c8dee2aaSAndroid Build Coastguard Worker             }
48*c8dee2aaSAndroid Build Coastguard Worker         }
49*c8dee2aaSAndroid Build Coastguard Worker         // FIXME: after switching to round sort, remove bumping fA
50*c8dee2aaSAndroid Build Coastguard Worker         if (dx() < 0) { // only worry about y bias when breaking cw/ccw tie
51*c8dee2aaSAndroid Build Coastguard Worker             return true;
52*c8dee2aaSAndroid Build Coastguard Worker         }
53*c8dee2aaSAndroid Build Coastguard Worker         // if cubic tangent is on x axis, look at next control point to break tie
54*c8dee2aaSAndroid Build Coastguard Worker         // control point may be approximate, so it must move significantly to account for error
55*c8dee2aaSAndroid Build Coastguard Worker         if (NotAlmostEqualUlps(pts[0].fY, pts[++endIndex].fY)) {
56*c8dee2aaSAndroid Build Coastguard Worker             if (pts[0].fY > pts[endIndex].fY) {
57*c8dee2aaSAndroid Build Coastguard Worker                 fA = DBL_EPSILON; // push it from 0 to slightly negative (y() returns -a)
58*c8dee2aaSAndroid Build Coastguard Worker             }
59*c8dee2aaSAndroid Build Coastguard Worker             return true;
60*c8dee2aaSAndroid Build Coastguard Worker         }
61*c8dee2aaSAndroid Build Coastguard Worker         if (endIndex == 3) {
62*c8dee2aaSAndroid Build Coastguard Worker             return true;
63*c8dee2aaSAndroid Build Coastguard Worker         }
64*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(endIndex == 2);
65*c8dee2aaSAndroid Build Coastguard Worker         if (pts[0].fY > pts[3].fY) {
66*c8dee2aaSAndroid Build Coastguard Worker             fA = DBL_EPSILON; // push it from 0 to slightly negative (y() returns -a)
67*c8dee2aaSAndroid Build Coastguard Worker         }
68*c8dee2aaSAndroid Build Coastguard Worker         return true;
69*c8dee2aaSAndroid Build Coastguard Worker     }
70*c8dee2aaSAndroid Build Coastguard Worker 
cubicEndPoints(const SkDCubic & pts,int s,int e)71*c8dee2aaSAndroid Build Coastguard Worker     void cubicEndPoints(const SkDCubic& pts, int s, int e) {
72*c8dee2aaSAndroid Build Coastguard Worker         fA = pts[s].fY - pts[e].fY;
73*c8dee2aaSAndroid Build Coastguard Worker         fB = pts[e].fX - pts[s].fX;
74*c8dee2aaSAndroid Build Coastguard Worker         fC = pts[s].fX * pts[e].fY - pts[e].fX * pts[s].fY;
75*c8dee2aaSAndroid Build Coastguard Worker     }
76*c8dee2aaSAndroid Build Coastguard Worker 
cubicPart(const SkDCubic & part)77*c8dee2aaSAndroid Build Coastguard Worker     double cubicPart(const SkDCubic& part) {
78*c8dee2aaSAndroid Build Coastguard Worker         cubicEndPoints(part);
79*c8dee2aaSAndroid Build Coastguard Worker         if (part[0] == part[1] || ((const SkDLine& ) part[0]).nearRay(part[2])) {
80*c8dee2aaSAndroid Build Coastguard Worker             return pointDistance(part[3]);
81*c8dee2aaSAndroid Build Coastguard Worker         }
82*c8dee2aaSAndroid Build Coastguard Worker         return pointDistance(part[2]);
83*c8dee2aaSAndroid Build Coastguard Worker     }
84*c8dee2aaSAndroid Build Coastguard Worker 
lineEndPoints(const SkDLine & pts)85*c8dee2aaSAndroid Build Coastguard Worker     void lineEndPoints(const SkDLine& pts) {
86*c8dee2aaSAndroid Build Coastguard Worker         fA = pts[0].fY - pts[1].fY;
87*c8dee2aaSAndroid Build Coastguard Worker         fB = pts[1].fX - pts[0].fX;
88*c8dee2aaSAndroid Build Coastguard Worker         fC = pts[0].fX * pts[1].fY - pts[1].fX * pts[0].fY;
89*c8dee2aaSAndroid Build Coastguard Worker     }
90*c8dee2aaSAndroid Build Coastguard Worker 
quadEndPoints(const SkDQuad & pts)91*c8dee2aaSAndroid Build Coastguard Worker     bool quadEndPoints(const SkDQuad& pts) {
92*c8dee2aaSAndroid Build Coastguard Worker         quadEndPoints(pts, 0, 1);
93*c8dee2aaSAndroid Build Coastguard Worker         if (dy() != 0) {
94*c8dee2aaSAndroid Build Coastguard Worker             return true;
95*c8dee2aaSAndroid Build Coastguard Worker         }
96*c8dee2aaSAndroid Build Coastguard Worker         if (dx() == 0) {
97*c8dee2aaSAndroid Build Coastguard Worker             quadEndPoints(pts, 0, 2);
98*c8dee2aaSAndroid Build Coastguard Worker             return false;
99*c8dee2aaSAndroid Build Coastguard Worker         }
100*c8dee2aaSAndroid Build Coastguard Worker         if (dx() < 0) { // only worry about y bias when breaking cw/ccw tie
101*c8dee2aaSAndroid Build Coastguard Worker             return true;
102*c8dee2aaSAndroid Build Coastguard Worker         }
103*c8dee2aaSAndroid Build Coastguard Worker         // FIXME: after switching to round sort, remove this
104*c8dee2aaSAndroid Build Coastguard Worker         if (pts[0].fY > pts[2].fY) {
105*c8dee2aaSAndroid Build Coastguard Worker             fA = DBL_EPSILON;
106*c8dee2aaSAndroid Build Coastguard Worker         }
107*c8dee2aaSAndroid Build Coastguard Worker         return true;
108*c8dee2aaSAndroid Build Coastguard Worker     }
109*c8dee2aaSAndroid Build Coastguard Worker 
quadEndPoints(const SkDQuad & pts,int s,int e)110*c8dee2aaSAndroid Build Coastguard Worker     void quadEndPoints(const SkDQuad& pts, int s, int e) {
111*c8dee2aaSAndroid Build Coastguard Worker         fA = pts[s].fY - pts[e].fY;
112*c8dee2aaSAndroid Build Coastguard Worker         fB = pts[e].fX - pts[s].fX;
113*c8dee2aaSAndroid Build Coastguard Worker         fC = pts[s].fX * pts[e].fY - pts[e].fX * pts[s].fY;
114*c8dee2aaSAndroid Build Coastguard Worker     }
115*c8dee2aaSAndroid Build Coastguard Worker 
quadPart(const SkDQuad & part)116*c8dee2aaSAndroid Build Coastguard Worker     double quadPart(const SkDQuad& part) {
117*c8dee2aaSAndroid Build Coastguard Worker         quadEndPoints(part);
118*c8dee2aaSAndroid Build Coastguard Worker         return pointDistance(part[2]);
119*c8dee2aaSAndroid Build Coastguard Worker     }
120*c8dee2aaSAndroid Build Coastguard Worker 
normalSquared()121*c8dee2aaSAndroid Build Coastguard Worker     double normalSquared() const {
122*c8dee2aaSAndroid Build Coastguard Worker         return fA * fA + fB * fB;
123*c8dee2aaSAndroid Build Coastguard Worker     }
124*c8dee2aaSAndroid Build Coastguard Worker 
normalize()125*c8dee2aaSAndroid Build Coastguard Worker     bool normalize() {
126*c8dee2aaSAndroid Build Coastguard Worker         double normal = sqrt(normalSquared());
127*c8dee2aaSAndroid Build Coastguard Worker         if (approximately_zero(normal)) {
128*c8dee2aaSAndroid Build Coastguard Worker             fA = fB = fC = 0;
129*c8dee2aaSAndroid Build Coastguard Worker             return false;
130*c8dee2aaSAndroid Build Coastguard Worker         }
131*c8dee2aaSAndroid Build Coastguard Worker         double reciprocal = 1 / normal;
132*c8dee2aaSAndroid Build Coastguard Worker         fA *= reciprocal;
133*c8dee2aaSAndroid Build Coastguard Worker         fB *= reciprocal;
134*c8dee2aaSAndroid Build Coastguard Worker         fC *= reciprocal;
135*c8dee2aaSAndroid Build Coastguard Worker         return true;
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker 
cubicDistanceY(const SkDCubic & pts,SkDCubic & distance)138*c8dee2aaSAndroid Build Coastguard Worker     void cubicDistanceY(const SkDCubic& pts, SkDCubic& distance) const {
139*c8dee2aaSAndroid Build Coastguard Worker         double oneThird = 1 / 3.0;
140*c8dee2aaSAndroid Build Coastguard Worker         for (int index = 0; index < 4; ++index) {
141*c8dee2aaSAndroid Build Coastguard Worker             distance[index].fX = index * oneThird;
142*c8dee2aaSAndroid Build Coastguard Worker             distance[index].fY = fA * pts[index].fX + fB * pts[index].fY + fC;
143*c8dee2aaSAndroid Build Coastguard Worker         }
144*c8dee2aaSAndroid Build Coastguard Worker     }
145*c8dee2aaSAndroid Build Coastguard Worker 
quadDistanceY(const SkDQuad & pts,SkDQuad & distance)146*c8dee2aaSAndroid Build Coastguard Worker     void quadDistanceY(const SkDQuad& pts, SkDQuad& distance) const {
147*c8dee2aaSAndroid Build Coastguard Worker         double oneHalf = 1 / 2.0;
148*c8dee2aaSAndroid Build Coastguard Worker         for (int index = 0; index < 3; ++index) {
149*c8dee2aaSAndroid Build Coastguard Worker             distance[index].fX = index * oneHalf;
150*c8dee2aaSAndroid Build Coastguard Worker             distance[index].fY = fA * pts[index].fX + fB * pts[index].fY + fC;
151*c8dee2aaSAndroid Build Coastguard Worker         }
152*c8dee2aaSAndroid Build Coastguard Worker     }
153*c8dee2aaSAndroid Build Coastguard Worker 
controlPtDistance(const SkDCubic & pts,int index)154*c8dee2aaSAndroid Build Coastguard Worker     double controlPtDistance(const SkDCubic& pts, int index) const {
155*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(index == 1 || index == 2);
156*c8dee2aaSAndroid Build Coastguard Worker         return fA * pts[index].fX + fB * pts[index].fY + fC;
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker 
controlPtDistance(const SkDQuad & pts)159*c8dee2aaSAndroid Build Coastguard Worker     double controlPtDistance(const SkDQuad& pts) const {
160*c8dee2aaSAndroid Build Coastguard Worker         return fA * pts[1].fX + fB * pts[1].fY + fC;
161*c8dee2aaSAndroid Build Coastguard Worker     }
162*c8dee2aaSAndroid Build Coastguard Worker 
pointDistance(const SkDPoint & pt)163*c8dee2aaSAndroid Build Coastguard Worker     double pointDistance(const SkDPoint& pt) const {
164*c8dee2aaSAndroid Build Coastguard Worker         return fA * pt.fX + fB * pt.fY + fC;
165*c8dee2aaSAndroid Build Coastguard Worker     }
166*c8dee2aaSAndroid Build Coastguard Worker 
dx()167*c8dee2aaSAndroid Build Coastguard Worker     double dx() const {
168*c8dee2aaSAndroid Build Coastguard Worker         return fB;
169*c8dee2aaSAndroid Build Coastguard Worker     }
170*c8dee2aaSAndroid Build Coastguard Worker 
dy()171*c8dee2aaSAndroid Build Coastguard Worker     double dy() const {
172*c8dee2aaSAndroid Build Coastguard Worker         return -fA;
173*c8dee2aaSAndroid Build Coastguard Worker     }
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker private:
176*c8dee2aaSAndroid Build Coastguard Worker     double fA;
177*c8dee2aaSAndroid Build Coastguard Worker     double fB;
178*c8dee2aaSAndroid Build Coastguard Worker     double fC;
179*c8dee2aaSAndroid Build Coastguard Worker };
180*c8dee2aaSAndroid Build Coastguard Worker 
181*c8dee2aaSAndroid Build Coastguard Worker #endif
182