blob: e3d18afadd7a225089c747c2a55afff416dea229 [file] [log] [blame]
caryclark@google.com9e49fb62012-08-27 14:11:33 +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 */
caryclark@google.com639df892012-01-10 21:46:10 +00007#ifndef __DataTypes_h__
8#define __DataTypes_h__
9
caryclark@google.comaa358312013-01-29 20:28:49 +000010#include <float.h> // for FLT_EPSILON
11#include <math.h> // for fabs, sqrt
12
13#include "SkTypes.h"
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000014
caryclark@google.com0b7da432012-10-31 19:00:20 +000015extern bool AlmostEqualUlps(float A, float B);
caryclark@google.com6d0032a2013-01-04 19:41:13 +000016inline bool AlmostEqualUlps(double A, double B) { return AlmostEqualUlps((float) A, (float) B); }
17
caryclark@google.com0b7da432012-10-31 19:00:20 +000018// FIXME: delete
caryclark@google.comb45a1b42012-05-18 20:50:33 +000019int UlpsDiff(float A, float B);
caryclark@google.comb45a1b42012-05-18 20:50:33 +000020
caryclark@google.com9f602912013-01-24 21:47:16 +000021// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
22const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
caryclark@google.com73ca6242013-01-17 21:02:47 +000023const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
24const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
caryclark@google.com85ec74c2013-01-28 19:25:51 +000025const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
caryclark@google.comb45a1b42012-05-18 20:50:33 +000026
27inline bool approximately_zero(double x) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000028
caryclark@google.comb45a1b42012-05-18 20:50:33 +000029 return fabs(x) < FLT_EPSILON;
30}
31
caryclark@google.coma461ff02012-10-11 12:54:23 +000032inline bool precisely_zero(double x) {
33
34 return fabs(x) < DBL_EPSILON;
35}
36
caryclark@google.comc899ad92012-08-23 15:24:42 +000037inline bool approximately_zero(float x) {
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +000038
caryclark@google.comc899ad92012-08-23 15:24:42 +000039 return fabs(x) < FLT_EPSILON;
40}
41
caryclark@google.com9f602912013-01-24 21:47:16 +000042inline bool approximately_zero_cubed(double x) {
43 return fabs(x) < FLT_EPSILON_CUBED;
44}
45
caryclark@google.comd1688742012-09-18 20:08:37 +000046inline bool approximately_zero_squared(double x) {
caryclark@google.com73ca6242013-01-17 21:02:47 +000047 return fabs(x) < FLT_EPSILON_SQUARED;
48}
49
50inline bool approximately_zero_sqrt(double x) {
51 return fabs(x) < FLT_EPSILON_SQRT;
caryclark@google.comd1688742012-09-18 20:08:37 +000052}
53
caryclark@google.com85ec74c2013-01-28 19:25:51 +000054inline bool approximately_zero_inverse(double x) {
55 return fabs(x) > FLT_EPSILON_INVERSE;
56}
57
caryclark@google.com9f602912013-01-24 21:47:16 +000058// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
59// AlmostEqualUlps instead.
caryclark@google.comb45a1b42012-05-18 20:50:33 +000060inline bool approximately_equal(double x, double y) {
caryclark@google.com9f602912013-01-24 21:47:16 +000061#if 1
caryclark@google.com0b7da432012-10-31 19:00:20 +000062 return approximately_zero(x - y);
caryclark@google.com9f602912013-01-24 21:47:16 +000063#else
64// see http://visualstudiomagazine.com/blogs/tool-tracker/2011/11/compare-floating-point-numbers.aspx
skia.committer@gmail.com4024f322013-01-25 07:06:46 +000065// this allows very small (e.g. degenerate) values to compare unequally, but in this case,
caryclark@google.com9f602912013-01-24 21:47:16 +000066// AlmostEqualUlps should be used instead.
67 if (x == y) {
68 return true;
69 }
70 double absY = fabs(y);
71 if (x == 0) {
72 return absY < FLT_EPSILON;
73 }
74 double absX = fabs(x);
75 if (y == 0) {
76 return absX < FLT_EPSILON;
77 }
78 return fabs(x - y) < (absX > absY ? absX : absY) * FLT_EPSILON;
79#endif
caryclark@google.comb45a1b42012-05-18 20:50:33 +000080}
81
82inline bool approximately_equal_squared(double x, double y) {
83 return approximately_equal(x, y);
84}
85
86inline bool approximately_greater(double x, double y) {
87 return approximately_equal(x, y) ? false : x > y;
88}
89
90inline bool approximately_lesser(double x, double y) {
91 return approximately_equal(x, y) ? false : x < y;
92}
93
caryclark@google.comc899ad92012-08-23 15:24:42 +000094inline double approximately_pin(double x) {
95 return approximately_zero(x) ? 0 : x;
96}
97
98inline float approximately_pin(float x) {
99 return approximately_zero(x) ? 0 : x;
100}
101
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000102inline bool approximately_greater_than_one(double x) {
103 return x > 1 - FLT_EPSILON;
104}
105
caryclark@google.com185c7c42012-10-19 18:26:24 +0000106inline bool precisely_greater_than_one(double x) {
107 return x > 1 - DBL_EPSILON;
108}
109
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000110inline bool approximately_less_than_zero(double x) {
111 return x < FLT_EPSILON;
112}
113
caryclark@google.com185c7c42012-10-19 18:26:24 +0000114inline bool precisely_less_than_zero(double x) {
115 return x < DBL_EPSILON;
116}
117
caryclark@google.comb45a1b42012-05-18 20:50:33 +0000118inline bool approximately_negative(double x) {
119 return x < FLT_EPSILON;
120}
121
caryclark@google.coma461ff02012-10-11 12:54:23 +0000122inline bool precisely_negative(double x) {
123 return x < DBL_EPSILON;
124}
125
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000126inline bool approximately_one_or_less(double x) {
127 return x < 1 + FLT_EPSILON;
128}
129
130inline bool approximately_positive(double x) {
131 return x > -FLT_EPSILON;
132}
133
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000134inline bool approximately_positive_squared(double x) {
caryclark@google.com73ca6242013-01-17 21:02:47 +0000135 return x > -(FLT_EPSILON_SQUARED);
caryclark@google.come7bd5f42012-12-13 19:47:53 +0000136}
137
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000138inline bool approximately_zero_or_more(double x) {
139 return x > -FLT_EPSILON;
140}
141
caryclark@google.com235f56a2012-09-14 14:19:30 +0000142inline bool approximately_between(double a, double b, double c) {
caryclark@google.comaa358312013-01-29 20:28:49 +0000143 SkASSERT(a <= c);
caryclark@google.com235f56a2012-09-14 14:19:30 +0000144 return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
145 : approximately_negative(b - a) && approximately_negative(c - b);
146}
147
148// returns true if (a <= b <= c) || (a >= b >= c)
149inline bool between(double a, double b, double c) {
caryclark@google.comaa358312013-01-29 20:28:49 +0000150 SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0));
caryclark@google.com235f56a2012-09-14 14:19:30 +0000151 return (a - b) * (c - b) <= 0;
152}
caryclark@google.com3350c3c2012-08-24 15:24:36 +0000153
caryclark@google.com639df892012-01-10 21:46:10 +0000154struct _Point {
155 double x;
156 double y;
157
caryclark@google.com73ca6242013-01-17 21:02:47 +0000158 friend _Point operator-(const _Point& a, const _Point& b) {
159 _Point v = {a.x - b.x, a.y - b.y};
160 return v;
161 }
162
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000163 void operator+=(const _Point& v) {
164 x += v.x;
165 y += v.y;
166 }
167
caryclark@google.com639df892012-01-10 21:46:10 +0000168 void operator-=(const _Point& v) {
169 x -= v.x;
170 y -= v.y;
171 }
172
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000173 void operator/=(const double s) {
174 x /= s;
175 y /= s;
176 }
177
178 void operator*=(const double s) {
179 x *= s;
180 y *= s;
181 }
182
caryclark@google.com639df892012-01-10 21:46:10 +0000183 friend bool operator==(const _Point& a, const _Point& b) {
184 return a.x == b.x && a.y == b.y;
185 }
186
187 friend bool operator!=(const _Point& a, const _Point& b) {
caryclark@google.com9f602912013-01-24 21:47:16 +0000188 return a.x != b.x || a.y != b.y;
caryclark@google.com639df892012-01-10 21:46:10 +0000189 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000190
caryclark@google.com0b7da432012-10-31 19:00:20 +0000191 // note: this can not be implemented with
192 // return approximately_equal(a.y, y) && approximately_equal(a.x, x);
193 // because that will not take the magnitude of the values
caryclark@google.com639df892012-01-10 21:46:10 +0000194 bool approximatelyEqual(const _Point& a) const {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000195 return AlmostEqualUlps((float) x, (float) a.x)
196 && AlmostEqualUlps((float) y, (float) a.y);
caryclark@google.com639df892012-01-10 21:46:10 +0000197 }
skia.committer@gmail.com15dd3002013-01-18 07:07:28 +0000198
caryclark@google.com9f602912013-01-24 21:47:16 +0000199 double cross(const _Point& a) const {
200 return x * a.y - y * a.x;
201 }
202
203 double dot(const _Point& a) const {
caryclark@google.com73ca6242013-01-17 21:02:47 +0000204 return x * a.x + y * a.y;
205 }
caryclark@google.com9f602912013-01-24 21:47:16 +0000206
207 double length() const {
208 return sqrt(lengthSquared());
209 }
210
211 double lengthSquared() const {
212 return x * x + y * y;
213 }
214
caryclark@google.com639df892012-01-10 21:46:10 +0000215};
216
217typedef _Point _Line[2];
218typedef _Point Quadratic[3];
219typedef _Point Cubic[4];
220
221struct _Rect {
222 double left;
223 double top;
224 double right;
225 double bottom;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000226
caryclark@google.com639df892012-01-10 21:46:10 +0000227 void add(const _Point& pt) {
228 if (left > pt.x) {
229 left = pt.x;
230 }
231 if (top > pt.y) {
232 top = pt.y;
233 }
234 if (right < pt.x) {
235 right = pt.x;
236 }
237 if (bottom < pt.y) {
238 bottom = pt.y;
239 }
240 }
skia.committer@gmail.com055c7c22012-09-15 02:01:41 +0000241
caryclark@google.com235f56a2012-09-14 14:19:30 +0000242 // FIXME: used by debugging only ?
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000243 bool contains(const _Point& pt) const {
caryclark@google.com235f56a2012-09-14 14:19:30 +0000244 return approximately_between(left, pt.x, right)
245 && approximately_between(top, pt.y, bottom);
246 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000247
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000248 bool intersects(_Rect& r) const {
caryclark@google.comaa358312013-01-29 20:28:49 +0000249 SkASSERT(left <= right);
250 SkASSERT(top <= bottom);
251 SkASSERT(r.left <= r.right);
252 SkASSERT(r.top <= r.bottom);
caryclark@google.com85ec74c2013-01-28 19:25:51 +0000253 return r.left <= right && left <= r.right && r.top <= bottom && top <= r.bottom;
caryclark@google.com05c4bad2013-01-19 13:22:39 +0000254 }
255
caryclark@google.comc6825902012-02-03 22:07:47 +0000256 void set(const _Point& pt) {
257 left = right = pt.x;
258 top = bottom = pt.y;
259 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000260
caryclark@google.com639df892012-01-10 21:46:10 +0000261 void setBounds(const _Line& line) {
caryclark@google.comc6825902012-02-03 22:07:47 +0000262 set(line[0]);
caryclark@google.com639df892012-01-10 21:46:10 +0000263 add(line[1]);
264 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000265
caryclark@google.comc6825902012-02-03 22:07:47 +0000266 void setBounds(const Cubic& );
267 void setBounds(const Quadratic& );
268 void setRawBounds(const Cubic& );
269 void setRawBounds(const Quadratic& );
caryclark@google.com639df892012-01-10 21:46:10 +0000270};
271
272struct CubicPair {
273 const Cubic& first() const { return (const Cubic&) pts[0]; }
274 const Cubic& second() const { return (const Cubic&) pts[3]; }
275 _Point pts[7];
276};
277
278struct QuadraticPair {
279 const Quadratic& first() const { return (const Quadratic&) pts[0]; }
280 const Quadratic& second() const { return (const Quadratic&) pts[2]; }
281 _Point pts[5];
282};
283
caryclark@google.com9f602912013-01-24 21:47:16 +0000284// FIXME: move these into SkTypes.h
285template <typename T> inline T SkTMax(T a, T b) {
286 if (a < b)
287 a = b;
288 return a;
289}
290
291template <typename T> inline T SkTMin(T a, T b) {
292 if (a > b)
293 a = b;
294 return a;
295}
296
caryclark@google.com639df892012-01-10 21:46:10 +0000297#endif // __DataTypes_h__