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