reorient_facets_raycast.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 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 "reorient_facets_raycast.h"
  9. #include "../per_face_normals.h"
  10. #include "../doublearea.h"
  11. #include "../random_dir.h"
  12. #include "../bfs_orient.h"
  13. #include "../PlainMatrix.h"
  14. #include "EmbreeIntersector.h"
  15. #include <iostream>
  16. #include <random>
  17. #include <ctime>
  18. #include <limits>
  19. template <
  20. typename DerivedV,
  21. typename DerivedF,
  22. typename DerivedI,
  23. typename DerivedC>
  24. IGL_INLINE void igl::embree::reorient_facets_raycast(
  25. const Eigen::MatrixBase<DerivedV> & V,
  26. const Eigen::MatrixBase<DerivedF> & F,
  27. int rays_total,
  28. int rays_minimum,
  29. bool facet_wise,
  30. bool use_parity,
  31. bool is_verbose,
  32. Eigen::PlainObjectBase<DerivedI> & I,
  33. Eigen::PlainObjectBase<DerivedC> & C)
  34. {
  35. assert(F.cols() == 3);
  36. assert(V.cols() == 3);
  37. // number of faces
  38. const int m = F.rows();
  39. Eigen::MatrixXi Fi = F.template cast<int>();
  40. Eigen::MatrixXi FF;
  41. if (facet_wise) {
  42. FF = Fi;
  43. C.resize(m);
  44. for (int i = 0; i < m; ++i) C(i) = i;
  45. } else {
  46. if (is_verbose) std::cout << "extracting patches... ";
  47. bfs_orient(Fi,FF,C);
  48. }
  49. if (is_verbose) std::cout << (C.maxCoeff() + 1) << " components. ";
  50. // number of patches
  51. const int num_cc = C.maxCoeff()+1;
  52. // Init Embree
  53. EmbreeIntersector ei;
  54. ei.init(V.template cast<float>(),FF);
  55. // face normal
  56. Eigen::MatrixXd N;
  57. per_face_normals(V,FF,N);
  58. // face area
  59. Eigen::Matrix<typename DerivedV::Scalar ,Eigen::Dynamic,1> A;
  60. doublearea(V,FF,A);
  61. double area_total = A.sum();
  62. // determine number of rays per component according to its area
  63. Eigen::VectorXd area_per_component;
  64. area_per_component.setZero(num_cc);
  65. for (int f = 0; f < m; ++f)
  66. {
  67. area_per_component(C(f)) += A(f);
  68. }
  69. Eigen::VectorXi num_rays_per_component(num_cc);
  70. for (int c = 0; c < num_cc; ++c)
  71. {
  72. num_rays_per_component(c) = std::max<int>(static_cast<int>(rays_total * area_per_component(c) / area_total), rays_minimum);
  73. }
  74. rays_total = num_rays_per_component.sum();
  75. // generate all the rays
  76. if (is_verbose) std::cout << "generating rays... ";
  77. std::uniform_real_distribution<float> rdist;
  78. std::mt19937 prng;
  79. prng.seed(time(nullptr));
  80. std::vector<int > ray_face;
  81. std::vector<Eigen::Vector3f> ray_ori;
  82. std::vector<Eigen::Vector3f> ray_dir;
  83. ray_face.reserve(rays_total);
  84. ray_ori .reserve(rays_total);
  85. ray_dir .reserve(rays_total);
  86. for (int c = 0; c < num_cc; ++c)
  87. {
  88. if (area_per_component[c] == 0)
  89. {
  90. continue;
  91. }
  92. std::vector<int> CF; // set of faces per component
  93. std::vector<double> CF_area;
  94. for (int f = 0; f < m; ++f)
  95. {
  96. if (C(f)==c)
  97. {
  98. CF.push_back(f);
  99. CF_area.push_back(A(f));
  100. }
  101. }
  102. // discrete distribution for random selection of faces with probability proportional to their areas
  103. std::discrete_distribution<int> ddist(CF.size(), 0, CF.size(), [&](double i){ return CF_area[static_cast<int>(i)]; }); // simple ctor of (Iter, Iter) not provided by the stupid VC11/12
  104. for (int i = 0; i < num_rays_per_component[c]; ++i)
  105. {
  106. int f = CF[ddist(prng)]; // select face with probability proportional to face area
  107. float s = rdist(prng); // random barycentric coordinate (reference: Generating Random Points in Triangles [Turk, Graphics Gems I 1990])
  108. float t = rdist(prng);
  109. float sqrt_t = sqrtf(t);
  110. float a = 1 - sqrt_t;
  111. float b = (1 - s) * sqrt_t;
  112. float c = s * sqrt_t;
  113. Eigen::Vector3f p = a * V.row(FF(f,0)).template cast<float>().eval() // be careful with the index!!!
  114. + b * V.row(FF(f,1)).template cast<float>().eval()
  115. + c * V.row(FF(f,2)).template cast<float>().eval();
  116. Eigen::Vector3f n = N.row(f).cast<float>();
  117. if (n.isZero()) continue;
  118. // random direction in hemisphere around n (avoid too grazing angle)
  119. Eigen::Vector3f d;
  120. while (true) {
  121. d = random_dir().cast<float>();
  122. float ndotd = n.dot(d);
  123. if (fabsf(ndotd) < 0.1f)
  124. {
  125. continue;
  126. }
  127. if (ndotd < 0)
  128. {
  129. d *= -1.0f;
  130. }
  131. break;
  132. }
  133. ray_face.push_back(f);
  134. ray_ori .push_back(p);
  135. ray_dir .push_back(d);
  136. if (is_verbose && ray_face.size() % (rays_total / 10) == 0) std::cout << ".";
  137. }
  138. }
  139. if (is_verbose) std::cout << ray_face.size() << " rays. ";
  140. // per component voting: first=front, second=back
  141. std::vector<std::pair<float, float>> C_vote_distance(num_cc, std::make_pair(0, 0)); // sum of distance between ray origin and intersection
  142. std::vector<std::pair<int , int >> C_vote_infinity(num_cc, std::make_pair(0, 0)); // number of rays reaching infinity
  143. std::vector<std::pair<int , int >> C_vote_parity(num_cc, std::make_pair(0, 0)); // sum of parity count for each ray
  144. if (is_verbose) std::cout << "shooting rays... ";
  145. // #pragma omp parallel for
  146. for (int i = 0; i < (int)ray_face.size(); ++i)
  147. {
  148. int f = ray_face[i];
  149. Eigen::Vector3f o = ray_ori [i];
  150. Eigen::Vector3f d = ray_dir [i];
  151. int c = C(f);
  152. // shoot ray toward front & back
  153. std::vector<Hit<float>> hits_front;
  154. std::vector<Hit<float>> hits_back;
  155. int num_rays_front;
  156. int num_rays_back;
  157. ei.intersectRay(o, d, hits_front, num_rays_front);
  158. ei.intersectRay(o, -d, hits_back , num_rays_back );
  159. if (!hits_front.empty() && hits_front[0].id == f) hits_front.erase(hits_front.begin());
  160. if (!hits_back .empty() && hits_back [0].id == f) hits_back .erase(hits_back .begin());
  161. if (use_parity) {
  162. // #pragma omp atomic
  163. C_vote_parity[c].first += hits_front.size() % 2;
  164. // #pragma omp atomic
  165. C_vote_parity[c].second += hits_back .size() % 2;
  166. } else {
  167. if (hits_front.empty())
  168. {
  169. // #pragma omp atomic
  170. C_vote_infinity[c].first++;
  171. } else {
  172. // #pragma omp atomic
  173. C_vote_distance[c].first += hits_front[0].t;
  174. }
  175. if (hits_back.empty())
  176. {
  177. // #pragma omp atomic
  178. C_vote_infinity[c].second++;
  179. } else {
  180. // #pragma omp atomic
  181. C_vote_distance[c].second += hits_back[0].t;
  182. }
  183. }
  184. }
  185. I.resize(m);
  186. for(int f = 0; f < m; ++f)
  187. {
  188. int c = C(f);
  189. if (use_parity) {
  190. I(f) = C_vote_parity[c].first > C_vote_parity[c].second ? 1 : 0; // Ideally, parity for the front/back side should be 1/0 (i.e., parity sum for all rays should be smaller on the front side)
  191. } else {
  192. I(f) = (C_vote_infinity[c].first == C_vote_infinity[c].second && C_vote_distance[c].first < C_vote_distance[c].second) ||
  193. C_vote_infinity[c].first < C_vote_infinity[c].second
  194. ? 1 : 0;
  195. }
  196. // To account for the effect of bfs_orient
  197. if (Fi.row(f) != FF.row(f))
  198. I(f) = 1 - I(f);
  199. }
  200. if (is_verbose) std::cout << "done!" << std::endl;
  201. }
  202. template <
  203. typename DerivedV,
  204. typename DerivedF,
  205. typename DerivedFF,
  206. typename DerivedI>
  207. IGL_INLINE void igl::embree::reorient_facets_raycast(
  208. const Eigen::MatrixBase<DerivedV> & V,
  209. const Eigen::MatrixBase<DerivedF> & F,
  210. Eigen::PlainObjectBase<DerivedFF> & FF,
  211. Eigen::PlainObjectBase<DerivedI> & I)
  212. {
  213. const int rays_total = F.rows()*100;
  214. const int rays_minimum = 10;
  215. const bool facet_wise = false;
  216. const bool use_parity = false;
  217. const bool is_verbose = false;
  218. Eigen::Vector<typename DerivedI::Scalar,Eigen::Dynamic> C;
  219. reorient_facets_raycast(
  220. V,F,rays_total,rays_minimum,facet_wise,use_parity,is_verbose,I,C);
  221. // Conservative in case FF = F
  222. FF.conservativeResize(F.rows(),F.cols());
  223. for(int i = 0;i<I.rows();i++)
  224. {
  225. if(I(i))
  226. {
  227. FF.row(i) = (F.row(i).reverse()).eval();
  228. }else
  229. {
  230. FF.row(i) = F.row(i);
  231. }
  232. }
  233. }
  234. #ifdef IGL_STATIC_LIBRARY
  235. // Explicit template instantiation
  236. template void igl::embree::reorient_facets_raycast<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  237. template void igl::embree::reorient_facets_raycast<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool, bool, bool, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  238. template void igl::embree::reorient_facets_raycast<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool, bool, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  239. #endif