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
crossCheckSkDVector61     double crossCheck(const SkDVector& a) const {
62         double xy = fX * a.fY;
63         double yx = fY * a.fX;
64         return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
65     }
66 
dotSkDVector67     double dot(const SkDVector& a) const {
68         return fX * a.fX + fY * a.fY;
69     }
70 
lengthSkDVector71     double length() const {
72         return sqrt(lengthSquared());
73     }
74 
lengthSquaredSkDVector75     double lengthSquared() const {
76         return fX * fX + fY * fY;
77     }
78 };
79 
80 struct SkDPoint {
81     double fX;
82     double fY;
83 
setSkDPoint84     void set(const SkPoint& pt) {
85         fX = pt.fX;
86         fY = pt.fY;
87     }
88 
89     friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b);
90 
91     friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
92         return a.fX == b.fX && a.fY == b.fY;
93     }
94 
95     friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
96         return a.fX != b.fX || a.fY != b.fY;
97     }
98 
99     void operator=(const SkPoint& pt) {
100         fX = pt.fX;
101         fY = pt.fY;
102     }
103 
104     // only used by testing
105     void operator+=(const SkDVector& v) {
106         fX += v.fX;
107         fY += v.fY;
108     }
109 
110     // only used by testing
111     void operator-=(const SkDVector& v) {
112         fX -= v.fX;
113         fY -= v.fY;
114     }
115 
116     // only used by testing
117     SkDPoint operator+(const SkDVector& v) {
118         SkDPoint result = *this;
119         result += v;
120         return result;
121     }
122 
123     // only used by testing
124     SkDPoint operator-(const SkDVector& v) {
125         SkDPoint result = *this;
126         result -= v;
127         return result;
128     }
129 
130     // note: this can not be implemented with
131     // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
132     // because that will not take the magnitude of the values into account
approximatelyEqualSkDPoint133     bool approximatelyEqual(const SkDPoint& a) const {
134         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
135             return true;
136         }
137         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
138             return false;
139         }
140         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
141         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
142         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
143         largest = SkTMax(largest, -tiniest);
144         return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
145     }
146 
approximatelyEqualSkDPoint147     bool approximatelyEqual(const SkPoint& a) const {
148         SkDPoint dA;
149         dA.set(a);
150         return approximatelyEqual(dA);
151     }
152 
ApproximatelyEqualSkDPoint153     static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
154         if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
155             return true;
156         }
157         if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
158             return false;
159         }
160         SkDPoint dA, dB;
161         dA.set(a);
162         dB.set(b);
163         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
164         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
165         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
166         largest = SkTMax(largest, -tiniest);
167         return AlmostPequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
168     }
169 
170     // only used by testing
approximatelyZeroSkDPoint171     bool approximatelyZero() const {
172         return approximately_zero(fX) && approximately_zero(fY);
173     }
174 
asSkPointSkDPoint175     SkPoint asSkPoint() const {
176         SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
177         return pt;
178     }
179 
distanceSkDPoint180     double distance(const SkDPoint& a) const {
181         SkDVector temp = *this - a;
182         return temp.length();
183     }
184 
distanceSquaredSkDPoint185     double distanceSquared(const SkDPoint& a) const {
186         SkDVector temp = *this - a;
187         return temp.lengthSquared();
188     }
189 
MidSkDPoint190     static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
191         SkDPoint result;
192         result.fX = (a.fX + b.fX) / 2;
193         result.fY = (a.fY + b.fY) / 2;
194         return result;
195     }
196 
roughlyEqualSkDPoint197     bool roughlyEqual(const SkDPoint& a) const {
198         if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
199             return true;
200         }
201         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
202         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
203         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
204         largest = SkTMax(largest, -tiniest);
205         return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
206     }
207 
RoughlyEqualSkDPoint208     static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
209         if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
210             return false;
211         }
212         SkDPoint dA, dB;
213         dA.set(a);
214         dB.set(b);
215         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
216         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
217         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
218         largest = SkTMax(largest, -tiniest);
219         return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
220     }
221 
222     // utilities callable by the user from the debugger when the implementation code is linked in
223     void dump() const;
224     static void Dump(const SkPoint& pt);
225     static void DumpHex(const SkPoint& pt);
226 };
227 
228 #endif
229