SkPathOpsPoint.h 8.4 KB

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