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 13inline bool AlmostEqualUlps(const SkPoint& pt1, const SkPoint& pt2) { 14 return AlmostEqualUlps(pt1.fX, pt2.fX) && AlmostEqualUlps(pt1.fY, pt2.fY); 15} 16 17struct 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 94struct 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 105 friend bool operator==(const SkDPoint& a, const SkDPoint& b) { 106 return a.fX == b.fX && a.fY == b.fY; 107 } 108 109 friend bool operator!=(const SkDPoint& a, const SkDPoint& b) { 110 return a.fX != b.fX || a.fY != b.fY; 111 } 112 113 void operator=(const SkPoint& pt) { 114 fX = pt.fX; 115 fY = pt.fY; 116 } 117 118 // only used by testing 119 void operator+=(const SkDVector& v) { 120 fX += v.fX; 121 fY += v.fY; 122 } 123 124 // only used by testing 125 void operator-=(const SkDVector& v) { 126 fX -= v.fX; 127 fY -= v.fY; 128 } 129 130 // only used by testing 131 SkDPoint operator+(const SkDVector& v) { 132 SkDPoint result = *this; 133 result += v; 134 return result; 135 } 136 137 // only used by testing 138 SkDPoint operator-(const SkDVector& v) { 139 SkDPoint result = *this; 140 result -= v; 141 return result; 142 } 143 144 // note: this can not be implemented with 145 // return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX); 146 // because that will not take the magnitude of the values into account 147 bool approximatelyDEqual(const SkDPoint& a) const { 148 if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) { 149 return true; 150 } 151 if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) { 152 return false; 153 } 154 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ? 155 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY); 156 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY); 157 largest = SkTMax(largest, -tiniest); 158 return AlmostDequalUlps(largest, largest + dist); // is the dist within ULPS tolerance? 159 } 160 161 bool approximatelyDEqual(const SkPoint& a) const { 162 SkDPoint dA; 163 dA.set(a); 164 return approximatelyDEqual(dA); 165 } 166 167 bool approximatelyEqual(const SkDPoint& a) const { 168 if (approximately_equal(fX, a.fX) && approximately_equal(fY, a.fY)) { 169 return true; 170 } 171 if (!RoughlyEqualUlps(fX, a.fX) || !RoughlyEqualUlps(fY, a.fY)) { 172 return false; 173 } 174 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ? 175 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY); 176 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY); 177 largest = SkTMax(largest, -tiniest); 178 return AlmostPequalUlps(largest, largest + dist); // is the dist within ULPS tolerance? 179 } 180 181 bool approximatelyEqual(const SkPoint& a) const { 182 SkDPoint dA; 183 dA.set(a); 184 return approximatelyEqual(dA); 185 } 186 187 static bool ApproximatelyEqual(const SkPoint& a, const SkPoint& b) { 188 if (approximately_equal(a.fX, b.fX) && approximately_equal(a.fY, b.fY)) { 189 return true; 190 } 191 if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) { 192 return false; 193 } 194 SkDPoint dA, dB; 195 dA.set(a); 196 dB.set(b); 197 double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ? 198 float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY); 199 float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY); 200 largest = SkTMax(largest, -tiniest); 201 return AlmostDequalUlps((double) largest, largest + dist); // is dist within ULPS tolerance? 202 } 203 204 // only used by testing 205 bool approximatelyZero() const { 206 return approximately_zero(fX) && approximately_zero(fY); 207 } 208 209 SkPoint asSkPoint() const { 210 SkPoint pt = {SkDoubleToScalar(fX), SkDoubleToScalar(fY)}; 211 return pt; 212 } 213 214 double distance(const SkDPoint& a) const { 215 SkDVector temp = *this - a; 216 return temp.length(); 217 } 218 219 double distanceSquared(const SkDPoint& a) const { 220 SkDVector temp = *this - a; 221 return temp.lengthSquared(); 222 } 223 224 static SkDPoint Mid(const SkDPoint& a, const SkDPoint& b) { 225 SkDPoint result; 226 result.fX = (a.fX + b.fX) / 2; 227 result.fY = (a.fY + b.fY) / 2; 228 return result; 229 } 230 231 bool roughlyEqual(const SkDPoint& a) const { 232 if (roughly_equal(fX, a.fX) && roughly_equal(fY, a.fY)) { 233 return true; 234 } 235 double dist = distance(a); // OPTIMIZATION: can we compare against distSq instead ? 236 double tiniest = SkTMin(SkTMin(SkTMin(fX, a.fX), fY), a.fY); 237 double largest = SkTMax(SkTMax(SkTMax(fX, a.fX), fY), a.fY); 238 largest = SkTMax(largest, -tiniest); 239 return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance? 240 } 241 242 static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) { 243 if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) { 244 return false; 245 } 246 SkDPoint dA, dB; 247 dA.set(a); 248 dB.set(b); 249 double dist = dA.distance(dB); // OPTIMIZATION: can we compare against distSq instead ? 250 float tiniest = SkTMin(SkTMin(SkTMin(a.fX, b.fX), a.fY), b.fY); 251 float largest = SkTMax(SkTMax(SkTMax(a.fX, b.fX), a.fY), b.fY); 252 largest = SkTMax(largest, -tiniest); 253 return RoughlyEqualUlps((double) largest, largest + dist); // is dist within ULPS tolerance? 254 } 255 256 // very light weight check, should only be used for inequality check 257 static bool WayRoughlyEqual(const SkPoint& a, const SkPoint& b) { 258 float largestNumber = SkTMax(SkTAbs(a.fX), SkTMax(SkTAbs(a.fY), 259 SkTMax(SkTAbs(b.fX), SkTAbs(b.fY)))); 260 SkVector diffs = a - b; 261 float largestDiff = SkTMax(diffs.fX, diffs.fY); 262 return roughly_zero_when_compared_to(largestDiff, largestNumber); 263 } 264 265 // utilities callable by the user from the debugger when the implementation code is linked in 266 void dump() const; 267 static void Dump(const SkPoint& pt); 268 static void DumpHex(const SkPoint& pt); 269}; 270 271#endif 272