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