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     friend SkDPoint operator+(const SkDPoint& a, const SkDVector& b);
     27 
     28     void operator+=(const SkDVector& v) {
     29         fX += v.fX;
     30         fY += v.fY;
     31     }
     32 
     33     void operator-=(const SkDVector& v) {
     34         fX -= v.fX;
     35         fY -= v.fY;
     36     }
     37 
     38     void operator/=(const double s) {
     39         fX /= s;
     40         fY /= s;
     41     }
     42 
     43     void operator*=(const double s) {
     44         fX *= s;
     45         fY *= s;
     46     }
     47 
     48     SkVector asSkVector() const {
     49         SkVector v = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
     50         return v;
     51     }
     52 
     53     double cross(const SkDVector& a) const {
     54         return fX * a.fY - fY * a.fX;
     55     }
     56 
     57     // similar to cross, this bastardization considers nearly coincident to be zero
     58     double crossCheck(const SkDVector& a) const {
     59         double xy = fX * a.fY;
     60         double yx = fY * a.fX;
     61         return AlmostEqualUlps(xy, yx) ? 0 : xy - yx;
     62     }
     63 
     64     double dot(const SkDVector& a) const {
     65         return fX * a.fX + fY * a.fY;
     66     }
     67 
     68     double length() const {
     69         return sqrt(lengthSquared());
     70     }
     71 
     72     double lengthSquared() const {
     73         return fX * fX + fY * fY;
     74     }
     75 };
     76 
     77 struct SkDPoint {
     78     double fX;
     79     double fY;
     80 
     81     void set(const SkPoint& pt) {
     82         fX = pt.fX;
     83         fY = pt.fY;
     84     }
     85 
     86     friend SkDVector operator-(const SkDPoint& a, const SkDPoint& b);
     87 
     88     friend bool operator==(const SkDPoint& a, const SkDPoint& b) {
     89         return a.fX == b.fX && a.fY == b.fY;
     90     }
     91 
     92     friend bool operator!=(const SkDPoint& a, const SkDPoint& b) {
     93         return a.fX != b.fX || a.fY != b.fY;
     94     }
     95 
     96     void operator=(const SkPoint& pt) {
     97         fX = pt.fX;
     98         fY = pt.fY;
     99     }
    100 
    101     void operator+=(const SkDVector& v) {
    102         fX += v.fX;
    103         fY += v.fY;
    104     }
    105 
    106     void operator-=(const SkDVector& v) {
    107         fX -= v.fX;
    108         fY -= v.fY;
    109     }
    110 
    111     // note: this can not be implemented with
    112     // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
    113     // because that will not take the magnitude of the values into account
    114     bool approximatelyEqual(const SkDPoint& a) const {
    115         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
    116             return true;
    117         }
    118         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
    119             return false;
    120         }
    121         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
    122         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
    123         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
    124         largest = SkTMax(largest, -tiniest);
    125         return AlmostBequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
    126     }
    127 
    128     bool approximatelyEqual(const SkPoint& a) const {
    129         SkDPoint dA;
    130         dA.set(a);
    131         return approximatelyEqual(dA);
    132     }
    133 
    134     static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) {
    135         if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
    136             return true;
    137         }
    138         if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
    139             return false;
    140         }
    141         SkDPoint dA, dB;
    142         dA.set(a);
    143         dB.set(b);
    144         double dist = dA.distance(dB);  // OPTIMIZATION: can we compare against distSq instead ?
    145         float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY);
    146         float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY);
    147         largest = SkTMax(largest, -tiniest);
    148         return AlmostBequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance?
    149     }
    150 
    151     static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
    152         if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) {
    153             return true;
    154         }
    155         return RoughlyEqualUlps(a.fX, b.fX) && RoughlyEqualUlps(a.fY, b.fY);
    156     }
    157 
    158     bool approximatelyPEqual(const SkDPoint& a) const {
    159         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
    160             return true;
    161         }
    162         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
    163             return false;
    164         }
    165         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
    166         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
    167         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
    168         largest = SkTMax(largest, -tiniest);
    169         return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
    170     }
    171 
    172     bool approximatelyDEqual(const SkDPoint& a) const {
    173         if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) {
    174             return true;
    175         }
    176         if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) {
    177             return false;
    178         }
    179         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
    180         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
    181         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
    182         largest = SkTMax(largest, -tiniest);
    183         return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance?
    184     }
    185 
    186     bool approximatelyZero() const {
    187         return approximately_zero(fX) && approximately_zero(fY);
    188     }
    189 
    190     SkPoint asSkPoint() const {
    191         SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)};
    192         return pt;
    193     }
    194 
    195     double distance(const SkDPoint& a) const {
    196         SkDVector temp = *this - a;
    197         return temp.length();
    198     }
    199 
    200     double distanceSquared(const SkDPoint& a) const {
    201         SkDVector temp = *this - a;
    202         return temp.lengthSquared();
    203     }
    204 
    205     static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) {
    206         SkDPoint result;
    207         result.fX = (a.fX + b.fX) / 2;
    208         result.fY = (a.fY + b.fY) / 2;
    209         return result;
    210     }
    211 
    212     bool moreRoughlyEqual(const SkDPoint& a) const {
    213         if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) {
    214             return true;
    215         }
    216         double dist = distance(a);  // OPTIMIZATION: can we compare against distSq instead ?
    217         double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY);
    218         double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY);
    219         largest = SkTMax(largest, -tiniest);
    220         return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
    221     }
    222 
    223     bool roughlyEqual(const SkDPoint& a) const {
    224         return roughly_equal(a.fY, fY) && roughly_equal(a.fX, fX);
    225     }
    226 
    227     // utilities callable by the user from the debugger when the implementation code is linked in
    228     void dump() const;
    229     static void Dump(const SkPoint& pt);
    230 };
    231 
    232 #endif
    233