ImathLineAlgo.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Copyright Contributors to the OpenEXR Project.
  4. //
  5. //
  6. // Algorithms applied to or in conjunction with Imath::Line class
  7. //
  8. #ifndef INCLUDED_IMATHLINEALGO_H
  9. #define INCLUDED_IMATHLINEALGO_H
  10. #include "ImathFun.h"
  11. #include "ImathLine.h"
  12. #include "ImathNamespace.h"
  13. #include "ImathVecAlgo.h"
  14. IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
  15. ///
  16. /// Compute point1 and point2 such that point1 is on line1, point2
  17. /// is on line2 and the distance between point1 and point2 is minimal.
  18. ///
  19. /// This function returns true if point1 and point2 can be computed,
  20. /// or false if line1 and line2 are parallel or nearly parallel.
  21. /// This function assumes that line1.dir and line2.dir are normalized.
  22. ///
  23. template <class T>
  24. IMATH_CONSTEXPR14 bool
  25. closestPoints (const Line3<T>& line1, const Line3<T>& line2, Vec3<T>& point1, Vec3<T>& point2) IMATH_NOEXCEPT
  26. {
  27. Vec3<T> w = line1.pos - line2.pos;
  28. T d1w = line1.dir ^ w;
  29. T d2w = line2.dir ^ w;
  30. T d1d2 = line1.dir ^ line2.dir;
  31. T n1 = d1d2 * d2w - d1w;
  32. T n2 = d2w - d1d2 * d1w;
  33. T d = 1 - d1d2 * d1d2;
  34. T absD = abs (d);
  35. if ((absD > 1) || (abs (n1) < std::numeric_limits<T>::max() * absD && abs (n2) < std::numeric_limits<T>::max() * absD))
  36. {
  37. point1 = line1 (n1 / d);
  38. point2 = line2 (n2 / d);
  39. return true;
  40. }
  41. else
  42. {
  43. return false;
  44. }
  45. }
  46. ///
  47. /// Given a line and a triangle (v0, v1, v2), the intersect() function
  48. /// finds the intersection of the line and the plane that contains the
  49. /// triangle.
  50. ///
  51. /// If the intersection point cannot be computed, either because the
  52. /// line and the triangle's plane are nearly parallel or because the
  53. /// triangle's area is very small, intersect() returns false.
  54. ///
  55. /// If the intersection point is outside the triangle, intersect
  56. /// returns false.
  57. ///
  58. /// If the intersection point, pt, is inside the triangle, intersect()
  59. /// computes a front-facing flag and the barycentric coordinates of
  60. /// the intersection point, and returns true.
  61. ///
  62. /// The front-facing flag is true if the dot product of the triangle's
  63. /// normal, (v2-v1)%(v1-v0), and the line's direction is negative.
  64. ///
  65. /// The barycentric coordinates have the following property:
  66. ///
  67. /// pt = v0 * barycentric.x + v1 * barycentric.y + v2 * barycentric.z
  68. ///
  69. template <class T>
  70. IMATH_CONSTEXPR14 bool
  71. intersect (const Line3<T>& line,
  72. const Vec3<T>& v0,
  73. const Vec3<T>& v1,
  74. const Vec3<T>& v2,
  75. Vec3<T>& pt,
  76. Vec3<T>& barycentric,
  77. bool& front) IMATH_NOEXCEPT
  78. {
  79. Vec3<T> edge0 = v1 - v0;
  80. Vec3<T> edge1 = v2 - v1;
  81. Vec3<T> normal = edge1 % edge0;
  82. T l = normal.length();
  83. if (l != 0)
  84. normal /= l;
  85. else
  86. return false; // zero-area triangle
  87. //
  88. // d is the distance of line.pos from the plane that contains the triangle.
  89. // The intersection point is at line.pos + (d/nd) * line.dir.
  90. //
  91. T d = normal ^ (v0 - line.pos);
  92. T nd = normal ^ line.dir;
  93. if (abs (nd) > 1 || abs (d) < std::numeric_limits<T>::max() * abs (nd))
  94. pt = line (d / nd);
  95. else
  96. return false; // line and plane are nearly parallel
  97. //
  98. // Compute the barycentric coordinates of the intersection point.
  99. // The intersection is inside the triangle if all three barycentric
  100. // coordinates are between zero and one.
  101. //
  102. {
  103. Vec3<T> en = edge0.normalized();
  104. Vec3<T> a = pt - v0;
  105. Vec3<T> b = v2 - v0;
  106. Vec3<T> c = (a - en * (en ^ a));
  107. Vec3<T> d = (b - en * (en ^ b));
  108. T e = c ^ d;
  109. T f = d ^ d;
  110. if (e >= 0 && e <= f)
  111. barycentric.z = e / f;
  112. else
  113. return false; // outside
  114. }
  115. {
  116. Vec3<T> en = edge1.normalized();
  117. Vec3<T> a = pt - v1;
  118. Vec3<T> b = v0 - v1;
  119. Vec3<T> c = (a - en * (en ^ a));
  120. Vec3<T> d = (b - en * (en ^ b));
  121. T e = c ^ d;
  122. T f = d ^ d;
  123. if (e >= 0 && e <= f)
  124. barycentric.x = e / f;
  125. else
  126. return false; // outside
  127. }
  128. barycentric.y = 1 - barycentric.x - barycentric.z;
  129. if (barycentric.y < 0)
  130. return false; // outside
  131. front = ((line.dir ^ normal) < 0);
  132. return true;
  133. }
  134. ///
  135. /// Return the vertex that is closest to the given line. The returned
  136. /// point is either v0, v1, or v2.
  137. ///
  138. template <class T>
  139. IMATH_CONSTEXPR14 Vec3<T>
  140. closestVertex (const Vec3<T>& v0, const Vec3<T>& v1, const Vec3<T>& v2, const Line3<T>& l) IMATH_NOEXCEPT
  141. {
  142. Vec3<T> nearest = v0;
  143. T neardot = (v0 - l.closestPointTo (v0)).length2();
  144. T tmp = (v1 - l.closestPointTo (v1)).length2();
  145. if (tmp < neardot)
  146. {
  147. neardot = tmp;
  148. nearest = v1;
  149. }
  150. tmp = (v2 - l.closestPointTo (v2)).length2();
  151. if (tmp < neardot)
  152. {
  153. neardot = tmp;
  154. nearest = v2;
  155. }
  156. return nearest;
  157. }
  158. ///
  159. /// Rotate the point p around the line l by the given angle.
  160. ///
  161. template <class T>
  162. IMATH_CONSTEXPR14 Vec3<T>
  163. rotatePoint (const Vec3<T> p, Line3<T> l, T angle) IMATH_NOEXCEPT
  164. {
  165. //
  166. // Form a coordinate frame with <x,y,a>. The rotation is the in xy
  167. // plane.
  168. //
  169. Vec3<T> q = l.closestPointTo (p);
  170. Vec3<T> x = p - q;
  171. T radius = x.length();
  172. x.normalize();
  173. Vec3<T> y = (x % l.dir).normalize();
  174. T cosangle = std::cos (angle);
  175. T sinangle = std::sin (angle);
  176. Vec3<T> r = q + x * radius * cosangle + y * radius * sinangle;
  177. return r;
  178. }
  179. IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
  180. #endif // INCLUDED_IMATHLINEALGO_H