michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: #ifndef SkPathOpsPoint_DEFINED michael@0: #define SkPathOpsPoint_DEFINED michael@0: michael@0: #include "SkPathOpsTypes.h" michael@0: #include "SkPoint.h" michael@0: michael@0: inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) { michael@0: return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY); michael@0: } michael@0: michael@0: struct SkDVector { michael@0: double fX, fY; michael@0: michael@0: friend SkDPoint operator+(const SkDPoint& a, const SkDVector& b); michael@0: michael@0: void operator+=(const SkDVector& v) { michael@0: fX += v.fX; michael@0: fY += v.fY; michael@0: } michael@0: michael@0: void operator-=(const SkDVector& v) { michael@0: fX -= v.fX; michael@0: fY -= v.fY; michael@0: } michael@0: michael@0: void operator/=(const double s) { michael@0: fX /= s; michael@0: fY /= s; michael@0: } michael@0: michael@0: void operator*=(const double s) { michael@0: fX *= s; michael@0: fY *= s; michael@0: } michael@0: michael@0: SkVector asSkVector() const { michael@0: SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)}; michael@0: return v; michael@0: } michael@0: michael@0: double cross(const SkDVector& a) const { michael@0: return fX * a.fY - fY * a.fX; michael@0: } michael@0: michael@0: double dot(const SkDVector& a) const { michael@0: return fX * a.fX + fY * a.fY; michael@0: } michael@0: michael@0: double length() const { michael@0: return sqrt(lengthSquared()); michael@0: } michael@0: michael@0: double lengthSquared() const { michael@0: return fX * fX + fY * fY; michael@0: } michael@0: }; michael@0: michael@0: struct SkDPoint { michael@0: double fX; michael@0: double fY; michael@0: michael@0: void set(const SkPoint& pt) { michael@0: fX = pt.fX; michael@0: fY = pt.fY; michael@0: } michael@0: michael@0: friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b); michael@0: michael@0: friend bool operator==(const SkDPoint& a, const SkDPoint& b) { michael@0: return a.fX == b.fX && a.fY == b.fY; michael@0: } michael@0: michael@0: friend bool operator!=(const SkDPoint& a, const SkDPoint& b) { michael@0: return a.fX != b.fX || a.fY != b.fY; michael@0: } michael@0: michael@0: void operator=(const SkPoint& pt) { michael@0: fX = pt.fX; michael@0: fY = pt.fY; michael@0: } michael@0: michael@0: michael@0: void operator+=(const SkDVector& v) { michael@0: fX += v.fX; michael@0: fY += v.fY; michael@0: } michael@0: michael@0: void operator-=(const SkDVector& v) { michael@0: fX -= v.fX; michael@0: fY -= v.fY; michael@0: } michael@0: michael@0: // note: this can not be implemented with michael@0: // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX); michael@0: // because that will not take the magnitude of the values into account michael@0: bool approximatelyEqual(const SkDPoint& a) const { michael@0: if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) { michael@0: return true; michael@0: } michael@0: if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) { michael@0: return false; michael@0: } michael@0: double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ? michael@0: double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY); michael@0: double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY); michael@0: largest = SkTMax(largest, -tiniest); michael@0: return AlmostBequalUlps(largest, largest + dist); // is the dist within ULPS tolerance? michael@0: } michael@0: michael@0: bool approximatelyEqual(const SkPoint& a) const { michael@0: SkDPoint dA; michael@0: dA.set(a); michael@0: return approximatelyEqual(dA); michael@0: } michael@0: michael@0: static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) { michael@0: if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) { michael@0: return true; michael@0: } michael@0: if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) { michael@0: return false; michael@0: } michael@0: SkDPoint dA, dB; michael@0: dA.set(a); michael@0: dB.set(b); michael@0: double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ? michael@0: float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY); michael@0: float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY); michael@0: largest = SkTMax(largest, -tiniest); michael@0: return AlmostBequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance? michael@0: } michael@0: michael@0: bool approximatelyPEqual(const SkDPoint& a) const { michael@0: if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) { michael@0: return true; michael@0: } michael@0: if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) { michael@0: return false; michael@0: } michael@0: double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ? michael@0: double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY); michael@0: double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY); michael@0: largest = SkTMax(largest, -tiniest); michael@0: return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance? michael@0: } michael@0: michael@0: bool approximatelyZero() const { michael@0: return approximately_zero(fX) && approximately_zero(fY); michael@0: } michael@0: michael@0: SkPoint asSkPoint() const { michael@0: SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)}; michael@0: return pt; michael@0: } michael@0: michael@0: double distance(const SkDPoint& a) const { michael@0: SkDVector temp = *this - a; michael@0: return temp.length(); michael@0: } michael@0: michael@0: double distanceSquared(const SkDPoint& a) const { michael@0: SkDVector temp = *this - a; michael@0: return temp.lengthSquared(); michael@0: } michael@0: michael@0: static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) { michael@0: SkDPoint result; michael@0: result.fX = (a.fX + b.fX) / 2; michael@0: result.fY = (a.fY + b.fY) / 2; michael@0: return result; michael@0: } michael@0: michael@0: bool moreRoughlyEqual(const SkDPoint& a) const { michael@0: if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) { michael@0: return true; michael@0: } michael@0: double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ? michael@0: double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY); michael@0: double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY); michael@0: largest = SkTMax(largest, -tiniest); michael@0: return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance? michael@0: } michael@0: michael@0: bool roughlyEqual(const SkDPoint& a) const { michael@0: return roughly_equal(a.fY, fY) && roughly_equal(a.fX, fX); michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: void dump() { michael@0: SkDebugf("{"); michael@0: DebugDumpDouble(fX); michael@0: SkDebugf(", "); michael@0: DebugDumpDouble(fY); michael@0: SkDebugf("}"); michael@0: } michael@0: michael@0: static void dump(const SkPoint& pt) { michael@0: SkDebugf("{"); michael@0: DebugDumpFloat(pt.fX); michael@0: SkDebugf(", "); michael@0: DebugDumpFloat(pt.fY); michael@0: SkDebugf("}"); michael@0: } michael@0: #endif michael@0: }; michael@0: michael@0: #endif