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 "include/core/SkPoint.h"
11#include "include/core/SkTypes.h"
12#include "include/private/base/SkTemplates.h"
13#include "src/pathops/SkPathOpsTypes.h"
14
15inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) {
16 return AlmostEqualUlps(a: pt1.fX, b: pt2.fX) && AlmostEqualUlps(a: pt1.fY, b: pt2.fY);
17}
18
19struct SkDVector {
20 double fX;
21 double fY;
22
23 SkDVector& set(const SkVector& pt) {
24 fX = pt.fX;
25 fY = pt.fY;
26 return *this;
27 }
28
29 // only used by testing
30 void operator+=(const SkDVector& v) {
31 fX += v.fX;
32 fY += v.fY;
33 }
34
35 // only called by nearestT, which is currently only used by testing
36 void operator-=(const SkDVector& v) {
37 fX -= v.fX;
38 fY -= v.fY;
39 }
40
41 // only used by testing
42 void operator/=(const double s) {
43 fX /= s;
44 fY /= s;
45 }
46
47 // only used by testing
48 void operator*=(const double s) {
49 fX *= s;
50 fY *= s;
51 }
52
53 SkVector asSkVector() const {
54 SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
55 return v;
56 }
57
58 // only used by testing
59 double cross(const SkDVector& a) const {
60 return fX * a.fY - fY * a.fX;
61 }
62
63 // similar to cross, this bastardization considers nearly coincident to be zero
64 // uses ulps epsilon == 16
65 double crossCheck(const SkDVector& a) const {
66 double xy = fX * a.fY;
67 double yx = fY * a.fX;
68 return AlmostEqualUlps(a: xy, b: yx) ? 0 : xy - yx;
69 }
70
71 // allow tinier numbers
72 double crossNoNormalCheck(const SkDVector& a) const {
73 double xy = fX * a.fY;
74 double yx = fY * a.fX;
75 return AlmostEqualUlpsNoNormalCheck(a: xy, b: yx) ? 0 : xy - yx;
76 }
77
78 double dot(const SkDVector& a) const {
79 return fX * a.fX + fY * a.fY;
80 }
81
82 double length() const {
83 return sqrt(x: lengthSquared());
84 }
85
86 double lengthSquared() const {
87 return fX * fX + fY * fY;
88 }
89
90 SkDVector& normalize() {
91 double inverseLength = sk_ieee_double_divide(numer: 1, denom: this->length());
92 fX *= inverseLength;
93 fY *= inverseLength;
94 return *this;
95 }
96
97 bool isFinite() const {
98 return std::isfinite(lcpp_x: fX) && std::isfinite(lcpp_x: fY);
99 }
100};
101
102struct SkDPoint {
103 double fX;
104 double fY;
105
106 void set(const SkPoint& pt) {
107 fX = pt.fX;
108 fY = pt.fY;
109 }
110
111 friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
112 return { .fX: a.fX - b.fX, .fY: a.fY - b.fY };
113 }
114
115 friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
116 return a.fX == b.fX && a.fY == b.fY;
117 }
118
119 friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
120 return a.fX != b.fX || a.fY != b.fY;
121 }
122
123 void operator=(const SkPoint& pt) {
124 fX = pt.fX;
125 fY = pt.fY;
126 }
127
128 // only used by testing
129 void operator+=(const SkDVector& v) {
130 fX += v.fX;
131 fY += v.fY;
132 }
133
134 // only used by testing
135 void operator-=(const SkDVector& v) {
136 fX -= v.fX;
137 fY -= v.fY;
138 }
139
140 // only used by testing
141 SkDPoint operator+(const SkDVector& v) {
142 SkDPoint result = *this;
143 result += v;
144 return result;
145 }
146
147 // only used by testing
148 SkDPoint operator-(const SkDVector& v) {
149 SkDPoint result = *this;
150 result -= v;
151 return result;
152 }
153
154 // note: this can not be implemented with
155 // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
156 // because that will not take the magnitude of the values into account
157 bool approximatelyDEqual(const SkDPoint& a) const {
158 if (approximately_equal(x: fX, y: a.fX) && approximately_equal(x: fY, y: a.fY)) {
159 return true;
160 }
161 if (!RoughlyEqualUlps(a: fX, b: a.fX) || !RoughlyEqualUlps(a: fY, b: a.fY)) {
162 return false;
163 }
164 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
165 double tiniest = std::min(a: std::min(a: std::min(a: fX, b: a.fX), b: fY), b: a.fY);
166 double largest = std::max(a: std::max(a: std::max(a: fX, b: a.fX), b: fY), b: a.fY);
167 largest = std::max(a: largest, b: -tiniest);
168 return AlmostDequalUlps(a: largest, b: largest + dist); // is the dist within ULPS tolerance?
169 }
170
171 bool approximatelyDEqual(const SkPoint& a) const {
172 SkDPoint dA;
173 dA.set(a);
174 return approximatelyDEqual(a: dA);
175 }
176
177 bool approximatelyEqual(const SkDPoint& a) const {
178 if (approximately_equal(x: fX, y: a.fX) && approximately_equal(x: fY, y: a.fY)) {
179 return true;
180 }
181 if (!RoughlyEqualUlps(a: fX, b: a.fX) || !RoughlyEqualUlps(a: fY, b: a.fY)) {
182 return false;
183 }
184 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
185 double tiniest = std::min(a: std::min(a: std::min(a: fX, b: a.fX), b: fY), b: a.fY);
186 double largest = std::max(a: std::max(a: std::max(a: fX, b: a.fX), b: fY), b: a.fY);
187 largest = std::max(a: largest, b: -tiniest);
188 return AlmostPequalUlps(a: largest, b: largest + dist); // is the dist within ULPS tolerance?
189 }
190
191 bool approximatelyEqual(const SkPoint& a) const {
192 SkDPoint dA;
193 dA.set(a);
194 return approximatelyEqual(a: dA);
195 }
196
197 static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
198 if (approximately_equal(x: a.fX, y: b.fX) && approximately_equal(x: a.fY, y: b.fY)) {
199 return true;
200 }
201 if (!RoughlyEqualUlps(a: a.fX, b: b.fX) || !RoughlyEqualUlps(a: a.fY, b: b.fY)) {
202 return false;
203 }
204 SkDPoint dA, dB;
205 dA.set(a);
206 dB.set(b);
207 double dist = dA.distance(a: dB); // OPTIMIZATION: can we compare against distSq instead ?
208 float tiniest = std::min(a: std::min(a: std::min(a: a.fX, b: b.fX), b: a.fY), b: b.fY);
209 float largest = std::max(a: std::max(a: std::max(a: a.fX, b: b.fX), b: a.fY), b: b.fY);
210 largest = std::max(a: largest, b: -tiniest);
211 return AlmostDequalUlps(a: (double) largest, b: largest + dist); // is dist within ULPS tolerance?
212 }
213
214 // only used by testing
215 bool approximatelyZero() const {
216 return approximately_zero(x: fX) && approximately_zero(x: fY);
217 }
218
219 SkPoint asSkPoint() const {
220 SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
221 return pt;
222 }
223
224 double distance(const SkDPoint& a) const {
225 SkDVector temp = *this - a;
226 return temp.length();
227 }
228
229 double distanceSquared(const SkDPoint& a) const {
230 SkDVector temp = *this - a;
231 return temp.lengthSquared();
232 }
233
234 static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
235 SkDPoint result;
236 result.fX = (a.fX + b.fX) / 2;
237 result.fY = (a.fY + b.fY) / 2;
238 return result;
239 }
240
241 bool roughlyEqual(const SkDPoint& a) const {
242 if (roughly_equal(x: fX, y: a.fX) && roughly_equal(x: fY, y: a.fY)) {
243 return true;
244 }
245 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
246 double tiniest = std::min(a: std::min(a: std::min(a: fX, b: a.fX), b: fY), b: a.fY);
247 double largest = std::max(a: std::max(a: std::max(a: fX, b: a.fX), b: fY), b: a.fY);
248 largest = std::max(a: largest, b: -tiniest);
249 return RoughlyEqualUlps(a: largest, b: largest + dist); // is the dist within ULPS tolerance?
250 }
251
252 static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
253 if (!RoughlyEqualUlps(a: a.fX, b: b.fX) && !RoughlyEqualUlps(a: a.fY, b: b.fY)) {
254 return false;
255 }
256 SkDPoint dA, dB;
257 dA.set(a);
258 dB.set(b);
259 double dist = dA.distance(a: dB); // OPTIMIZATION: can we compare against distSq instead ?
260 float tiniest = std::min(a: std::min(a: std::min(a: a.fX, b: b.fX), b: a.fY), b: b.fY);
261 float largest = std::max(a: std::max(a: std::max(a: a.fX, b: b.fX), b: a.fY), b: b.fY);
262 largest = std::max(a: largest, b: -tiniest);
263 return RoughlyEqualUlps(a: (double) largest, b: largest + dist); // is dist within ULPS tolerance?
264 }
265
266 // very light weight check, should only be used for inequality check
267 static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
268 float largestNumber = std::max(a: SkTAbs(value: a.fX), b: std::max(a: SkTAbs(value: a.fY),
269 b: std::max(a: SkTAbs(value: b.fX), b: SkTAbs(value: b.fY))));
270 SkVector diffs = a - b;
271 float largestDiff = std::max(a: diffs.fX, b: diffs.fY);
272 return roughly_zero_when_compared_to(x: largestDiff, y: largestNumber);
273 }
274
275 // utilities callable by the user from the debugger when the implementation code is linked in
276 void dump() const;
277 static void Dump(const SkPoint& pt);
278 static void DumpHex(const SkPoint& pt);
279};
280
281#endif
282

source code of flutter_engine/third_party/skia/src/pathops/SkPathOpsPoint.h