Home | History | Annotate | Download | only in pathops
      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 SkPathOpsPoint_DEFINED
      8 #define SkPathOpsPoint_DEFINED
      9 
     10 #include "SkPathOpsTypes.h"
     11 #include "SkPoint.h"
     12 
     13 inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) {
     14     return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY);
     15 }
     16 
     17 struct SkDVector {
     18     double fX;
     19     double fY;
     20 
     21     void set(const SkVector& pt) {
     22         fX = pt.fX;
     23         fY = pt.fY;
     24     }
     25 
     26     // only used by testing
     27     void operator+=(const SkDVector& v) {
     28         fX += v.fX;
     29         fY += v.fY;
     30     }
     31 
     32     // only called by nearestT, which is currently only used by testing
     33     void operator-=(const SkDVector& v) {
     34         fX -= v.fX;
     35         fY -= v.fY;
     36     }
     37 
     38     // only used by testing
     39     void operator/=(const double s) {
     40         fX /= s;
     41         fY /= s;
     42     }
     43 
     44     // only used by testing
     45     void operator*=(const double s) {
     46         fX *= s;
     47         fY *= s;
     48     }
     49 
     50     SkVector asSkVector() const {
     51         SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
     52         return v;
     53     }
     54 
     55     // only used by testing
     56     double cross(const SkDVector& a) const {
     57         return fX * a.fY - fY * a.fX;
     58     }
     59 
     60     // similar to cross, this bastardization considers nearly coincident to be zero
     61     // uses ulps epsilon == 16
     62     double crossCheck(const SkDVector& a) const {
     63         double xy = fX * a.fY;
     64         double yx = fY * a.fX;
     65         return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
     66     }
     67 
     68     // allow tinier numbers
     69     double crossNoNormalCheck(const SkDVector& a) const {
     70         double xy = fX * a.fY;
     71         double yx = fY * a.fX;
     72         return AlmostEqualUlpsNoNormalCheck(xy, yx) ? 0 : xy - yx;
     73     }
     74 
     75     double dot(const SkDVector& a) const {
     76         return fX * a.fX + fY * a.fY;
     77     }
     78 
     79     double length() const {
     80         return sqrt(lengthSquared());
     81     }
     82 
     83     double lengthSquared() const {
     84         return fX * fX + fY * fY;
     85     }
     86 
     87     void normalize() {
     88         double inverseLength = 1 / this->length();
     89         fX *= inverseLength;
     90         fY *= inverseLength;
     91     }
     92 };
     93 
     94 struct SkDPoint {
     95     double fX;
     96     double fY;
     97 
     98     void set(const SkPoint& pt) {
     99         fX = pt.fX;
    100         fY = pt.fY;
    101     }
    102 
    103     friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
    104         return { a.fX - b.fX, a.fY - b.fY };
    105     }
    106 
    107     friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
    108         return a.fX == b.fX && a.fY == b.fY;
    109     }
    110 
    111     friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
    112         return a.fX != b.fX || a.fY != b.fY;
    113     }
    114 
    115     void operator=(const SkPoint& pt) {
    116         fX = pt.fX;
    117         fY = pt.fY;
    118     }
    119 
    120     // only used by testing
    121     void operator+=(const SkDVector& v) {
    122         fX += v.fX;
    123         fY += v.fY;
    124     }
    125 
    126     // only used by testing
    127     void operator-=(const SkDVector& v) {
    128         fX -= v.fX;
    129         fY -= v.fY;
    130     }
    131 
    132     // only used by testing
    133     SkDPoint operator+(const SkDVector& v) {
    134         SkDPoint result = *this;
    135         result += v;
    136         return result;
    137     }
    138 
    139     // only used by testing
    140     SkDPoint operator-(const SkDVector& v) {
    141         SkDPoint result = *this;
    142         result -= v;
    143         return result;
    144     }
    145 
    146     // note: this can not be implemented with
    147     // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
    148     // because that will not take the magnitude of the values into account
    149     bool approximatelyDEqual(const SkDPoint& a) const {
    150         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
    151             return true;
    152         }
    153         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
    154             return false;
    155         }
    156         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
    157         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
    158         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
    159         largest = SkTMax(largest, -tiniest);
    160         return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
    161     }
    162 
    163     bool approximatelyDEqual(const SkPoint& a) const {
    164         SkDPoint dA;
    165         dA.set(a);
    166         return approximatelyDEqual(dA);
    167     }
    168 
    169     bool approximatelyEqual(const SkDPoint& a) const {
    170         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
    171             return true;
    172         }
    173         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
    174             return false;
    175         }
    176         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
    177         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
    178         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
    179         largest = SkTMax(largest, -tiniest);
    180         return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
    181     }
    182 
    183     bool approximatelyEqual(const SkPoint& a) const {
    184         SkDPoint dA;
    185         dA.set(a);
    186         return approximatelyEqual(dA);
    187     }
    188 
    189     static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
    190         if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
    191             return true;
    192         }
    193         if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
    194             return false;
    195         }
    196         SkDPoint dA, dB;
    197         dA.set(a);
    198         dB.set(b);
    199         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
    200         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
    201         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
    202         largest = SkTMax(largest, -tiniest);
    203         return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
    204     }
    205 
    206     // only used by testing
    207     bool approximatelyZero() const {
    208         return approximately_zero(fX) && approximately_zero(fY);
    209     }
    210 
    211     SkPoint asSkPoint() const {
    212         SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
    213         return pt;
    214     }
    215 
    216     double distance(const SkDPoint& a) const {
    217         SkDVector temp = *this - a;
    218         return temp.length();
    219     }
    220 
    221     double distanceSquared(const SkDPoint& a) const {
    222         SkDVector temp = *this - a;
    223         return temp.lengthSquared();
    224     }
    225 
    226     static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
    227         SkDPoint result;
    228         result.fX = (a.fX + b.fX) / 2;
    229         result.fY = (a.fY + b.fY) / 2;
    230         return result;
    231     }
    232 
    233     bool roughlyEqual(const SkDPoint& a) const {
    234         if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
    235             return true;
    236         }
    237         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
    238         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
    239         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
    240         largest = SkTMax(largest, -tiniest);
    241         return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
    242     }
    243 
    244     static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
    245         if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
    246             return false;
    247         }
    248         SkDPoint dA, dB;
    249         dA.set(a);
    250         dB.set(b);
    251         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
    252         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
    253         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
    254         largest = SkTMax(largest, -tiniest);
    255         return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
    256     }
    257 
    258     // very light weight check, should only be used for inequality check
    259     static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) {
    260         float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY),
    261                 SkTMax(SkTAbs(b.fX), SkTAbs(b.fY))));
    262         SkVector diffs = a - b;
    263         float largestDiff = SkTMax(diffs.fX, diffs.fY);
    264         return roughly_zero_when_compared_to(largestDiff, largestNumber);
    265     }
    266 
    267     // utilities callable by the user from the debugger when the implementation code is linked in
    268     void dump() const;
    269     static void Dump(const SkPoint& pt);
    270     static void DumpHex(const SkPoint& pt);
    271 };
    272 
    273 #endif
    274