shape_diameter_function.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2017 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 "shape_diameter_function.h"
  9. #include "random_dir.h"
  10. #include "barycenter.h"
  11. #include "ray_mesh_intersect.h"
  12. #include "per_vertex_normals.h"
  13. #include "per_face_normals.h"
  14. #include "EPS.h"
  15. #include "Hit.h"
  16. #include "parallel_for.h"
  17. #include <functional>
  18. #include <vector>
  19. #include <algorithm>
  20. template <
  21. typename DerivedP,
  22. typename DerivedN,
  23. typename DerivedS >
  24. IGL_INLINE void igl::shape_diameter_function(
  25. const std::function<
  26. double(
  27. const Eigen::Vector3f&,
  28. const Eigen::Vector3f&)
  29. > & shoot_ray,
  30. const Eigen::PlainObjectBase<DerivedP> & P,
  31. const Eigen::PlainObjectBase<DerivedN> & N,
  32. const int num_samples,
  33. Eigen::PlainObjectBase<DerivedS> & S)
  34. {
  35. using namespace Eigen;
  36. const int n = P.rows();
  37. // Resize output
  38. S.resize(n,1);
  39. // Embree seems to be parallel when constructing but not when tracing rays
  40. const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
  41. const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
  42. {
  43. const Vector3f origin = P.row(p).template cast<float>();
  44. const Vector3f normal = N.row(p).template cast<float>();
  45. int num_hits = 0;
  46. double total_distance = 0;
  47. for(int s = 0;s<num_samples;s++)
  48. {
  49. Vector3f d = D.row(s);
  50. // Shoot _inward_
  51. if(d.dot(normal) > 0)
  52. {
  53. // reverse ray
  54. d *= -1;
  55. }
  56. const double dist = shoot_ray(origin,d);
  57. if(std::isfinite(dist))
  58. {
  59. total_distance += dist;
  60. num_hits++;
  61. }
  62. }
  63. S(p) = total_distance/(double)num_hits;
  64. };
  65. parallel_for(n,inner,1000);
  66. }
  67. template <
  68. typename DerivedV,
  69. int DIM,
  70. typename DerivedF,
  71. typename DerivedP,
  72. typename DerivedN,
  73. typename DerivedS >
  74. IGL_INLINE void igl::shape_diameter_function(
  75. const igl::AABB<DerivedV,DIM> & aabb,
  76. const Eigen::PlainObjectBase<DerivedV> & V,
  77. const Eigen::PlainObjectBase<DerivedF> & F,
  78. const Eigen::PlainObjectBase<DerivedP> & P,
  79. const Eigen::PlainObjectBase<DerivedN> & N,
  80. const int num_samples,
  81. Eigen::PlainObjectBase<DerivedS> & S)
  82. {
  83. const auto & shoot_ray = [&aabb,&V,&F](
  84. const Eigen::Vector3f& _s,
  85. const Eigen::Vector3f& dir)->double
  86. {
  87. Eigen::Vector3f s = _s+1e-4*dir;
  88. igl::Hit hit;
  89. if(aabb.intersect_ray(
  90. V,
  91. F,
  92. s .cast<typename DerivedV::Scalar>().eval(),
  93. dir.cast<typename DerivedV::Scalar>().eval(),
  94. hit))
  95. {
  96. return hit.t;
  97. }else
  98. {
  99. return std::numeric_limits<double>::infinity();
  100. }
  101. };
  102. return shape_diameter_function(shoot_ray,P,N,num_samples,S);
  103. }
  104. template <
  105. typename DerivedV,
  106. typename DerivedF,
  107. typename DerivedP,
  108. typename DerivedN,
  109. typename DerivedS >
  110. IGL_INLINE void igl::shape_diameter_function(
  111. const Eigen::PlainObjectBase<DerivedV> & V,
  112. const Eigen::PlainObjectBase<DerivedF> & F,
  113. const Eigen::PlainObjectBase<DerivedP> & P,
  114. const Eigen::PlainObjectBase<DerivedN> & N,
  115. const int num_samples,
  116. Eigen::PlainObjectBase<DerivedS> & S)
  117. {
  118. if(F.rows() < 100)
  119. {
  120. // Super naive
  121. const auto & shoot_ray = [&V,&F](
  122. const Eigen::Vector3f& _s,
  123. const Eigen::Vector3f& dir)->double
  124. {
  125. Eigen::Vector3f s = _s+1e-4*dir;
  126. igl::Hit hit;
  127. if(ray_mesh_intersect(s,dir,V,F,hit))
  128. {
  129. return hit.t;
  130. }else
  131. {
  132. return std::numeric_limits<double>::infinity();
  133. }
  134. };
  135. return shape_diameter_function(shoot_ray,P,N,num_samples,S);
  136. }
  137. AABB<DerivedV,3> aabb;
  138. aabb.init(V,F);
  139. return shape_diameter_function(aabb,V,F,P,N,num_samples,S);
  140. }
  141. template <
  142. typename DerivedV,
  143. typename DerivedF,
  144. typename DerivedS>
  145. IGL_INLINE void igl::shape_diameter_function(
  146. const Eigen::PlainObjectBase<DerivedV> & V,
  147. const Eigen::PlainObjectBase<DerivedF> & F,
  148. const bool per_face,
  149. const int num_samples,
  150. Eigen::PlainObjectBase<DerivedS> & S)
  151. {
  152. if (per_face)
  153. {
  154. DerivedV N;
  155. igl::per_face_normals(V, F, N);
  156. DerivedV P;
  157. igl::barycenter(V, F, P);
  158. return igl::shape_diameter_function(V, F, P, N, num_samples, S);
  159. }
  160. else
  161. {
  162. DerivedV N;
  163. igl::per_vertex_normals(V, F, N);
  164. return igl::shape_diameter_function(V, F, V, N, num_samples, S);
  165. }
  166. }
  167. #ifdef IGL_STATIC_LIBRARY
  168. // Explicit template instantiation
  169. template void igl::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  170. template void igl::shape_diameter_function<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  171. template void igl::shape_diameter_function<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  172. template void igl::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  173. template void igl::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  174. #endif