ray_box_intersect.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 Alec Jacobson <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "ray_box_intersect.h"
  9. #include <array>
  10. #include <igl/matlab_format.h>
  11. template <
  12. typename Derivedsource,
  13. typename Deriveddir,
  14. typename Scalar>
  15. IGL_INLINE bool igl::ray_box_intersect(
  16. const Eigen::MatrixBase<Derivedsource> & origin,
  17. const Eigen::MatrixBase<Deriveddir> & dir,
  18. const Eigen::AlignedBox<Scalar,3> & box,
  19. const Scalar & t0,
  20. const Scalar & t1,
  21. Scalar & tmin,
  22. Scalar & tmax)
  23. {
  24. #ifdef false
  25. // https://github.com/RMonica/basic_next_best_view/blob/master/src/RayTracer.cpp
  26. const auto & intersectRayBox = [](
  27. const Eigen::Vector3f& rayo,
  28. const Eigen::Vector3f& rayd,
  29. const Eigen::Vector3f& bmin,
  30. const Eigen::Vector3f& bmax,
  31. float & tnear,
  32. float & tfar
  33. )->bool
  34. {
  35. Eigen::Vector3f bnear;
  36. Eigen::Vector3f bfar;
  37. // Checks for intersection testing on each direction coordinate
  38. // Computes
  39. float t1, t2;
  40. tnear = -1e+6f, tfar = 1e+6f; //, tCube;
  41. bool intersectFlag = true;
  42. for (int i = 0; i < 3; ++i) {
  43. // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl;
  44. assert(bmin(i) <= bmax(i));
  45. if (::fabs(rayd(i)) < 1e-6) { // Ray parallel to axis i-th
  46. if (rayo(i) < bmin(i) || rayo(i) > bmax(i)) {
  47. intersectFlag = false;
  48. }
  49. }
  50. else {
  51. // Finds the nearest and the farthest vertices of the box from the ray origin
  52. if (::fabs(bmin(i) - rayo(i)) < ::fabs(bmax(i) - rayo(i))) {
  53. bnear(i) = bmin(i);
  54. bfar(i) = bmax(i);
  55. }
  56. else {
  57. bnear(i) = bmax(i);
  58. bfar(i) = bmin(i);
  59. }
  60. // std::cout << " bnear " << bnear(i) << ", bfar " << bfar(i) << std::endl;
  61. // Finds the distance parameters t1 and t2 of the two ray-box intersections:
  62. // t1 must be the closest to the ray origin rayo.
  63. t1 = (bnear(i) - rayo(i)) / rayd(i);
  64. t2 = (bfar(i) - rayo(i)) / rayd(i);
  65. if (t1 > t2) {
  66. std::swap(t1,t2);
  67. }
  68. // The two intersection values are used to saturate tnear and tfar
  69. if (t1 > tnear) {
  70. tnear = t1;
  71. }
  72. if (t2 < tfar) {
  73. tfar = t2;
  74. }
  75. // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar
  76. // << " tnear > tfar? " << (tnear > tfar) << ", tfar < 0? " << (tfar < 0) << std::endl;
  77. if(tnear > tfar) {
  78. intersectFlag = false;
  79. }
  80. if(tfar < 0) {
  81. intersectFlag = false;
  82. }
  83. }
  84. }
  85. // Checks whether intersection occurs or not
  86. return intersectFlag;
  87. };
  88. float tmin_f, tmax_f;
  89. bool ret = intersectRayBox(
  90. origin. template cast<float>(),
  91. dir. template cast<float>(),
  92. box.min().template cast<float>(),
  93. box.max().template cast<float>(),
  94. tmin_f,
  95. tmax_f);
  96. tmin = tmin_f;
  97. tmax = tmax_f;
  98. return ret;
  99. #else
  100. using namespace Eigen;
  101. // This should be precomputed and provided as input
  102. typedef Matrix<Scalar,1,3> RowVector3S;
  103. const RowVector3S inv_dir( 1./dir(0),1./dir(1),1./dir(2));
  104. const std::array<bool, 3> sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0};
  105. // http://people.csail.mit.edu/amy/papers/box-jgt.pdf
  106. // "An Efficient and Robust Ray–Box Intersection Algorithm"
  107. Scalar tymin, tymax, tzmin, tzmax;
  108. std::array<RowVector3S, 2> bounds = {box.min().array(),box.max().array()};
  109. tmin = ( bounds[sign[0]](0) - origin(0)) * inv_dir(0);
  110. tmax = ( bounds[1-sign[0]](0) - origin(0)) * inv_dir(0);
  111. tymin = (bounds[sign[1]](1) - origin(1)) * inv_dir(1);
  112. tymax = (bounds[1-sign[1]](1) - origin(1)) * inv_dir(1);
  113. // NaN-safe min and max
  114. const auto berger_perrin_min = [&](
  115. const Scalar a,
  116. const Scalar b) -> Scalar
  117. {
  118. return (a < b) ? a : b;
  119. };
  120. const auto berger_perrin_max = [&](
  121. const Scalar a,
  122. const Scalar b) -> Scalar
  123. {
  124. return (a > b) ? a : b;
  125. };
  126. if ( (tmin > tymax) || (tymin > tmax) )
  127. {
  128. return false;
  129. }
  130. tmin = berger_perrin_max(tmin,tymin);
  131. tmax = berger_perrin_min(tmax,tymax);
  132. tzmin = (bounds[sign[2]](2) - origin(2)) * inv_dir(2);
  133. tzmax = (bounds[1-sign[2]](2) - origin(2)) * inv_dir(2);
  134. if ( (tmin > tzmax) || (tzmin > tmax) )
  135. {
  136. return false;
  137. }
  138. tmin = berger_perrin_max(tmin,tzmin);
  139. tmax = berger_perrin_min(tmax,tzmax);
  140. if(!( (tmin < t1) && (tmax > t0) ))
  141. {
  142. return false;
  143. }
  144. return true;
  145. #endif
  146. }
  147. #ifdef IGL_STATIC_LIBRARY
  148. // Explicit template instantiation
  149. // generated by autoexplicit.sh
  150. template bool igl::ray_box_intersect<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, float>(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<float, 3> const&, float const&, float const&, float&, float&);
  151. template bool igl::ray_box_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<double, 3> const&, double const&, double const&, double&, double&);
  152. #endif