SkPoint.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright 2008 The Android Open Source Project
  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. #include "src/core/SkMathPriv.h"
  8. #include "src/core/SkPointPriv.h"
  9. ///////////////////////////////////////////////////////////////////////////////
  10. void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
  11. SkASSERT(dst);
  12. dst->set(fX * scale, fY * scale);
  13. }
  14. bool SkPoint::normalize() {
  15. return this->setLength(fX, fY, SK_Scalar1);
  16. }
  17. bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
  18. return this->setLength(x, y, SK_Scalar1);
  19. }
  20. bool SkPoint::setLength(SkScalar length) {
  21. return this->setLength(fX, fY, length);
  22. }
  23. /*
  24. * We have to worry about 2 tricky conditions:
  25. * 1. underflow of mag2 (compared against nearlyzero^2)
  26. * 2. overflow of mag2 (compared w/ isfinite)
  27. *
  28. * If we underflow, we return false. If we overflow, we compute again using
  29. * doubles, which is much slower (3x in a desktop test) but will not overflow.
  30. */
  31. template <bool use_rsqrt> bool set_point_length(SkPoint* pt, float x, float y, float length,
  32. float* orig_length = nullptr) {
  33. SkASSERT(!use_rsqrt || (orig_length == nullptr));
  34. // our mag2 step overflowed to infinity, so use doubles instead.
  35. // much slower, but needed when x or y are very large, other wise we
  36. // divide by inf. and return (0,0) vector.
  37. double xx = x;
  38. double yy = y;
  39. double dmag = sqrt(xx * xx + yy * yy);
  40. double dscale = sk_ieee_double_divide(length, dmag);
  41. x *= dscale;
  42. y *= dscale;
  43. // check if we're not finite, or we're zero-length
  44. if (!sk_float_isfinite(x) || !sk_float_isfinite(y) || (x == 0 && y == 0)) {
  45. pt->set(0, 0);
  46. return false;
  47. }
  48. float mag = 0;
  49. if (orig_length) {
  50. mag = sk_double_to_float(dmag);
  51. }
  52. pt->set(x, y);
  53. if (orig_length) {
  54. *orig_length = mag;
  55. }
  56. return true;
  57. }
  58. SkScalar SkPoint::Normalize(SkPoint* pt) {
  59. float mag;
  60. if (set_point_length<false>(pt, pt->fX, pt->fY, 1.0f, &mag)) {
  61. return mag;
  62. }
  63. return 0;
  64. }
  65. SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
  66. float mag2 = dx * dx + dy * dy;
  67. if (SkScalarIsFinite(mag2)) {
  68. return sk_float_sqrt(mag2);
  69. } else {
  70. double xx = dx;
  71. double yy = dy;
  72. return sk_double_to_float(sqrt(xx * xx + yy * yy));
  73. }
  74. }
  75. bool SkPoint::setLength(float x, float y, float length) {
  76. return set_point_length<false>(this, x, y, length);
  77. }
  78. bool SkPointPriv::SetLengthFast(SkPoint* pt, float length) {
  79. return set_point_length<true>(pt, pt->fX, pt->fY, length);
  80. }
  81. ///////////////////////////////////////////////////////////////////////////////
  82. SkScalar SkPointPriv::DistanceToLineBetweenSqd(const SkPoint& pt, const SkPoint& a,
  83. const SkPoint& b,
  84. Side* side) {
  85. SkVector u = b - a;
  86. SkVector v = pt - a;
  87. SkScalar uLengthSqd = LengthSqd(u);
  88. SkScalar det = u.cross(v);
  89. if (side) {
  90. SkASSERT(-1 == kLeft_Side &&
  91. 0 == kOn_Side &&
  92. 1 == kRight_Side);
  93. *side = (Side) SkScalarSignAsInt(det);
  94. }
  95. SkScalar temp = sk_ieee_float_divide(det, uLengthSqd);
  96. temp *= det;
  97. // It's possible we have a degenerate line vector, or we're so far away it looks degenerate
  98. // In this case, return squared distance to point A.
  99. if (!SkScalarIsFinite(temp)) {
  100. return LengthSqd(v);
  101. }
  102. return temp;
  103. }
  104. SkScalar SkPointPriv::DistanceToLineSegmentBetweenSqd(const SkPoint& pt, const SkPoint& a,
  105. const SkPoint& b) {
  106. // See comments to distanceToLineBetweenSqd. If the projection of c onto
  107. // u is between a and b then this returns the same result as that
  108. // function. Otherwise, it returns the distance to the closer of a and
  109. // b. Let the projection of v onto u be v'. There are three cases:
  110. // 1. v' points opposite to u. c is not between a and b and is closer
  111. // to a than b.
  112. // 2. v' points along u and has magnitude less than y. c is between
  113. // a and b and the distance to the segment is the same as distance
  114. // to the line ab.
  115. // 3. v' points along u and has greater magnitude than u. c is not
  116. // not between a and b and is closer to b than a.
  117. // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
  118. // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
  119. // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
  120. // avoid a sqrt to compute |u|.
  121. SkVector u = b - a;
  122. SkVector v = pt - a;
  123. SkScalar uLengthSqd = LengthSqd(u);
  124. SkScalar uDotV = SkPoint::DotProduct(u, v);
  125. // closest point is point A
  126. if (uDotV <= 0) {
  127. return LengthSqd(v);
  128. // closest point is point B
  129. } else if (uDotV > uLengthSqd) {
  130. return DistanceToSqd(b, pt);
  131. // closest point is inside segment
  132. } else {
  133. SkScalar det = u.cross(v);
  134. SkScalar temp = sk_ieee_float_divide(det, uLengthSqd);
  135. temp *= det;
  136. // It's possible we have a degenerate segment, or we're so far away it looks degenerate
  137. // In this case, return squared distance to point A.
  138. if (!SkScalarIsFinite(temp)) {
  139. return LengthSqd(v);
  140. }
  141. return temp;
  142. }
  143. }