blob: 6cd29848949f35e05763f0a235d8c31b1e792e2c [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
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
caryclark@google.coma5e55922013-05-07 18:51:31 +000013inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) {
14 return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY);
15}
16
caryclark@google.com07393ca2013-04-08 11:47:37 +000017struct SkDVector {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000018 double fX;
19 double fY;
20
21 void set(const SkVector& pt) {
22 fX = pt.fX;
23 fY = pt.fY;
24 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000025
caryclark54359292015-03-26 07:52:43 -070026 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000027 void operator+=(const SkDVector& v) {
28 fX += v.fX;
29 fY += v.fY;
30 }
31
caryclark54359292015-03-26 07:52:43 -070032 // only called by nearestT, which is currently only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000033 void operator-=(const SkDVector& v) {
34 fX -= v.fX;
35 fY -= v.fY;
36 }
37
Cary Clark59d5a0e2017-01-23 14:38:52 +000038 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000039 void operator/=(const double s) {
40 fX /= s;
41 fY /= s;
42 }
43
caryclark54359292015-03-26 07:52:43 -070044 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000045 void operator*=(const double s) {
46 fX *= s;
47 fY *= s;
48 }
49
50 SkVector asSkVector() const {
51 SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
52 return v;
53 }
54
caryclark54359292015-03-26 07:52:43 -070055 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000056 double cross(const SkDVector& a) const {
57 return fX * a.fY - fY * a.fX;
58 }
59
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000060 // similar to cross, this bastardization considers nearly coincident to be zero
caryclark55888e42016-07-18 10:01:36 -070061 // uses ulps epsilon == 16
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000062 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
caryclark55888e42016-07-18 10:01:36 -070068 // allow tinier numbers
69 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
caryclark@google.com07393ca2013-04-08 11:47:37 +000075 double dot(const SkDVector& a) const {
76 return fX * a.fX + fY * a.fY;
77 }
78
79 double length() const {
80 return sqrt(lengthSquared());
81 }
82
83 double lengthSquared() const {
84 return fX * fX + fY * fY;
85 }
caryclark55888e42016-07-18 10:01:36 -070086
87 void normalize() {
88 double inverseLength = 1 / this->length();
89 fX *= inverseLength;
90 fY *= inverseLength;
91 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000092};
93
94struct SkDPoint {
95 double fX;
96 double fY;
97
98 void set(const SkPoint& pt) {
99 fX = pt.fX;
100 fY = pt.fY;
101 }
102
Mike Reed534e7762018-11-05 07:46:38 -0500103 friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
104 return { a.fX - b.fX, a.fY - b.fY };
105 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000106
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
caryclark54359292015-03-26 07:52:43 -0700120 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +0000121 void operator+=(const SkDVector& v) {
122 fX += v.fX;
123 fY += v.fY;
124 }
125
caryclark54359292015-03-26 07:52:43 -0700126 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +0000127 void operator-=(const SkDVector& v) {
128 fX -= v.fX;
129 fY -= v.fY;
130 }
131
Cary Clark59d5a0e2017-01-23 14:38:52 +0000132 // only used by testing
133 SkDPoint operator+(const SkDVector& v) {
caryclark03b03ca2015-04-23 09:13:37 -0700134 SkDPoint result = *this;
135 result += v;
136 return result;
137 }
138
139 // only used by testing
Cary Clark59d5a0e2017-01-23 14:38:52 +0000140 SkDPoint operator-(const SkDVector& v) {
caryclark03b03ca2015-04-23 09:13:37 -0700141 SkDPoint result = *this;
142 result -= v;
143 return result;
144 }
145
caryclark@google.com07393ca2013-04-08 11:47:37 +0000146 // note: this can not be implemented with
147 // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000148 // because that will not take the magnitude of the values into account
caryclark30b9fdd2016-08-31 14:36:29 -0700149 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
163 bool approximatelyDEqual(const SkPoint& a) const {
164 SkDPoint dA;
165 dA.set(a);
166 return approximatelyDEqual(dA);
167 }
168
caryclark@google.com07393ca2013-04-08 11:47:37 +0000169 bool approximatelyEqual(const SkDPoint& a) const {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000170 if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000171 return true;
172 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000173 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);
caryclark54359292015-03-26 07:52:43 -0700180 return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000181 }
182
183 bool approximatelyEqual(const SkPoint& a) const {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000184 SkDPoint dA;
185 dA.set(a);
186 return approximatelyEqual(dA);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000187 }
188
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000189 static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
190 if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000191 return true;
192 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000193 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);
caryclark55888e42016-07-18 10:01:36 -0700203 return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000204 }
205
caryclark54359292015-03-26 07:52:43 -0700206 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +0000207 bool approximatelyZero() const {
208 return approximately_zero(fX) && approximately_zero(fY);
209 }
210
211 SkPoint asSkPoint() const {
212 SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
213 return pt;
214 }
215
216 double distance(const SkDPoint& a) const {
217 SkDVector temp = *this - a;
218 return temp.length();
219 }
220
221 double distanceSquared(const SkDPoint& a) const {
222 SkDVector temp = *this - a;
223 return temp.lengthSquared();
224 }
225
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000226 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
caryclark54359292015-03-26 07:52:43 -0700233 bool roughlyEqual(const SkDPoint& a) const {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000234 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?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000242 }
243
caryclark1049f122015-04-20 08:31:59 -0700244 static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
caryclark624637c2015-05-11 07:21:27 -0700245 if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
caryclark1049f122015-04-20 08:31:59 -0700246 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
caryclark30b9fdd2016-08-31 14:36:29 -0700258 // very light weight check, should only be used for inequality check
259 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
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000267 // 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);
caryclark65f55312014-11-13 06:58:52 -0800270 static void DumpHex(const SkPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000271};
272
273#endif