blob: bca0530fedb01b83c3d64d579b3962216ef7363a [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkPoint.h"
11#include "src/pathops/SkPathOpsTypes.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000012
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
Mike Reedbae61692019-07-12 11:00:41 -040021 SkDVector& set(const SkVector& pt) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000022 fX = pt.fX;
23 fY = pt.fY;
Mike Reedbae61692019-07-12 11:00:41 -040024 return *this;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000025 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000026
caryclark54359292015-03-26 07:52:43 -070027 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000028 void operator+=(const SkDVector& v) {
29 fX += v.fX;
30 fY += v.fY;
31 }
32
caryclark54359292015-03-26 07:52:43 -070033 // only called by nearestT, which is currently only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000034 void operator-=(const SkDVector& v) {
35 fX -= v.fX;
36 fY -= v.fY;
37 }
38
Cary Clark59d5a0e2017-01-23 14:38:52 +000039 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000040 void operator/=(const double s) {
41 fX /= s;
42 fY /= s;
43 }
44
caryclark54359292015-03-26 07:52:43 -070045 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000046 void operator*=(const double s) {
47 fX *= s;
48 fY *= s;
49 }
50
51 SkVector asSkVector() const {
52 SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
53 return v;
54 }
55
caryclark54359292015-03-26 07:52:43 -070056 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +000057 double cross(const SkDVector& a) const {
58 return fX * a.fY - fY * a.fX;
59 }
60
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000061 // similar to cross, this bastardization considers nearly coincident to be zero
caryclark55888e42016-07-18 10:01:36 -070062 // uses ulps epsilon == 16
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000063 double crossCheck(const SkDVector& a) const {
64 double xy = fX * a.fY;
65 double yx = fY * a.fX;
66 return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
67 }
68
caryclark55888e42016-07-18 10:01:36 -070069 // allow tinier numbers
70 double crossNoNormalCheck(const SkDVector& a) const {
71 double xy = fX * a.fY;
72 double yx = fY * a.fX;
73 return AlmostEqualUlpsNoNormalCheck(xy, yx) ? 0 : xy - yx;
74 }
75
caryclark@google.com07393ca2013-04-08 11:47:37 +000076 double dot(const SkDVector& a) const {
77 return fX * a.fX + fY * a.fY;
78 }
79
80 double length() const {
81 return sqrt(lengthSquared());
82 }
83
84 double lengthSquared() const {
85 return fX * fX + fY * fY;
86 }
caryclark55888e42016-07-18 10:01:36 -070087
Mike Reedbae61692019-07-12 11:00:41 -040088 SkDVector& normalize() {
89 double inverseLength = sk_ieee_double_divide(1, this->length());
caryclark55888e42016-07-18 10:01:36 -070090 fX *= inverseLength;
91 fY *= inverseLength;
Mike Reedbae61692019-07-12 11:00:41 -040092 return *this;
93 }
94
95 bool isFinite() const {
96 return std::isfinite(fX) && std::isfinite(fY);
caryclark55888e42016-07-18 10:01:36 -070097 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000098};
99
100struct SkDPoint {
101 double fX;
102 double fY;
103
104 void set(const SkPoint& pt) {
105 fX = pt.fX;
106 fY = pt.fY;
107 }
108
Mike Reed534e7762018-11-05 07:46:38 -0500109 friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
110 return { a.fX - b.fX, a.fY - b.fY };
111 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000112
113 friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
114 return a.fX == b.fX && a.fY == b.fY;
115 }
116
117 friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
118 return a.fX != b.fX || a.fY != b.fY;
119 }
120
121 void operator=(const SkPoint& pt) {
122 fX = pt.fX;
123 fY = pt.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
caryclark54359292015-03-26 07:52:43 -0700132 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +0000133 void operator-=(const SkDVector& v) {
134 fX -= v.fX;
135 fY -= v.fY;
136 }
137
Cary Clark59d5a0e2017-01-23 14:38:52 +0000138 // only used by testing
139 SkDPoint operator+(const SkDVector& v) {
caryclark03b03ca2015-04-23 09:13:37 -0700140 SkDPoint result = *this;
141 result += v;
142 return result;
143 }
144
145 // only used by testing
Cary Clark59d5a0e2017-01-23 14:38:52 +0000146 SkDPoint operator-(const SkDVector& v) {
caryclark03b03ca2015-04-23 09:13:37 -0700147 SkDPoint result = *this;
148 result -= v;
149 return result;
150 }
151
caryclark@google.com07393ca2013-04-08 11:47:37 +0000152 // note: this can not be implemented with
153 // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000154 // because that will not take the magnitude of the values into account
caryclark30b9fdd2016-08-31 14:36:29 -0700155 bool approximatelyDEqual(const SkDPoint& a) const {
156 if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
157 return true;
158 }
159 if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
160 return false;
161 }
162 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
163 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
164 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
165 largest = SkTMax(largest, -tiniest);
166 return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
167 }
168
169 bool approximatelyDEqual(const SkPoint& a) const {
170 SkDPoint dA;
171 dA.set(a);
172 return approximatelyDEqual(dA);
173 }
174
caryclark@google.com07393ca2013-04-08 11:47:37 +0000175 bool approximatelyEqual(const SkDPoint& a) const {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000176 if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000177 return true;
178 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000179 if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
180 return false;
181 }
182 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
183 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
184 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
185 largest = SkTMax(largest, -tiniest);
caryclark54359292015-03-26 07:52:43 -0700186 return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000187 }
188
189 bool approximatelyEqual(const SkPoint& a) const {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000190 SkDPoint dA;
191 dA.set(a);
192 return approximatelyEqual(dA);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000193 }
194
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000195 static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
196 if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000197 return true;
198 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000199 if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
200 return false;
201 }
202 SkDPoint dA, dB;
203 dA.set(a);
204 dB.set(b);
205 double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
206 float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
207 float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
208 largest = SkTMax(largest, -tiniest);
caryclark55888e42016-07-18 10:01:36 -0700209 return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000210 }
211
caryclark54359292015-03-26 07:52:43 -0700212 // only used by testing
caryclark@google.com07393ca2013-04-08 11:47:37 +0000213 bool approximatelyZero() const {
214 return approximately_zero(fX) && approximately_zero(fY);
215 }
216
217 SkPoint asSkPoint() const {
218 SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
219 return pt;
220 }
221
222 double distance(const SkDPoint& a) const {
223 SkDVector temp = *this - a;
224 return temp.length();
225 }
226
227 double distanceSquared(const SkDPoint& a) const {
228 SkDVector temp = *this - a;
229 return temp.lengthSquared();
230 }
231
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000232 static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
233 SkDPoint result;
234 result.fX = (a.fX + b.fX) / 2;
235 result.fY = (a.fY + b.fY) / 2;
236 return result;
237 }
238
caryclark54359292015-03-26 07:52:43 -0700239 bool roughlyEqual(const SkDPoint& a) const {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000240 if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
241 return true;
242 }
243 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
244 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
245 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
246 largest = SkTMax(largest, -tiniest);
247 return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000248 }
249
caryclark1049f122015-04-20 08:31:59 -0700250 static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
caryclark624637c2015-05-11 07:21:27 -0700251 if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
caryclark1049f122015-04-20 08:31:59 -0700252 return false;
253 }
254 SkDPoint dA, dB;
255 dA.set(a);
256 dB.set(b);
257 double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
258 float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
259 float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
260 largest = SkTMax(largest, -tiniest);
261 return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
262 }
263
caryclark30b9fdd2016-08-31 14:36:29 -0700264 // very light weight check, should only be used for inequality check
265 static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
266 float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY),
267 SkTMax(SkTAbs(b.fX), SkTAbs(b.fY))));
268 SkVector diffs = a - b;
269 float largestDiff = SkTMax(diffs.fX, diffs.fY);
270 return roughly_zero_when_compared_to(largestDiff, largestNumber);
271 }
272
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000273 // utilities callable by the user from the debugger when the implementation code is linked in
274 void dump() const;
275 static void Dump(const SkPoint& pt);
caryclark65f55312014-11-13 06:58:52 -0800276 static void DumpHex(const SkPoint& pt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000277};
278
279#endif