ray_box_intersect.cpp 4.8 KB

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