Line data Source code
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 :
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 :
21 0 : void set(const SkVector& pt) {
22 0 : fX = pt.fX;
23 0 : fY = pt.fY;
24 0 : }
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 :
50 0 : SkVector asSkVector() const {
51 0 : SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
52 0 : return v;
53 : }
54 :
55 : // only used by testing
56 : 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
62 0 : double crossCheck(const SkDVector& a) const {
63 0 : double xy = fX * a.fY;
64 0 : double yx = fY * a.fX;
65 0 : return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
66 : }
67 :
68 : // allow tinier numbers
69 0 : double crossNoNormalCheck(const SkDVector& a) const {
70 0 : double xy = fX * a.fY;
71 0 : double yx = fY * a.fX;
72 0 : return AlmostEqualUlpsNoNormalCheck(xy, yx) ? 0 : xy - yx;
73 : }
74 :
75 0 : double dot(const SkDVector& a) const {
76 0 : return fX * a.fX + fY * a.fY;
77 : }
78 :
79 0 : double length() const {
80 0 : return sqrt(lengthSquared());
81 : }
82 :
83 0 : double lengthSquared() const {
84 0 : return fX * fX + fY * fY;
85 : }
86 :
87 : 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 :
98 0 : void set(const SkPoint& pt) {
99 0 : fX = pt.fX;
100 0 : fY = pt.fY;
101 0 : }
102 :
103 : friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b);
104 :
105 0 : friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
106 0 : return a.fX == b.fX && a.fY == b.fY;
107 : }
108 :
109 0 : friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
110 0 : return a.fX != b.fX || a.fY != b.fY;
111 : }
112 :
113 132 : void operator=(const SkPoint& pt) {
114 132 : fX = pt.fX;
115 132 : fY = pt.fY;
116 132 : }
117 :
118 : // only used by testing
119 0 : void operator+=(const SkDVector& v) {
120 0 : fX += v.fX;
121 0 : fY += v.fY;
122 0 : }
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 0 : SkDPoint operator+(const SkDVector& v) {
132 0 : SkDPoint result = *this;
133 0 : result += v;
134 0 : 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
147 0 : bool approximatelyDEqual(const SkDPoint& a) const {
148 0 : if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
149 0 : return true;
150 : }
151 0 : if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
152 0 : return false;
153 : }
154 0 : double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
155 0 : double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
156 0 : double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
157 0 : largest = SkTMax(largest, -tiniest);
158 0 : return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
159 : }
160 :
161 0 : bool approximatelyDEqual(const SkPoint& a) const {
162 : SkDPoint dA;
163 0 : dA.set(a);
164 0 : return approximatelyDEqual(dA);
165 : }
166 :
167 0 : bool approximatelyEqual(const SkDPoint& a) const {
168 0 : if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
169 0 : return true;
170 : }
171 0 : if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
172 0 : return false;
173 : }
174 0 : double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
175 0 : double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
176 0 : double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
177 0 : largest = SkTMax(largest, -tiniest);
178 0 : return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
179 : }
180 :
181 0 : bool approximatelyEqual(const SkPoint& a) const {
182 : SkDPoint dA;
183 0 : dA.set(a);
184 0 : return approximatelyEqual(dA);
185 : }
186 :
187 0 : static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
188 0 : if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
189 0 : return true;
190 : }
191 0 : if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
192 0 : return false;
193 : }
194 : SkDPoint dA, dB;
195 0 : dA.set(a);
196 0 : dB.set(b);
197 0 : double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
198 0 : float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
199 0 : float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
200 0 : largest = SkTMax(largest, -tiniest);
201 0 : return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
202 : }
203 :
204 : // only used by testing
205 : bool approximatelyZero() const {
206 : return approximately_zero(fX) && approximately_zero(fY);
207 : }
208 :
209 231 : SkPoint asSkPoint() const {
210 231 : SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
211 231 : return pt;
212 : }
213 :
214 0 : double distance(const SkDPoint& a) const {
215 0 : SkDVector temp = *this - a;
216 0 : return temp.length();
217 : }
218 :
219 0 : double distanceSquared(const SkDPoint& a) const {
220 0 : SkDVector temp = *this - a;
221 0 : return temp.lengthSquared();
222 : }
223 :
224 0 : static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
225 : SkDPoint result;
226 0 : result.fX = (a.fX + b.fX) / 2;
227 0 : result.fY = (a.fY + b.fY) / 2;
228 0 : return result;
229 : }
230 :
231 0 : bool roughlyEqual(const SkDPoint& a) const {
232 0 : if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
233 0 : return true;
234 : }
235 0 : double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
236 0 : double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
237 0 : double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
238 0 : largest = SkTMax(largest, -tiniest);
239 0 : return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
240 : }
241 :
242 0 : static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
243 0 : if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
244 0 : return false;
245 : }
246 : SkDPoint dA, dB;
247 0 : dA.set(a);
248 0 : dB.set(b);
249 0 : double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
250 0 : float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
251 0 : float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
252 0 : largest = SkTMax(largest, -tiniest);
253 0 : 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
257 0 : static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
258 0 : float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY),
259 0 : SkTMax(SkTAbs(b.fX), SkTAbs(b.fY))));
260 0 : SkVector diffs = a - b;
261 0 : float largestDiff = SkTMax(diffs.fX, diffs.fY);
262 0 : 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
|