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