Home | History | Annotate | Download | only in Intersection
      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 FORCE_RELEASE 0  // set force release to 1 for multiple thread -- no debugging
     16 #define ONE_OFF_DEBUG 1
     17 #define ONE_OFF_DEBUG_MATHEMATICA 0
     18 
     19 // FIXME: move these into SkTypes.h
     20 template <typename T> inline T SkTMax(T a, T b) {
     21     if (a < b)
     22         a = b;
     23     return a;
     24 }
     25 
     26 template <typename T> inline T SkTMin(T a, T b) {
     27     if (a > b)
     28         a = b;
     29     return a;
     30 }
     31 
     32 extern bool AlmostEqualUlps(float A, float B);
     33 inline bool AlmostEqualUlps(double A, double B) { return AlmostEqualUlps((float) A, (float) B); }
     34 
     35 // FIXME: delete
     36 int UlpsDiff(float A, float B);
     37 
     38 // FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
     39 // DBL_EPSILON == 2.22045e-16
     40 const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
     41 const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
     42 const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
     43 const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
     44 const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
     45 const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // tune -- allow a few bits of error
     46 const double ROUGH_EPSILON = FLT_EPSILON * 64;
     47 const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
     48 
     49 inline bool approximately_zero(double x) {
     50     return fabs(x) < FLT_EPSILON;
     51 }
     52 
     53 inline bool precisely_zero(double x) {
     54     return fabs(x) < DBL_EPSILON_ERR;
     55 }
     56 
     57 inline bool approximately_zero(float x) {
     58     return fabs(x) < FLT_EPSILON;
     59 }
     60 
     61 inline bool approximately_zero_cubed(double x) {
     62     return fabs(x) < FLT_EPSILON_CUBED;
     63 }
     64 
     65 inline bool approximately_zero_half(double x) {
     66     return fabs(x) < FLT_EPSILON_HALF;
     67 }
     68 
     69 inline bool approximately_zero_squared(double x) {
     70     return fabs(x) < FLT_EPSILON_SQUARED;
     71 }
     72 
     73 inline bool approximately_zero_sqrt(double x) {
     74     return fabs(x) < FLT_EPSILON_SQRT;
     75 }
     76 
     77 inline 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
     82 inline 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.
     88 inline 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 
    110 inline bool precisely_equal(double x, double y) {
    111     return precisely_zero(x - y);
    112 }
    113 
    114 inline bool approximately_equal_half(double x, double y) {
    115     return approximately_zero_half(x - y);
    116 }
    117 
    118 inline bool approximately_equal_squared(double x, double y) {
    119     return approximately_equal(x, y);
    120 }
    121 
    122 inline bool approximately_greater(double x, double y) {
    123     return x - FLT_EPSILON >= y;
    124 }
    125 
    126 inline bool approximately_greater_or_equal(double x, double y) {
    127     return x + FLT_EPSILON > y;
    128 }
    129 
    130 inline bool approximately_lesser(double x, double y) {
    131     return x + FLT_EPSILON <= y;
    132 }
    133 
    134 inline bool approximately_lesser_or_equal(double x, double y) {
    135     return x - FLT_EPSILON < y;
    136 }
    137 
    138 inline double approximately_pin(double x) {
    139     return approximately_zero(x) ? 0 : x;
    140 }
    141 
    142 inline float approximately_pin(float x) {
    143     return approximately_zero(x) ? 0 : x;
    144 }
    145 
    146 inline bool approximately_greater_than_one(double x) {
    147     return x > 1 - FLT_EPSILON;
    148 }
    149 
    150 inline bool precisely_greater_than_one(double x) {
    151     return x > 1 - DBL_EPSILON_ERR;
    152 }
    153 
    154 inline bool approximately_less_than_zero(double x) {
    155     return x < FLT_EPSILON;
    156 }
    157 
    158 inline bool precisely_less_than_zero(double x) {
    159     return x < DBL_EPSILON_ERR;
    160 }
    161 
    162 inline bool approximately_negative(double x) {
    163     return x < FLT_EPSILON;
    164 }
    165 
    166 inline bool precisely_negative(double x) {
    167     return x < DBL_EPSILON_ERR;
    168 }
    169 
    170 inline bool approximately_one_or_less(double x) {
    171     return x < 1 + FLT_EPSILON;
    172 }
    173 
    174 inline bool approximately_positive(double x) {
    175     return x > -FLT_EPSILON;
    176 }
    177 
    178 inline bool approximately_positive_squared(double x) {
    179     return x > -(FLT_EPSILON_SQUARED);
    180 }
    181 
    182 inline bool approximately_zero_or_more(double x) {
    183     return x > -FLT_EPSILON;
    184 }
    185 
    186 inline 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)
    192 inline 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 inline bool more_roughly_equal(double x, double y) {
    198     return fabs(x - y) < MORE_ROUGH_EPSILON;
    199 }
    200 
    201 inline bool roughly_equal(double x, double y) {
    202     return fabs(x - y) < ROUGH_EPSILON;
    203 }
    204 
    205 struct _Point;
    206 
    207 struct _Vector {
    208     double x;
    209     double y;
    210 
    211     friend _Point operator+(const _Point& a, const _Vector& b);
    212 
    213     void operator+=(const _Vector& v) {
    214         x += v.x;
    215         y += v.y;
    216     }
    217 
    218     void operator-=(const _Vector& v) {
    219         x -= v.x;
    220         y -= v.y;
    221     }
    222 
    223     void operator/=(const double s) {
    224         x /= s;
    225         y /= s;
    226     }
    227 
    228     void operator*=(const double s) {
    229         x *= s;
    230         y *= s;
    231     }
    232 
    233     double cross(const _Vector& a) const {
    234         return x * a.y - y * a.x;
    235     }
    236 
    237     double dot(const _Vector& a) const {
    238         return x * a.x + y * a.y;
    239     }
    240 
    241     double length() const {
    242         return sqrt(lengthSquared());
    243     }
    244 
    245     double lengthSquared() const {
    246         return x * x + y * y;
    247     }
    248 
    249     SkVector asSkVector() const {
    250         SkVector v = {SkDoubleToScalar(x), SkDoubleToScalar(y)};
    251         return v;
    252     }
    253 };
    254 
    255 struct _Point {
    256     double x;
    257     double y;
    258 
    259     friend _Vector operator-(const _Point& a, const _Point& b);
    260 
    261     void operator+=(const _Vector& v) {
    262         x += v.x;
    263         y += v.y;
    264     }
    265 
    266     void operator-=(const _Vector& v) {
    267         x -= v.x;
    268         y -= v.y;
    269     }
    270 
    271     friend bool operator==(const _Point& a, const _Point& b) {
    272         return a.x == b.x && a.y == b.y;
    273     }
    274 
    275     friend bool operator!=(const _Point& a, const _Point& b) {
    276         return a.x != b.x || a.y != b.y;
    277     }
    278 
    279     // note: this can not be implemented with
    280     // return approximately_equal(a.y, y) && approximately_equal(a.x, x);
    281     // because that will not take the magnitude of the values
    282     bool approximatelyEqual(const _Point& a) const {
    283         double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.x), fabs(a.y))));
    284         if (denom == 0) {
    285             return true;
    286         }
    287         double inv = 1 / denom;
    288         return approximately_equal(x * inv, a.x * inv) && approximately_equal(y * inv, a.y * inv);
    289     }
    290 
    291     bool approximatelyEqual(const SkPoint& a) const {
    292         double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.fX), fabs(a.fY))));
    293         if (denom == 0) {
    294             return true;
    295         }
    296         double inv = 1 / denom;
    297         return approximately_equal(x * inv, a.fX * inv) && approximately_equal(y * inv, a.fY * inv);
    298     }
    299 
    300     bool approximatelyEqualHalf(const _Point& a) const {
    301         double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.x), fabs(a.y))));
    302         if (denom == 0) {
    303             return true;
    304         }
    305         double inv = 1 / denom;
    306         return approximately_equal_half(x * inv, a.x * inv)
    307                 && approximately_equal_half(y * inv, a.y * inv);
    308     }
    309 
    310     bool approximatelyZero() const {
    311         return approximately_zero(x) && approximately_zero(y);
    312     }
    313 
    314     SkPoint asSkPoint() const {
    315         SkPoint pt = {SkDoubleToScalar(x), SkDoubleToScalar(y)};
    316         return pt;
    317     }
    318 
    319     double distance(const _Point& a) const {
    320         _Vector temp = *this - a;
    321         return temp.length();
    322     }
    323 
    324     double distanceSquared(const _Point& a) const {
    325         _Vector temp = *this - a;
    326         return temp.lengthSquared();
    327     }
    328 
    329     double moreRoughlyEqual(const _Point& a) const {
    330         return more_roughly_equal(a.y, y) && more_roughly_equal(a.x, x);
    331     }
    332 
    333     double roughlyEqual(const _Point& a) const {
    334         return roughly_equal(a.y, y) && roughly_equal(a.x, x);
    335     }
    336 };
    337 
    338 typedef _Point _Line[2];
    339 typedef _Point Quadratic[3];
    340 typedef _Point Triangle[3];
    341 typedef _Point Cubic[4];
    342 
    343 struct _Rect {
    344     double left;
    345     double top;
    346     double right;
    347     double bottom;
    348 
    349     void add(const _Point& pt) {
    350         if (left > pt.x) {
    351             left = pt.x;
    352         }
    353         if (top > pt.y) {
    354             top = pt.y;
    355         }
    356         if (right < pt.x) {
    357             right = pt.x;
    358         }
    359         if (bottom < pt.y) {
    360             bottom = pt.y;
    361         }
    362     }
    363 
    364     // FIXME: used by debugging only ?
    365     bool contains(const _Point& pt) const {
    366         return approximately_between(left, pt.x, right)
    367                 && approximately_between(top, pt.y, bottom);
    368     }
    369 
    370     bool intersects(_Rect& r) const {
    371         SkASSERT(left <= right);
    372         SkASSERT(top <= bottom);
    373         SkASSERT(r.left <= r.right);
    374         SkASSERT(r.top <= r.bottom);
    375         return r.left <= right && left <= r.right && r.top <= bottom && top <= r.bottom;
    376     }
    377 
    378     void set(const _Point& pt) {
    379         left = right = pt.x;
    380         top = bottom = pt.y;
    381     }
    382 
    383     void setBounds(const _Line& line) {
    384         set(line[0]);
    385         add(line[1]);
    386     }
    387 
    388     void setBounds(const Cubic& );
    389     void setBounds(const Quadratic& );
    390     void setRawBounds(const Cubic& );
    391     void setRawBounds(const Quadratic& );
    392 };
    393 
    394 struct CubicPair {
    395     const Cubic& first() const { return (const Cubic&) pts[0]; }
    396     const Cubic& second() const { return (const Cubic&) pts[3]; }
    397     _Point pts[7];
    398 };
    399 
    400 struct QuadraticPair {
    401     const Quadratic& first() const { return (const Quadratic&) pts[0]; }
    402     const Quadratic& second() const { return (const Quadratic&) pts[2]; }
    403     _Point pts[5];
    404 };
    405 
    406 // FIXME: move these into SkFloatingPoint.h
    407 #include "SkFloatingPoint.h"
    408 
    409 #define sk_double_isnan(a) sk_float_isnan(a)
    410 
    411 // FIXME: move these to debugging file
    412 #ifdef SK_DEBUG
    413 void mathematica_ize(char* str, size_t bufferSize);
    414 bool valid_wind(int winding);
    415 void winding_printf(int winding);
    416 #endif
    417 
    418 #endif // __DataTypes_h__
    419