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 "SkPathOpsTypes.h"
11 #include "SkPoint.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     void set(const SkVector& pt) {
22         fX = pt.fX;
23         fY = pt.fY;
24     }
25 
26     // only used by testing
27     void operator+=(const SkDVector& v) {
28         fX += v.fX;
29         fY += v.fY;
30     }
31 
32     // only called by nearestT, which is currently only used by testing
33     void operator-=(const SkDVector& v) {
34         fX -= v.fX;
35         fY -= v.fY;
36     }
37 
38     // only used by testing
39     void operator/=(const double s) {
40         fX /= s;
41         fY /= s;
42     }
43 
44     // only used by testing
45     void operator*=(const double s) {
46         fX *= s;
47         fY *= s;
48     }
49 
asSkVectorSkDVector50     SkVector asSkVector() const {
51         SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
52         return v;
53     }
54 
55     // only used by testing
crossSkDVector56     double cross(const SkDVector& a) const {
57         return fX * a.fY - fY * a.fX;
58     }
59 
60     // similar to cross, this bastardization considers nearly coincident to be zero
61     // uses ulps epsilon == 16
crossCheckSkDVector62     double crossCheck(const SkDVector& a) const {
63         double xy = fX * a.fY;
64         double yx = fY * a.fX;
65         return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
66     }
67 
68     // allow tinier numbers
crossNoNormalCheckSkDVector69     double crossNoNormalCheck(const SkDVector& a) const {
70         double xy = fX * a.fY;
71         double yx = fY * a.fX;
72         return AlmostEqualUlpsNoNormalCheck(xy, yx) ? 0 : xy - yx;
73     }
74 
dotSkDVector75     double dot(const SkDVector& a) const {
76         return fX * a.fX + fY * a.fY;
77     }
78 
lengthSkDVector79     double length() const {
80         return sqrt(lengthSquared());
81     }
82 
lengthSquaredSkDVector83     double lengthSquared() const {
84         return fX * fX + fY * fY;
85     }
86 
normalizeSkDVector87     void normalize() {
88         double inverseLength = 1 / this->length();
89         fX *= inverseLength;
90         fY *= inverseLength;
91     }
92 };
93 
94 struct SkDPoint {
95     double fX;
96     double fY;
97 
setSkDPoint98     void set(const SkPoint& pt) {
99         fX = pt.fX;
100         fY = pt.fY;
101     }
102 
103     friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
104         return { a.fX - b.fX, a.fY - b.fY };
105     }
106 
107     friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
108         return a.fX == b.fX && a.fY == b.fY;
109     }
110 
111     friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
112         return a.fX != b.fX || a.fY != b.fY;
113     }
114 
115     void operator=(const SkPoint& pt) {
116         fX = pt.fX;
117         fY = pt.fY;
118     }
119 
120     // only used by testing
121     void operator+=(const SkDVector& v) {
122         fX += v.fX;
123         fY += v.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     SkDPoint operator+(const SkDVector& v) {
134         SkDPoint result = *this;
135         result += v;
136         return result;
137     }
138 
139     // only used by testing
140     SkDPoint operator-(const SkDVector& v) {
141         SkDPoint result = *this;
142         result -= v;
143         return result;
144     }
145 
146     // note: this can not be implemented with
147     // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
148     // because that will not take the magnitude of the values into account
approximatelyDEqualSkDPoint149     bool approximatelyDEqual(const SkDPoint& a) const {
150         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
151             return true;
152         }
153         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
154             return false;
155         }
156         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
157         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
158         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
159         largest = SkTMax(largest, -tiniest);
160         return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
161     }
162 
approximatelyDEqualSkDPoint163     bool approximatelyDEqual(const SkPoint& a) const {
164         SkDPoint dA;
165         dA.set(a);
166         return approximatelyDEqual(dA);
167     }
168 
approximatelyEqualSkDPoint169     bool approximatelyEqual(const SkDPoint& a) const {
170         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
171             return true;
172         }
173         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
174             return false;
175         }
176         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
177         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
178         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
179         largest = SkTMax(largest, -tiniest);
180         return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
181     }
182 
approximatelyEqualSkDPoint183     bool approximatelyEqual(const SkPoint& a) const {
184         SkDPoint dA;
185         dA.set(a);
186         return approximatelyEqual(dA);
187     }
188 
ApproximatelyEqualSkDPoint189     static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
190         if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
191             return true;
192         }
193         if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
194             return false;
195         }
196         SkDPoint dA, dB;
197         dA.set(a);
198         dB.set(b);
199         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
200         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
201         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
202         largest = SkTMax(largest, -tiniest);
203         return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
204     }
205 
206     // only used by testing
approximatelyZeroSkDPoint207     bool approximatelyZero() const {
208         return approximately_zero(fX) && approximately_zero(fY);
209     }
210 
asSkPointSkDPoint211     SkPoint asSkPoint() const {
212         SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
213         return pt;
214     }
215 
distanceSkDPoint216     double distance(const SkDPoint& a) const {
217         SkDVector temp = *this - a;
218         return temp.length();
219     }
220 
distanceSquaredSkDPoint221     double distanceSquared(const SkDPoint& a) const {
222         SkDVector temp = *this - a;
223         return temp.lengthSquared();
224     }
225 
MidSkDPoint226     static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
227         SkDPoint result;
228         result.fX = (a.fX + b.fX) / 2;
229         result.fY = (a.fY + b.fY) / 2;
230         return result;
231     }
232 
roughlyEqualSkDPoint233     bool roughlyEqual(const SkDPoint& a) const {
234         if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
235             return true;
236         }
237         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
238         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
239         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
240         largest = SkTMax(largest, -tiniest);
241         return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
242     }
243 
RoughlyEqualSkDPoint244     static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
245         if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
246             return false;
247         }
248         SkDPoint dA, dB;
249         dA.set(a);
250         dB.set(b);
251         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
252         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
253         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
254         largest = SkTMax(largest, -tiniest);
255         return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
256     }
257 
258     // very light weight check, should only be used for inequality check
WayRoughlyEqualSkDPoint259     static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
260         float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY),
261                 SkTMax(SkTAbs(b.fX), SkTAbs(b.fY))));
262         SkVector diffs = a - b;
263         float largestDiff = SkTMax(diffs.fX, diffs.fY);
264         return roughly_zero_when_compared_to(largestDiff, largestNumber);
265     }
266 
267     // utilities callable by the user from the debugger when the implementation code is linked in
268     void dump() const;
269     static void Dump(const SkPoint& pt);
270     static void DumpHex(const SkPoint& pt);
271 };
272 
273 #endif
274