blob: e3d18afadd7a225089c747c2a55afff416dea229 [file] [log] [blame]
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef __DataTypes_h__
#define __DataTypes_h__
#include <float.h> // for FLT_EPSILON
#include <math.h> // for fabs, sqrt
#include "SkTypes.h"
extern bool AlmostEqualUlps(float A, float B);
inline bool AlmostEqualUlps(double A, double B) { return AlmostEqualUlps((float) A, (float) B); }
// FIXME: delete
int UlpsDiff(float A, float B);
// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
inline bool approximately_zero(double x) {
return fabs(x) < FLT_EPSILON;
}
inline bool precisely_zero(double x) {
return fabs(x) < DBL_EPSILON;
}
inline bool approximately_zero(float x) {
return fabs(x) < FLT_EPSILON;
}
inline bool approximately_zero_cubed(double x) {
return fabs(x) < FLT_EPSILON_CUBED;
}
inline bool approximately_zero_squared(double x) {
return fabs(x) < FLT_EPSILON_SQUARED;
}
inline bool approximately_zero_sqrt(double x) {
return fabs(x) < FLT_EPSILON_SQRT;
}
inline bool approximately_zero_inverse(double x) {
return fabs(x) > FLT_EPSILON_INVERSE;
}
// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
// AlmostEqualUlps instead.
inline bool approximately_equal(double x, double y) {
#if 1
return approximately_zero(x - y);
#else
// see http://visualstudiomagazine.com/blogs/tool-tracker/2011/11/compare-floating-point-numbers.aspx
// this allows very small (e.g. degenerate) values to compare unequally, but in this case,
// AlmostEqualUlps should be used instead.
if (x == y) {
return true;
}
double absY = fabs(y);
if (x == 0) {
return absY < FLT_EPSILON;
}
double absX = fabs(x);
if (y == 0) {
return absX < FLT_EPSILON;
}
return fabs(x - y) < (absX > absY ? absX : absY) * FLT_EPSILON;
#endif
}
inline bool approximately_equal_squared(double x, double y) {
return approximately_equal(x, y);
}
inline bool approximately_greater(double x, double y) {
return approximately_equal(x, y) ? false : x > y;
}
inline bool approximately_lesser(double x, double y) {
return approximately_equal(x, y) ? false : x < y;
}
inline double approximately_pin(double x) {
return approximately_zero(x) ? 0 : x;
}
inline float approximately_pin(float x) {
return approximately_zero(x) ? 0 : x;
}
inline bool approximately_greater_than_one(double x) {
return x > 1 - FLT_EPSILON;
}
inline bool precisely_greater_than_one(double x) {
return x > 1 - DBL_EPSILON;
}
inline bool approximately_less_than_zero(double x) {
return x < FLT_EPSILON;
}
inline bool precisely_less_than_zero(double x) {
return x < DBL_EPSILON;
}
inline bool approximately_negative(double x) {
return x < FLT_EPSILON;
}
inline bool precisely_negative(double x) {
return x < DBL_EPSILON;
}
inline bool approximately_one_or_less(double x) {
return x < 1 + FLT_EPSILON;
}
inline bool approximately_positive(double x) {
return x > -FLT_EPSILON;
}
inline bool approximately_positive_squared(double x) {
return x > -(FLT_EPSILON_SQUARED);
}
inline bool approximately_zero_or_more(double x) {
return x > -FLT_EPSILON;
}
inline bool approximately_between(double a, double b, double c) {
SkASSERT(a <= c);
return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
: approximately_negative(b - a) && approximately_negative(c - b);
}
// returns true if (a <= b <= c) || (a >= b >= c)
inline bool between(double a, double b, double c) {
SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0));
return (a - b) * (c - b) <= 0;
}
struct _Point {
double x;
double y;
friend _Point operator-(const _Point& a, const _Point& b) {
_Point v = {a.x - b.x, a.y - b.y};
return v;
}
void operator+=(const _Point& v) {
x += v.x;
y += v.y;
}
void operator-=(const _Point& v) {
x -= v.x;
y -= v.y;
}
void operator/=(const double s) {
x /= s;
y /= s;
}
void operator*=(const double s) {
x *= s;
y *= s;
}
friend bool operator==(const _Point& a, const _Point& b) {
return a.x == b.x && a.y == b.y;
}
friend bool operator!=(const _Point& a, const _Point& b) {
return a.x != b.x || a.y != b.y;
}
// note: this can not be implemented with
// return approximately_equal(a.y, y) && approximately_equal(a.x, x);
// because that will not take the magnitude of the values
bool approximatelyEqual(const _Point& a) const {
return AlmostEqualUlps((float) x, (float) a.x)
&& AlmostEqualUlps((float) y, (float) a.y);
}
double cross(const _Point& a) const {
return x * a.y - y * a.x;
}
double dot(const _Point& a) const {
return x * a.x + y * a.y;
}
double length() const {
return sqrt(lengthSquared());
}
double lengthSquared() const {
return x * x + y * y;
}
};
typedef _Point _Line[2];
typedef _Point Quadratic[3];
typedef _Point Cubic[4];
struct _Rect {
double left;
double top;
double right;
double bottom;
void add(const _Point& pt) {
if (left > pt.x) {
left = pt.x;
}
if (top > pt.y) {
top = pt.y;
}
if (right < pt.x) {
right = pt.x;
}
if (bottom < pt.y) {
bottom = pt.y;
}
}
// FIXME: used by debugging only ?
bool contains(const _Point& pt) const {
return approximately_between(left, pt.x, right)
&& approximately_between(top, pt.y, bottom);
}
bool intersects(_Rect& r) const {
SkASSERT(left <= right);
SkASSERT(top <= bottom);
SkASSERT(r.left <= r.right);
SkASSERT(r.top <= r.bottom);
return r.left <= right && left <= r.right && r.top <= bottom && top <= r.bottom;
}
void set(const _Point& pt) {
left = right = pt.x;
top = bottom = pt.y;
}
void setBounds(const _Line& line) {
set(line[0]);
add(line[1]);
}
void setBounds(const Cubic& );
void setBounds(const Quadratic& );
void setRawBounds(const Cubic& );
void setRawBounds(const Quadratic& );
};
struct CubicPair {
const Cubic& first() const { return (const Cubic&) pts[0]; }
const Cubic& second() const { return (const Cubic&) pts[3]; }
_Point pts[7];
};
struct QuadraticPair {
const Quadratic& first() const { return (const Quadratic&) pts[0]; }
const Quadratic& second() const { return (const Quadratic&) pts[2]; }
_Point pts[5];
};
// FIXME: move these into SkTypes.h
template <typename T> inline T SkTMax(T a, T b) {
if (a < b)
a = b;
return a;
}
template <typename T> inline T SkTMin(T a, T b) {
if (a > b)
a = b;
return a;
}
#endif // __DataTypes_h__