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
105 friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
106 return a.fX == b.fX && a.fY == b.fY;
107 }
108
109 friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
110 return a.fX != b.fX || a.fY != b.fY;
111 }
112
113 void operator=(const SkPoint& pt) {
114 fX = pt.fX;
115 fY = pt.fY;
116 }
117
118 // only used by testing
119 void operator+=(const SkDVector& v) {
120 fX += v.fX;
121 fY += v.fY;
122 }
123
124 // only used by testing
125 void operator-=(const SkDVector& v) {
126 fX -= v.fX;
127 fY -= v.fY;
128 }
129
130 // only used by testing
131 SkDPoint operator+(const SkDVector& v) {
132 SkDPoint result = *this;
133 result += v;
134 return result;
135 }
136
137 // only used by testing
138 SkDPoint operator-(const SkDVector& v) {
139 SkDPoint result = *this;
140 result -= v;
141 return result;
142 }
143
144 // note: this can not be implemented with
145 // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
146 // because that will not take the magnitude of the values into account
approximatelyDEqualSkDPoint147 bool approximatelyDEqual(const SkDPoint& a) const {
148 if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
149 return true;
150 }
151 if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
152 return false;
153 }
154 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
155 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
156 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
157 largest = SkTMax(largest, -tiniest);
158 return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
159 }
160
approximatelyDEqualSkDPoint161 bool approximatelyDEqual(const SkPoint& a) const {
162 SkDPoint dA;
163 dA.set(a);
164 return approximatelyDEqual(dA);
165 }
166
approximatelyEqualSkDPoint167 bool approximatelyEqual(const SkDPoint& a) const {
168 if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
169 return true;
170 }
171 if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
172 return false;
173 }
174 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
175 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
176 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
177 largest = SkTMax(largest, -tiniest);
178 return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
179 }
180
approximatelyEqualSkDPoint181 bool approximatelyEqual(const SkPoint& a) const {
182 SkDPoint dA;
183 dA.set(a);
184 return approximatelyEqual(dA);
185 }
186
ApproximatelyEqualSkDPoint187 static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
188 if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
189 return true;
190 }
191 if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
192 return false;
193 }
194 SkDPoint dA, dB;
195 dA.set(a);
196 dB.set(b);
197 double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
198 float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
199 float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
200 largest = SkTMax(largest, -tiniest);
201 return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
202 }
203
204 // only used by testing
approximatelyZeroSkDPoint205 bool approximatelyZero() const {
206 return approximately_zero(fX) && approximately_zero(fY);
207 }
208
asSkPointSkDPoint209 SkPoint asSkPoint() const {
210 SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
211 return pt;
212 }
213
distanceSkDPoint214 double distance(const SkDPoint& a) const {
215 SkDVector temp = *this - a;
216 return temp.length();
217 }
218
distanceSquaredSkDPoint219 double distanceSquared(const SkDPoint& a) const {
220 SkDVector temp = *this - a;
221 return temp.lengthSquared();
222 }
223
MidSkDPoint224 static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
225 SkDPoint result;
226 result.fX = (a.fX + b.fX) / 2;
227 result.fY = (a.fY + b.fY) / 2;
228 return result;
229 }
230
roughlyEqualSkDPoint231 bool roughlyEqual(const SkDPoint& a) const {
232 if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
233 return true;
234 }
235 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
236 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
237 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
238 largest = SkTMax(largest, -tiniest);
239 return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
240 }
241
RoughlyEqualSkDPoint242 static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
243 if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
244 return false;
245 }
246 SkDPoint dA, dB;
247 dA.set(a);
248 dB.set(b);
249 double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
250 float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
251 float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
252 largest = SkTMax(largest, -tiniest);
253 return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
254 }
255
256 // very light weight check, should only be used for inequality check
WayRoughlyEqualSkDPoint257 static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
258 float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY),
259 SkTMax(SkTAbs(b.fX), SkTAbs(b.fY))));
260 SkVector diffs = a - b;
261 float largestDiff = SkTMax(diffs.fX, diffs.fY);
262 return roughly_zero_when_compared_to(largestDiff, largestNumber);
263 }
264
265 // utilities callable by the user from the debugger when the implementation code is linked in
266 void dump() const;
267 static void Dump(const SkPoint& pt);
268 static void DumpHex(const SkPoint& pt);
269 };
270
271 #endif
272