DataTypes.h revision c83c70e911a38aea03db4af8dd9841d0d77bd129
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 __DataTypes_h__
8#define __DataTypes_h__
9
10#include <float.h> // for FLT_EPSILON
11#include <math.h> // for fabs, sqrt
12
13#include "SkPoint.h"
14
15#define ONE_OFF_DEBUG 0
16
17// FIXME: move these into SkTypes.h
18template <typename T> inline T SkTMax(T a, T b) {
19    if (a < b)
20        a = b;
21    return a;
22}
23
24template <typename T> inline T SkTMin(T a, T b) {
25    if (a > b)
26        a = b;
27    return a;
28}
29
30extern bool AlmostEqualUlps(float A, float B);
31inline bool AlmostEqualUlps(double A, double B) { return AlmostEqualUlps((float) A, (float) B); }
32
33// FIXME: delete
34int UlpsDiff(float A, float B);
35
36// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
37// DBL_EPSILON == 2.22045e-16
38const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
39const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
40const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
41const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
42const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
43const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // tune -- allow a few bits of error
44
45#ifdef SK_DEBUG
46const double ROUGH_EPSILON = FLT_EPSILON * 16;
47#endif
48
49inline bool approximately_zero(double x) {
50    return fabs(x) < FLT_EPSILON;
51}
52
53inline bool precisely_zero(double x) {
54    return fabs(x) < DBL_EPSILON_ERR;
55}
56
57inline bool approximately_zero(float x) {
58    return fabs(x) < FLT_EPSILON;
59}
60
61inline bool approximately_zero_cubed(double x) {
62    return fabs(x) < FLT_EPSILON_CUBED;
63}
64
65inline bool approximately_zero_half(double x) {
66    return fabs(x) < FLT_EPSILON_HALF;
67}
68
69inline bool approximately_zero_squared(double x) {
70    return fabs(x) < FLT_EPSILON_SQUARED;
71}
72
73inline bool approximately_zero_sqrt(double x) {
74    return fabs(x) < FLT_EPSILON_SQRT;
75}
76
77inline bool approximately_zero_inverse(double x) {
78    return fabs(x) > FLT_EPSILON_INVERSE;
79}
80
81// FIXME: if called multiple times with the same denom, we want to pass 1/y instead
82inline bool approximately_zero_when_compared_to(double x, double y) {
83    return x == 0 || fabs(x / y) < FLT_EPSILON;
84}
85
86// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
87// AlmostEqualUlps instead.
88inline bool approximately_equal(double x, double y) {
89#if 1
90    return approximately_zero(x - y);
91#else
92// see http://visualstudiomagazine.com/blogs/tool-tracker/2011/11/compare-floating-point-numbers.aspx
93// this allows very small (e.g. degenerate) values to compare unequally, but in this case,
94// AlmostEqualUlps should be used instead.
95    if (x == y) {
96        return true;
97    }
98    double absY = fabs(y);
99    if (x == 0) {
100        return absY < FLT_EPSILON;
101    }
102    double absX = fabs(x);
103    if (y == 0) {
104        return absX < FLT_EPSILON;
105    }
106    return fabs(x - y) < (absX > absY ? absX : absY) * FLT_EPSILON;
107#endif
108}
109
110inline bool precisely_equal(double x, double y) {
111    return precisely_zero(x - y);
112}
113
114inline bool approximately_equal_half(double x, double y) {
115    return approximately_zero_half(x - y);
116}
117
118inline bool approximately_equal_squared(double x, double y) {
119    return approximately_equal(x, y);
120}
121
122inline bool approximately_greater(double x, double y) {
123    return x - FLT_EPSILON >= y;
124}
125
126inline bool approximately_greater_or_equal(double x, double y) {
127    return x + FLT_EPSILON > y;
128}
129
130inline bool approximately_lesser(double x, double y) {
131    return x + FLT_EPSILON <= y;
132}
133
134inline bool approximately_lesser_or_equal(double x, double y) {
135    return x - FLT_EPSILON < y;
136}
137
138inline double approximately_pin(double x) {
139    return approximately_zero(x) ? 0 : x;
140}
141
142inline float approximately_pin(float x) {
143    return approximately_zero(x) ? 0 : x;
144}
145
146inline bool approximately_greater_than_one(double x) {
147    return x > 1 - FLT_EPSILON;
148}
149
150inline bool precisely_greater_than_one(double x) {
151    return x > 1 - DBL_EPSILON_ERR;
152}
153
154inline bool approximately_less_than_zero(double x) {
155    return x < FLT_EPSILON;
156}
157
158inline bool precisely_less_than_zero(double x) {
159    return x < DBL_EPSILON_ERR;
160}
161
162inline bool approximately_negative(double x) {
163    return x < FLT_EPSILON;
164}
165
166inline bool precisely_negative(double x) {
167    return x < DBL_EPSILON_ERR;
168}
169
170inline bool approximately_one_or_less(double x) {
171    return x < 1 + FLT_EPSILON;
172}
173
174inline bool approximately_positive(double x) {
175    return x > -FLT_EPSILON;
176}
177
178inline bool approximately_positive_squared(double x) {
179    return x > -(FLT_EPSILON_SQUARED);
180}
181
182inline bool approximately_zero_or_more(double x) {
183    return x > -FLT_EPSILON;
184}
185
186inline bool approximately_between(double a, double b, double c) {
187    return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
188            : approximately_negative(b - a) && approximately_negative(c - b);
189}
190
191// returns true if (a <= b <= c) || (a >= b >= c)
192inline bool between(double a, double b, double c) {
193    SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0));
194    return (a - b) * (c - b) <= 0;
195}
196
197#ifdef SK_DEBUG
198inline bool roughly_equal(double x, double y) {
199    return fabs(x - y) < ROUGH_EPSILON;
200}
201#endif
202
203struct _Point {
204    double x;
205    double y;
206
207    friend _Point operator-(const _Point& a, const _Point& b) {
208        _Point v = {a.x - b.x, a.y - b.y};
209        return v;
210    }
211
212    void operator+=(const _Point& v) {
213        x += v.x;
214        y += v.y;
215    }
216
217    void operator-=(const _Point& v) {
218        x -= v.x;
219        y -= v.y;
220    }
221
222    void operator/=(const double s) {
223        x /= s;
224        y /= s;
225    }
226
227    void operator*=(const double s) {
228        x *= s;
229        y *= s;
230    }
231
232    friend bool operator==(const _Point& a, const _Point& b) {
233        return a.x == b.x && a.y == b.y;
234    }
235
236    friend bool operator!=(const _Point& a, const _Point& b) {
237        return a.x != b.x || a.y != b.y;
238    }
239
240    // note: this can not be implemented with
241    // return approximately_equal(a.y, y) && approximately_equal(a.x, x);
242    // because that will not take the magnitude of the values
243    bool approximatelyEqual(const _Point& a) const {
244        double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.x), fabs(a.y))));
245        if (denom == 0) {
246            return true;
247        }
248        double inv = 1 / denom;
249        return approximately_equal(x * inv, a.x * inv) && approximately_equal(y * inv, a.y * inv);
250    }
251
252    bool approximatelyEqual(const SkPoint& a) const {
253        double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.fX), fabs(a.fY))));
254        if (denom == 0) {
255            return true;
256        }
257        double inv = 1 / denom;
258        return approximately_equal(x * inv, a.fX * inv) && approximately_equal(y * inv, a.fY * inv);
259    }
260
261    bool approximatelyEqualHalf(const _Point& a) const {
262        double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.x), fabs(a.y))));
263        if (denom == 0) {
264            return true;
265        }
266        double inv = 1 / denom;
267        return approximately_equal_half(x * inv, a.x * inv)
268                && approximately_equal_half(y * inv, a.y * inv);
269    }
270
271    bool approximatelyZero() const {
272        return approximately_zero(x) && approximately_zero(y);
273    }
274
275    SkPoint asSkPoint() const {
276        SkPoint pt = {SkDoubleToScalar(x), SkDoubleToScalar(y)};
277        return pt;
278    }
279
280    double cross(const _Point& a) const {
281        return x * a.y - y * a.x;
282    }
283
284    double distance(const _Point& a) const {
285        _Point temp = *this - a;
286        return temp.length();
287    }
288
289    double distanceSquared(const _Point& a) const {
290        _Point temp = *this - a;
291        return temp.lengthSquared();
292    }
293
294    double dot(const _Point& a) const {
295        return x * a.x + y * a.y;
296    }
297
298    double length() const {
299        return sqrt(lengthSquared());
300    }
301
302    double lengthSquared() const {
303        return x * x + y * y;
304    }
305
306    double roughlyEqual(const _Point& a) const {
307        return roughly_equal(a.y, y) && roughly_equal(a.x, x);
308    }
309};
310
311typedef _Point _Line[2];
312typedef _Point Quadratic[3];
313typedef _Point Triangle[3];
314typedef _Point Cubic[4];
315
316struct _Rect {
317    double left;
318    double top;
319    double right;
320    double bottom;
321
322    void add(const _Point& pt) {
323        if (left > pt.x) {
324            left = pt.x;
325        }
326        if (top > pt.y) {
327            top = pt.y;
328        }
329        if (right < pt.x) {
330            right = pt.x;
331        }
332        if (bottom < pt.y) {
333            bottom = pt.y;
334        }
335    }
336
337    // FIXME: used by debugging only ?
338    bool contains(const _Point& pt) const {
339        return approximately_between(left, pt.x, right)
340                && approximately_between(top, pt.y, bottom);
341    }
342
343    bool intersects(_Rect& r) const {
344        SkASSERT(left <= right);
345        SkASSERT(top <= bottom);
346        SkASSERT(r.left <= r.right);
347        SkASSERT(r.top <= r.bottom);
348        return r.left <= right && left <= r.right && r.top <= bottom && top <= r.bottom;
349    }
350
351    void set(const _Point& pt) {
352        left = right = pt.x;
353        top = bottom = pt.y;
354    }
355
356    void setBounds(const _Line& line) {
357        set(line[0]);
358        add(line[1]);
359    }
360
361    void setBounds(const Cubic& );
362    void setBounds(const Quadratic& );
363    void setRawBounds(const Cubic& );
364    void setRawBounds(const Quadratic& );
365};
366
367struct CubicPair {
368    const Cubic& first() const { return (const Cubic&) pts[0]; }
369    const Cubic& second() const { return (const Cubic&) pts[3]; }
370    _Point pts[7];
371};
372
373struct QuadraticPair {
374    const Quadratic& first() const { return (const Quadratic&) pts[0]; }
375    const Quadratic& second() const { return (const Quadratic&) pts[2]; }
376    _Point pts[5];
377};
378
379// FIXME: move these into SkFloatingPoint.h
380#include "SkFloatingPoint.h"
381
382#define sk_double_isnan(a) sk_float_isnan(a)
383
384// FIXME: move these to debugging file
385#if SK_DEBUG
386void mathematica_ize(char* str, size_t bufferSize);
387bool valid_wind(int winding);
388void winding_printf(int winding);
389#endif
390
391#endif // __DataTypes_h__
392