xref: /aosp_15_r20/external/skia/src/pathops/SkPathOpsPoint.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 SkPathOpsPoint_DEFINED
8 #define SkPathOpsPoint_DEFINED
9 
10 #include "include/core/SkPoint.h"
11 #include "include/core/SkTypes.h"
12 #include "include/private/base/SkTemplates.h"
13 #include "src/pathops/SkPathOpsTypes.h"
14 
AlmostEqualUlps(const SkPoint & pt1,const SkPoint & pt2)15 inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) {
16     return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY);
17 }
18 
19 struct SkDVector {
20     double fX;
21     double fY;
22 
setSkDVector23     SkDVector& set(const SkVector& pt) {
24         fX = pt.fX;
25         fY = pt.fY;
26         return *this;
27     }
28 
29     // only used by testing
30     void operator+=(const SkDVector& v) {
31         fX += v.fX;
32         fY += v.fY;
33     }
34 
35     // only called by nearestT, which is currently only used by testing
36     void operator-=(const SkDVector& v) {
37         fX -= v.fX;
38         fY -= v.fY;
39     }
40 
41     // only used by testing
42     void operator/=(const double s) {
43         fX /= s;
44         fY /= s;
45     }
46 
47     // only used by testing
48     void operator*=(const double s) {
49         fX *= s;
50         fY *= s;
51     }
52 
asSkVectorSkDVector53     SkVector asSkVector() const {
54         SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
55         return v;
56     }
57 
58     // only used by testing
crossSkDVector59     double cross(const SkDVector& a) const {
60         return fX * a.fY - fY * a.fX;
61     }
62 
63     // similar to cross, this bastardization considers nearly coincident to be zero
64     // uses ulps epsilon == 16
crossCheckSkDVector65     double crossCheck(const SkDVector& a) const {
66         double xy = fX * a.fY;
67         double yx = fY * a.fX;
68         return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
69     }
70 
71     // allow tinier numbers
crossNoNormalCheckSkDVector72     double crossNoNormalCheck(const SkDVector& a) const {
73         double xy = fX * a.fY;
74         double yx = fY * a.fX;
75         return AlmostEqualUlpsNoNormalCheck(xy, yx) ? 0 : xy - yx;
76     }
77 
dotSkDVector78     double dot(const SkDVector& a) const {
79         return fX * a.fX + fY * a.fY;
80     }
81 
lengthSkDVector82     double length() const {
83         return sqrt(lengthSquared());
84     }
85 
lengthSquaredSkDVector86     double lengthSquared() const {
87         return fX * fX + fY * fY;
88     }
89 
normalizeSkDVector90     SkDVector& normalize() {
91         double inverseLength = sk_ieee_double_divide(1, this->length());
92         fX *= inverseLength;
93         fY *= inverseLength;
94         return *this;
95     }
96 
isFiniteSkDVector97     bool isFinite() const {
98         return SkIsFinite(fX, fY);
99     }
100 };
101 
102 struct SkDPoint {
103     double fX;
104     double fY;
105 
setSkDPoint106     void set(const SkPoint& pt) {
107         fX = pt.fX;
108         fY = pt.fY;
109     }
110 
111     friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
112         return { a.fX - b.fX, a.fY - b.fY };
113     }
114 
115     friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
116         return a.fX == b.fX && a.fY == b.fY;
117     }
118 
119     friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
120         return a.fX != b.fX || a.fY != b.fY;
121     }
122 
123     void operator=(const SkPoint& pt) {
124         fX = pt.fX;
125         fY = pt.fY;
126     }
127 
128     // only used by testing
129     void operator+=(const SkDVector& v) {
130         fX += v.fX;
131         fY += v.fY;
132     }
133 
134     // only used by testing
135     void operator-=(const SkDVector& v) {
136         fX -= v.fX;
137         fY -= v.fY;
138     }
139 
140     // only used by testing
141     SkDPoint operator+(const SkDVector& v) {
142         SkDPoint result = *this;
143         result += v;
144         return result;
145     }
146 
147     // only used by testing
148     SkDPoint operator-(const SkDVector& v) {
149         SkDPoint result = *this;
150         result -= v;
151         return result;
152     }
153 
154     // note: this can not be implemented with
155     // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
156     // because that will not take the magnitude of the values into account
approximatelyDEqualSkDPoint157     bool approximatelyDEqual(const SkDPoint& a) const {
158         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
159             return true;
160         }
161         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
162             return false;
163         }
164         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
165         double tiniest = std::min(std::min(std::min(fX, a.fX), fY), a.fY);
166         double largest = std::max(std::max(std::max(fX, a.fX), fY), a.fY);
167         largest = std::max(largest, -tiniest);
168         return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
169     }
170 
approximatelyDEqualSkDPoint171     bool approximatelyDEqual(const SkPoint& a) const {
172         SkDPoint dA;
173         dA.set(a);
174         return approximatelyDEqual(dA);
175     }
176 
approximatelyEqualSkDPoint177     bool approximatelyEqual(const SkDPoint& a) const {
178         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
179             return true;
180         }
181         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
182             return false;
183         }
184         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
185         double tiniest = std::min(std::min(std::min(fX, a.fX), fY), a.fY);
186         double largest = std::max(std::max(std::max(fX, a.fX), fY), a.fY);
187         largest = std::max(largest, -tiniest);
188         return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
189     }
190 
approximatelyEqualSkDPoint191     bool approximatelyEqual(const SkPoint& a) const {
192         SkDPoint dA;
193         dA.set(a);
194         return approximatelyEqual(dA);
195     }
196 
ApproximatelyEqualSkDPoint197     static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
198         if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
199             return true;
200         }
201         if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
202             return false;
203         }
204         SkDPoint dA, dB;
205         dA.set(a);
206         dB.set(b);
207         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
208         float tiniest = std::min(std::min(std::min(a.fX, b.fX), a.fY), b.fY);
209         float largest = std::max(std::max(std::max(a.fX, b.fX), a.fY), b.fY);
210         largest = std::max(largest, -tiniest);
211         return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
212     }
213 
214     // only used by testing
approximatelyZeroSkDPoint215     bool approximatelyZero() const {
216         return approximately_zero(fX) && approximately_zero(fY);
217     }
218 
asSkPointSkDPoint219     SkPoint asSkPoint() const {
220         SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
221         return pt;
222     }
223 
distanceSkDPoint224     double distance(const SkDPoint& a) const {
225         SkDVector temp = *this - a;
226         return temp.length();
227     }
228 
distanceSquaredSkDPoint229     double distanceSquared(const SkDPoint& a) const {
230         SkDVector temp = *this - a;
231         return temp.lengthSquared();
232     }
233 
MidSkDPoint234     static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
235         SkDPoint result;
236         result.fX = (a.fX + b.fX) / 2;
237         result.fY = (a.fY + b.fY) / 2;
238         return result;
239     }
240 
roughlyEqualSkDPoint241     bool roughlyEqual(const SkDPoint& a) const {
242         if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
243             return true;
244         }
245         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
246         double tiniest = std::min(std::min(std::min(fX, a.fX), fY), a.fY);
247         double largest = std::max(std::max(std::max(fX, a.fX), fY), a.fY);
248         largest = std::max(largest, -tiniest);
249         return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
250     }
251 
RoughlyEqualSkDPoint252     static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
253         if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
254             return false;
255         }
256         SkDPoint dA, dB;
257         dA.set(a);
258         dB.set(b);
259         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
260         float tiniest = std::min(std::min(std::min(a.fX, b.fX), a.fY), b.fY);
261         float largest = std::max(std::max(std::max(a.fX, b.fX), a.fY), b.fY);
262         largest = std::max(largest, -tiniest);
263         return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
264     }
265 
266     // very light weight check, should only be used for inequality check
WayRoughlyEqualSkDPoint267     static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
268         float largestNumber = std::max(SkTAbs(a.fX), std::max(SkTAbs(a.fY),
269                 std::max(SkTAbs(b.fX), SkTAbs(b.fY))));
270         SkVector diffs = a - b;
271         float largestDiff = std::max(diffs.fX, diffs.fY);
272         return roughly_zero_when_compared_to(largestDiff, largestNumber);
273     }
274 
275     // utilities callable by the user from the debugger when the implementation code is linked in
276     void dump() const;
277     static void Dump(const SkPoint& pt);
278     static void DumpHex(const SkPoint& pt);
279 };
280 
281 #endif
282