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 "src/pathops/SkPathOpsTypes.h"
12 
AlmostEqualUlps(const SkPoint & pt1,const SkPoint & pt2)13 inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) {
14     return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY);
15 }
16 
17 struct SkDVector {
18     double fX;
19     double fY;
20 
setSkDVector21     SkDVector& set(const SkVector& pt) {
22         fX = pt.fX;
23         fY = pt.fY;
24         return *this;
25     }
26 
27     // only used by testing
28     void operator+=(const SkDVector& v) {
29         fX += v.fX;
30         fY += v.fY;
31     }
32 
33     // only called by nearestT, which is currently only used by testing
34     void operator-=(const SkDVector& v) {
35         fX -= v.fX;
36         fY -= v.fY;
37     }
38 
39     // only used by testing
40     void operator/=(const double s) {
41         fX /= s;
42         fY /= s;
43     }
44 
45     // only used by testing
46     void operator*=(const double s) {
47         fX *= s;
48         fY *= s;
49     }
50 
asSkVectorSkDVector51     SkVector asSkVector() const {
52         SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
53         return v;
54     }
55 
56     // only used by testing
crossSkDVector57     double cross(const SkDVector& a) const {
58         return fX * a.fY - fY * a.fX;
59     }
60 
61     // similar to cross, this bastardization considers nearly coincident to be zero
62     // uses ulps epsilon == 16
crossCheckSkDVector63     double crossCheck(const SkDVector& a) const {
64         double xy = fX * a.fY;
65         double yx = fY * a.fX;
66         return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
67     }
68 
69     // allow tinier numbers
crossNoNormalCheckSkDVector70     double crossNoNormalCheck(const SkDVector& a) const {
71         double xy = fX * a.fY;
72         double yx = fY * a.fX;
73         return AlmostEqualUlpsNoNormalCheck(xy, yx) ? 0 : xy - yx;
74     }
75 
dotSkDVector76     double dot(const SkDVector& a) const {
77         return fX * a.fX + fY * a.fY;
78     }
79 
lengthSkDVector80     double length() const {
81         return sqrt(lengthSquared());
82     }
83 
lengthSquaredSkDVector84     double lengthSquared() const {
85         return fX * fX + fY * fY;
86     }
87 
normalizeSkDVector88     SkDVector& normalize() {
89         double inverseLength = sk_ieee_double_divide(1, this->length());
90         fX *= inverseLength;
91         fY *= inverseLength;
92         return *this;
93     }
94 
isFiniteSkDVector95     bool isFinite() const {
96         return std::isfinite(fX) && std::isfinite(fY);
97     }
98 };
99 
100 struct SkDPoint {
101     double fX;
102     double fY;
103 
setSkDPoint104     void set(const SkPoint& pt) {
105         fX = pt.fX;
106         fY = pt.fY;
107     }
108 
109     friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
110         return { a.fX - b.fX, a.fY - b.fY };
111     }
112 
113     friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
114         return a.fX == b.fX && a.fY == b.fY;
115     }
116 
117     friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
118         return a.fX != b.fX || a.fY != b.fY;
119     }
120 
121     void operator=(const SkPoint& pt) {
122         fX = pt.fX;
123         fY = pt.fY;
124     }
125 
126     // only used by testing
127     void operator+=(const SkDVector& v) {
128         fX += v.fX;
129         fY += v.fY;
130     }
131 
132     // only used by testing
133     void operator-=(const SkDVector& v) {
134         fX -= v.fX;
135         fY -= v.fY;
136     }
137 
138     // only used by testing
139     SkDPoint operator+(const SkDVector& v) {
140         SkDPoint result = *this;
141         result += v;
142         return result;
143     }
144 
145     // only used by testing
146     SkDPoint operator-(const SkDVector& v) {
147         SkDPoint result = *this;
148         result -= v;
149         return result;
150     }
151 
152     // note: this can not be implemented with
153     // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
154     // because that will not take the magnitude of the values into account
approximatelyDEqualSkDPoint155     bool approximatelyDEqual(const SkDPoint& a) const {
156         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
157             return true;
158         }
159         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
160             return false;
161         }
162         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
163         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
164         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
165         largest = SkTMax(largest, -tiniest);
166         return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
167     }
168 
approximatelyDEqualSkDPoint169     bool approximatelyDEqual(const SkPoint& a) const {
170         SkDPoint dA;
171         dA.set(a);
172         return approximatelyDEqual(dA);
173     }
174 
approximatelyEqualSkDPoint175     bool approximatelyEqual(const SkDPoint& a) const {
176         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
177             return true;
178         }
179         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
180             return false;
181         }
182         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
183         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
184         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
185         largest = SkTMax(largest, -tiniest);
186         return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
187     }
188 
approximatelyEqualSkDPoint189     bool approximatelyEqual(const SkPoint& a) const {
190         SkDPoint dA;
191         dA.set(a);
192         return approximatelyEqual(dA);
193     }
194 
ApproximatelyEqualSkDPoint195     static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
196         if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
197             return true;
198         }
199         if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
200             return false;
201         }
202         SkDPoint dA, dB;
203         dA.set(a);
204         dB.set(b);
205         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
206         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
207         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
208         largest = SkTMax(largest, -tiniest);
209         return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
210     }
211 
212     // only used by testing
approximatelyZeroSkDPoint213     bool approximatelyZero() const {
214         return approximately_zero(fX) && approximately_zero(fY);
215     }
216 
asSkPointSkDPoint217     SkPoint asSkPoint() const {
218         SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
219         return pt;
220     }
221 
distanceSkDPoint222     double distance(const SkDPoint& a) const {
223         SkDVector temp = *this - a;
224         return temp.length();
225     }
226 
distanceSquaredSkDPoint227     double distanceSquared(const SkDPoint& a) const {
228         SkDVector temp = *this - a;
229         return temp.lengthSquared();
230     }
231 
MidSkDPoint232     static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
233         SkDPoint result;
234         result.fX = (a.fX + b.fX) / 2;
235         result.fY = (a.fY + b.fY) / 2;
236         return result;
237     }
238 
roughlyEqualSkDPoint239     bool roughlyEqual(const SkDPoint& a) const {
240         if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
241             return true;
242         }
243         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
244         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
245         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
246         largest = SkTMax(largest, -tiniest);
247         return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
248     }
249 
RoughlyEqualSkDPoint250     static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
251         if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
252             return false;
253         }
254         SkDPoint dA, dB;
255         dA.set(a);
256         dB.set(b);
257         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
258         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
259         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
260         largest = SkTMax(largest, -tiniest);
261         return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
262     }
263 
264     // very light weight check, should only be used for inequality check
WayRoughlyEqualSkDPoint265     static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
266         float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY),
267                 SkTMax(SkTAbs(b.fX), SkTAbs(b.fY))));
268         SkVector diffs = a - b;
269         float largestDiff = SkTMax(diffs.fX, diffs.fY);
270         return roughly_zero_when_compared_to(largestDiff, largestNumber);
271     }
272 
273     // utilities callable by the user from the debugger when the implementation code is linked in
274     void dump() const;
275     static void Dump(const SkPoint& pt);
276     static void DumpHex(const SkPoint& pt);
277 };
278 
279 #endif
280