/*
|
* 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 SkPathOpsPoint_DEFINED
|
#define SkPathOpsPoint_DEFINED
|
|
#include "SkPathOpsTypes.h"
|
#include "SkPoint.h"
|
|
inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) {
|
return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY);
|
}
|
|
struct SkDVector {
|
double fX;
|
double fY;
|
|
void set(const SkVector& pt) {
|
fX = pt.fX;
|
fY = pt.fY;
|
}
|
|
// only used by testing
|
void operator+=(const SkDVector& v) {
|
fX += v.fX;
|
fY += v.fY;
|
}
|
|
// only called by nearestT, which is currently only used by testing
|
void operator-=(const SkDVector& v) {
|
fX -= v.fX;
|
fY -= v.fY;
|
}
|
|
// only used by testing
|
void operator/=(const double s) {
|
fX /= s;
|
fY /= s;
|
}
|
|
// only used by testing
|
void operator*=(const double s) {
|
fX *= s;
|
fY *= s;
|
}
|
|
SkVector asSkVector() const {
|
SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
|
return v;
|
}
|
|
// only used by testing
|
double cross(const SkDVector& a) const {
|
return fX * a.fY - fY * a.fX;
|
}
|
|
// similar to cross, this bastardization considers nearly coincident to be zero
|
// uses ulps epsilon == 16
|
double crossCheck(const SkDVector& a) const {
|
double xy = fX * a.fY;
|
double yx = fY * a.fX;
|
return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
|
}
|
|
// allow tinier numbers
|
double crossNoNormalCheck(const SkDVector& a) const {
|
double xy = fX * a.fY;
|
double yx = fY * a.fX;
|
return AlmostEqualUlpsNoNormalCheck(xy, yx) ? 0 : xy - yx;
|
}
|
|
double dot(const SkDVector& a) const {
|
return fX * a.fX + fY * a.fY;
|
}
|
|
double length() const {
|
return sqrt(lengthSquared());
|
}
|
|
double lengthSquared() const {
|
return fX * fX + fY * fY;
|
}
|
|
void normalize() {
|
double inverseLength = 1 / this->length();
|
fX *= inverseLength;
|
fY *= inverseLength;
|
}
|
};
|
|
struct SkDPoint {
|
double fX;
|
double fY;
|
|
void set(const SkPoint& pt) {
|
fX = pt.fX;
|
fY = pt.fY;
|
}
|
|
friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
|
return { a.fX - b.fX, a.fY - b.fY };
|
}
|
|
friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
|
return a.fX == b.fX && a.fY == b.fY;
|
}
|
|
friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
|
return a.fX != b.fX || a.fY != b.fY;
|
}
|
|
void operator=(const SkPoint& pt) {
|
fX = pt.fX;
|
fY = pt.fY;
|
}
|
|
// only used by testing
|
void operator+=(const SkDVector& v) {
|
fX += v.fX;
|
fY += v.fY;
|
}
|
|
// only used by testing
|
void operator-=(const SkDVector& v) {
|
fX -= v.fX;
|
fY -= v.fY;
|
}
|
|
// only used by testing
|
SkDPoint operator+(const SkDVector& v) {
|
SkDPoint result = *this;
|
result += v;
|
return result;
|
}
|
|
// only used by testing
|
SkDPoint operator-(const SkDVector& v) {
|
SkDPoint result = *this;
|
result -= v;
|
return result;
|
}
|
|
// note: this can not be implemented with
|
// return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
|
// because that will not take the magnitude of the values into account
|
bool approximatelyDEqual(const SkDPoint& a) const {
|
if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
|
return true;
|
}
|
if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
|
return false;
|
}
|
double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
|
double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
|
double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
|
largest = SkTMax(largest, -tiniest);
|
return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
|
}
|
|
bool approximatelyDEqual(const SkPoint& a) const {
|
SkDPoint dA;
|
dA.set(a);
|
return approximatelyDEqual(dA);
|
}
|
|
bool approximatelyEqual(const SkDPoint& a) const {
|
if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
|
return true;
|
}
|
if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
|
return false;
|
}
|
double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
|
double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
|
double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
|
largest = SkTMax(largest, -tiniest);
|
return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
|
}
|
|
bool approximatelyEqual(const SkPoint& a) const {
|
SkDPoint dA;
|
dA.set(a);
|
return approximatelyEqual(dA);
|
}
|
|
static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
|
if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
|
return true;
|
}
|
if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
|
return false;
|
}
|
SkDPoint dA, dB;
|
dA.set(a);
|
dB.set(b);
|
double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
|
float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
|
float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
|
largest = SkTMax(largest, -tiniest);
|
return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
|
}
|
|
// only used by testing
|
bool approximatelyZero() const {
|
return approximately_zero(fX) && approximately_zero(fY);
|
}
|
|
SkPoint asSkPoint() const {
|
SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
|
return pt;
|
}
|
|
double distance(const SkDPoint& a) const {
|
SkDVector temp = *this - a;
|
return temp.length();
|
}
|
|
double distanceSquared(const SkDPoint& a) const {
|
SkDVector temp = *this - a;
|
return temp.lengthSquared();
|
}
|
|
static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
|
SkDPoint result;
|
result.fX = (a.fX + b.fX) / 2;
|
result.fY = (a.fY + b.fY) / 2;
|
return result;
|
}
|
|
bool roughlyEqual(const SkDPoint& a) const {
|
if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
|
return true;
|
}
|
double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ?
|
double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
|
double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
|
largest = SkTMax(largest, -tiniest);
|
return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
|
}
|
|
static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
|
if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
|
return false;
|
}
|
SkDPoint dA, dB;
|
dA.set(a);
|
dB.set(b);
|
double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ?
|
float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
|
float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
|
largest = SkTMax(largest, -tiniest);
|
return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
|
}
|
|
// very light weight check, should only be used for inequality check
|
static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
|
float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY),
|
SkTMax(SkTAbs(b.fX), SkTAbs(b.fY))));
|
SkVector diffs = a - b;
|
float largestDiff = SkTMax(diffs.fX, diffs.fY);
|
return roughly_zero_when_compared_to(largestDiff, largestNumber);
|
}
|
|
// utilities callable by the user from the debugger when the implementation code is linked in
|
void dump() const;
|
static void Dump(const SkPoint& pt);
|
static void DumpHex(const SkPoint& pt);
|
};
|
|
#endif
|