fast_winding_number.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. #include "fast_winding_number.h"
  2. #include "octree.h"
  3. #include "parallel_for.h"
  4. #include "PI.h"
  5. #include <vector>
  6. #include <cassert>
  7. template <
  8. typename DerivedP,
  9. typename DerivedA,
  10. typename DerivedN,
  11. typename Index,
  12. typename DerivedCH,
  13. typename DerivedCM,
  14. typename DerivedR,
  15. typename DerivedEC>
  16. IGL_INLINE void igl::fast_winding_number(
  17. const Eigen::MatrixBase<DerivedP>& P,
  18. const Eigen::MatrixBase<DerivedN>& N,
  19. const Eigen::MatrixBase<DerivedA>& A,
  20. const std::vector<std::vector<Index> > & point_indices,
  21. const Eigen::MatrixBase<DerivedCH>& CH,
  22. const int expansion_order,
  23. Eigen::PlainObjectBase<DerivedCM>& CM,
  24. Eigen::PlainObjectBase<DerivedR>& R,
  25. Eigen::PlainObjectBase<DerivedEC>& EC)
  26. {
  27. typedef typename DerivedP::Scalar real_p;
  28. typedef typename DerivedCM::Scalar real_cm;
  29. typedef typename DerivedR::Scalar real_r;
  30. typedef typename DerivedEC::Scalar real_ec;
  31. int m = CH.size();
  32. int num_terms = -1;
  33. assert(expansion_order < 3 && expansion_order >= 0 && "m must be less than n");
  34. if(expansion_order == 0){
  35. num_terms = 3;
  36. } else if(expansion_order ==1){
  37. num_terms = 3 + 9;
  38. } else if(expansion_order == 2){
  39. num_terms = 3 + 9 + 27;
  40. }
  41. assert(num_terms > 0);
  42. R.resize(m);
  43. CM.resize(m,3);
  44. EC.resize(m,num_terms);
  45. EC.setZero(m,num_terms);
  46. std::function< void(const int) > helper;
  47. helper = [&helper,
  48. &P,&N,&A,&point_indices,&CH,&EC,&R,&CM]
  49. (const int index)-> void
  50. {
  51. Eigen::Matrix<real_cm,1,3> masscenter;
  52. masscenter << 0,0,0;
  53. Eigen::Matrix<real_ec,1,3> zeroth_expansion;
  54. zeroth_expansion << 0,0,0;
  55. real_p areatotal = 0.0;
  56. for(int j = 0; j < point_indices[index].size(); j++){
  57. int curr_point_index = point_indices[index][j];
  58. areatotal += A(curr_point_index);
  59. masscenter += A(curr_point_index)*P.row(curr_point_index);
  60. zeroth_expansion += A(curr_point_index)*N.row(curr_point_index);
  61. }
  62. masscenter = masscenter/areatotal;
  63. CM.row(index) = masscenter;
  64. EC.block(index,0,1,3) = zeroth_expansion;
  65. real_r max_norm = 0;
  66. real_r curr_norm;
  67. for(int i = 0; i < point_indices[index].size(); i++){
  68. //Get max distance from center of mass:
  69. int curr_point_index = point_indices[index][i];
  70. Eigen::Matrix<real_r,1,3> point =
  71. P.row(curr_point_index)-masscenter;
  72. curr_norm = point.norm();
  73. if(curr_norm > max_norm){
  74. max_norm = curr_norm;
  75. }
  76. //Calculate higher order terms if necessary
  77. Eigen::Matrix<real_ec,3,3> TempCoeffs;
  78. if(EC.cols() >= (3+9)){
  79. TempCoeffs = A(curr_point_index)*point.transpose()*
  80. N.row(curr_point_index);
  81. EC.block(index,3,1,9) +=
  82. Eigen::Map<Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
  83. TempCoeffs.size());
  84. }
  85. if(EC.cols() == (3+9+27)){
  86. for(int k = 0; k < 3; k++){
  87. TempCoeffs = 0.5 * point(k) * (A(curr_point_index)*
  88. point.transpose()*N.row(curr_point_index));
  89. EC.block(index,12+9*k,1,9) += Eigen::Map<
  90. Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
  91. TempCoeffs.size());
  92. }
  93. }
  94. }
  95. R(index) = max_norm;
  96. if(CH(index,0) != -1)
  97. {
  98. for(int i = 0; i < 8; i++){
  99. int child = CH(index,i);
  100. helper(child);
  101. }
  102. }
  103. };
  104. helper(0);
  105. }
  106. template <
  107. typename DerivedP,
  108. typename DerivedA,
  109. typename DerivedN,
  110. typename Index,
  111. typename DerivedCH,
  112. typename DerivedCM,
  113. typename DerivedR,
  114. typename DerivedEC,
  115. typename DerivedQ,
  116. typename BetaType,
  117. typename DerivedWN>
  118. IGL_INLINE void igl::fast_winding_number(
  119. const Eigen::MatrixBase<DerivedP>& P,
  120. const Eigen::MatrixBase<DerivedN>& N,
  121. const Eigen::MatrixBase<DerivedA>& A,
  122. const std::vector<std::vector<Index> > & point_indices,
  123. const Eigen::MatrixBase<DerivedCH>& CH,
  124. const Eigen::MatrixBase<DerivedCM>& CM,
  125. const Eigen::MatrixBase<DerivedR>& R,
  126. const Eigen::MatrixBase<DerivedEC>& EC,
  127. const Eigen::MatrixBase<DerivedQ>& Q,
  128. const BetaType beta,
  129. Eigen::PlainObjectBase<DerivedWN>& WN)
  130. {
  131. typedef typename DerivedEC::Scalar real_ec;
  132. typedef typename DerivedQ::Scalar real_q;
  133. typedef typename DerivedWN::Scalar real_wn;
  134. const real_wn PI_4 = 4.0*igl::PI;
  135. typedef Eigen::Matrix<real_q,1,3> RowVec;
  136. auto direct_eval = [&PI_4](
  137. const RowVec & loc,
  138. const Eigen::Matrix<real_ec,1,3> & anorm)->real_wn
  139. {
  140. const typename RowVec::Scalar loc_norm = loc.norm();
  141. if(loc_norm == 0)
  142. {
  143. return 0.5;
  144. }else
  145. {
  146. return (loc(0)*anorm(0)+loc(1)*anorm(1)+loc(2)*anorm(2))
  147. /(PI_4*(loc_norm*loc_norm*loc_norm));
  148. }
  149. };
  150. auto expansion_eval =
  151. [&direct_eval,&EC,&PI_4](
  152. const RowVec & loc,
  153. const int & child_index)->real_wn
  154. {
  155. real_wn wn;
  156. wn = direct_eval(loc,EC.row(child_index).template head<3>());
  157. real_wn r = loc.norm();
  158. real_wn PI_4_r3;
  159. real_wn PI_4_r5;
  160. real_wn PI_4_r7;
  161. if(EC.row(child_index).size()>3)
  162. {
  163. PI_4_r3 = PI_4*r*r*r;
  164. PI_4_r5 = PI_4_r3*r*r;
  165. const real_ec d = 1.0/(PI_4_r3);
  166. Eigen::Matrix<real_ec,3,3> SecondDerivative =
  167. loc.transpose()*loc*(-3.0/(PI_4_r5));
  168. SecondDerivative(0,0) += d;
  169. SecondDerivative(1,1) += d;
  170. SecondDerivative(2,2) += d;
  171. wn +=
  172. Eigen::Map<Eigen::Matrix<real_ec,1,9> >(
  173. SecondDerivative.data(),
  174. SecondDerivative.size()).dot(
  175. EC.row(child_index).template segment<9>(3));
  176. }
  177. if(EC.row(child_index).size()>3+9)
  178. {
  179. PI_4_r7 = PI_4_r5*r*r;
  180. const Eigen::Matrix<real_ec,3,3> locTloc = loc.transpose()*(loc/(PI_4_r7));
  181. for(int i = 0; i < 3; i++)
  182. {
  183. Eigen::Matrix<real_ec,3,3> RowCol_Diagonal =
  184. Eigen::Matrix<real_ec,3,3>::Zero(3,3);
  185. for(int u = 0;u<3;u++)
  186. {
  187. for(int v = 0;v<3;v++)
  188. {
  189. if(u==v) RowCol_Diagonal(u,v) += loc(i);
  190. if(u==i) RowCol_Diagonal(u,v) += loc(v);
  191. if(v==i) RowCol_Diagonal(u,v) += loc(u);
  192. }
  193. }
  194. Eigen::Matrix<real_ec,3,3> ThirdDerivative =
  195. 15.0*loc(i)*locTloc + (-3.0/(PI_4_r5))*(RowCol_Diagonal);
  196. wn += Eigen::Map<Eigen::Matrix<real_ec,1,9> >(
  197. ThirdDerivative.data(),
  198. ThirdDerivative.size()).dot(
  199. EC.row(child_index).template segment<9>(12 + i*9));
  200. }
  201. }
  202. return wn;
  203. };
  204. int m = Q.rows();
  205. WN.resize(m,1);
  206. std::function< real_wn(const RowVec & , const std::vector<int> &) > helper;
  207. helper = [&helper,
  208. &P,&N,&A,
  209. &point_indices,&CH,
  210. &CM,&R,&beta,
  211. &direct_eval,&expansion_eval]
  212. (const RowVec & query, const std::vector<int> & near_indices)-> real_wn
  213. {
  214. real_wn wn = 0;
  215. std::vector<int> new_near_indices;
  216. new_near_indices.reserve(8);
  217. for(int i = 0; i < near_indices.size(); i++)
  218. {
  219. int index = near_indices[i];
  220. //Leaf Case, Brute force
  221. if(CH(index,0) == -1)
  222. {
  223. for(int j = 0; j < point_indices[index].size(); j++)
  224. {
  225. int curr_row = point_indices[index][j];
  226. wn += direct_eval(P.row(curr_row)-query,
  227. N.row(curr_row)*A(curr_row));
  228. }
  229. }
  230. //Non-Leaf Case
  231. else
  232. {
  233. for(int child = 0; child < 8; child++)
  234. {
  235. int child_index = CH(index,child);
  236. if(point_indices[child_index].size() > 0)
  237. {
  238. const RowVec CMciq = (CM.row(child_index)-query);
  239. if(CMciq.norm() > beta*R(child_index))
  240. {
  241. if(CH(child_index,0) == -1)
  242. {
  243. for(int j=0;j<point_indices[child_index].size();j++)
  244. {
  245. int curr_row = point_indices[child_index][j];
  246. wn += direct_eval(P.row(curr_row)-query,
  247. N.row(curr_row)*A(curr_row));
  248. }
  249. }else{
  250. wn += expansion_eval(CMciq,child_index);
  251. }
  252. }else
  253. {
  254. new_near_indices.emplace_back(child_index);
  255. }
  256. }
  257. }
  258. }
  259. }
  260. if(new_near_indices.size() > 0)
  261. {
  262. wn += helper(query,new_near_indices);
  263. }
  264. return wn;
  265. };
  266. if(beta > 0)
  267. {
  268. const std::vector<int> near_indices_start = {0};
  269. igl::parallel_for(m,[&](int iter){
  270. WN(iter) = helper(Q.row(iter).eval(),near_indices_start);
  271. },1000);
  272. } else
  273. {
  274. igl::parallel_for(m,[&](int iter){
  275. double wn = 0;
  276. for(int j = 0; j <P.rows(); j++)
  277. {
  278. wn += direct_eval(P.row(j)-Q.row(iter),N.row(j)*A(j));
  279. }
  280. WN(iter) = wn;
  281. },1000);
  282. }
  283. }
  284. template <
  285. typename DerivedP,
  286. typename DerivedA,
  287. typename DerivedN,
  288. typename DerivedQ,
  289. typename BetaType,
  290. typename DerivedWN>
  291. IGL_INLINE void igl::fast_winding_number(
  292. const Eigen::MatrixBase<DerivedP>& P,
  293. const Eigen::MatrixBase<DerivedN>& N,
  294. const Eigen::MatrixBase<DerivedA>& A,
  295. const Eigen::MatrixBase<DerivedQ>& Q,
  296. const int expansion_order,
  297. const BetaType beta,
  298. Eigen::PlainObjectBase<DerivedWN>& WN)
  299. {
  300. typedef typename DerivedWN::Scalar real;
  301. std::vector<std::vector<int> > point_indices;
  302. Eigen::Matrix<int,Eigen::Dynamic,8> CH;
  303. Eigen::Matrix<real,Eigen::Dynamic,3> CN;
  304. Eigen::Matrix<real,Eigen::Dynamic,1> W;
  305. octree(P,point_indices,CH,CN,W);
  306. Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
  307. Eigen::Matrix<real,Eigen::Dynamic,3> CM;
  308. Eigen::Matrix<real,Eigen::Dynamic,1> R;
  309. fast_winding_number(P,N,A,point_indices,CH,expansion_order,CM,R,EC);
  310. fast_winding_number(P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
  311. }
  312. template <
  313. typename DerivedP,
  314. typename DerivedA,
  315. typename DerivedN,
  316. typename DerivedQ,
  317. typename DerivedWN>
  318. IGL_INLINE void igl::fast_winding_number(
  319. const Eigen::MatrixBase<DerivedP>& P,
  320. const Eigen::MatrixBase<DerivedN>& N,
  321. const Eigen::MatrixBase<DerivedA>& A,
  322. const Eigen::MatrixBase<DerivedQ>& Q,
  323. Eigen::PlainObjectBase<DerivedWN>& WN)
  324. {
  325. fast_winding_number(P,N,A,Q,2,2.0,WN);
  326. }
  327. template <
  328. typename DerivedV,
  329. typename DerivedF,
  330. typename DerivedQ,
  331. typename DerivedW>
  332. IGL_INLINE void igl::fast_winding_number(
  333. const Eigen::MatrixBase<DerivedV> & V,
  334. const Eigen::MatrixBase<DerivedF> & F,
  335. const Eigen::MatrixBase<DerivedQ> & Q,
  336. Eigen::PlainObjectBase<DerivedW> & W)
  337. {
  338. igl::FastWindingNumberBVH fwn_bvh;
  339. int order = 2;
  340. igl::fast_winding_number(V,F,order,fwn_bvh);
  341. float accuracy_scale = 2;
  342. igl::fast_winding_number(fwn_bvh,accuracy_scale,Q,W);
  343. }
  344. template <
  345. typename DerivedV,
  346. typename DerivedF>
  347. IGL_INLINE void igl::fast_winding_number(
  348. const Eigen::MatrixBase<DerivedV> & V,
  349. const Eigen::MatrixBase<DerivedF> & F,
  350. const int order,
  351. FastWindingNumberBVH & fwn_bvh)
  352. {
  353. assert(V.cols() == 3 && "V should be 3D");
  354. assert(F.cols() == 3 && "F should contain triangles");
  355. // Extra copies. Usuually this won't be the bottleneck.
  356. fwn_bvh.U.resize(V.rows());
  357. for(int i = 0;i<V.rows();i++)
  358. {
  359. for(int j = 0;j<3;j++)
  360. {
  361. fwn_bvh.U[i][j] = V(i,j);
  362. }
  363. }
  364. // Wouldn't need to copy if F is **RowMajor**
  365. fwn_bvh.F.resize(F.size());
  366. for(int f = 0;f<F.rows();f++)
  367. {
  368. for(int c = 0;c<F.cols();c++)
  369. {
  370. fwn_bvh.F[c+f*F.cols()] = F(f,c);
  371. }
  372. }
  373. fwn_bvh.ut_solid_angle.clear();
  374. fwn_bvh.ut_solid_angle.init(
  375. fwn_bvh.F.size()/3,
  376. &fwn_bvh.F[0],
  377. fwn_bvh.U.size(),
  378. &fwn_bvh.U[0],
  379. order);
  380. }
  381. template <
  382. typename DerivedQ,
  383. typename DerivedW>
  384. IGL_INLINE void igl::fast_winding_number(
  385. const FastWindingNumberBVH & fwn_bvh,
  386. const float accuracy_scale,
  387. const Eigen::MatrixBase<DerivedQ> & Q,
  388. Eigen::PlainObjectBase<DerivedW> & W)
  389. {
  390. assert(Q.cols() == 3 && "Q should be 3D");
  391. W.resize(Q.rows(),1);
  392. igl::parallel_for(Q.rows(),[&](int p)
  393. {
  394. FastWindingNumber::HDK_Sample::UT_Vector3T<float>Qp;
  395. Qp[0] = Q(p,0);
  396. Qp[1] = Q(p,1);
  397. Qp[2] = Q(p,2);
  398. W(p) = fwn_bvh.ut_solid_angle.computeSolidAngle(Qp,accuracy_scale) / (4.0*igl::PI);
  399. },1000);
  400. }
  401. template <typename Derivedp>
  402. IGL_INLINE typename Derivedp::Scalar igl::fast_winding_number(
  403. const FastWindingNumberBVH & fwn_bvh,
  404. const float accuracy_scale,
  405. const Eigen::MatrixBase<Derivedp> & p)
  406. {
  407. assert(p.cols() == 3 && "p should be 3D");
  408. FastWindingNumber::HDK_Sample::UT_Vector3T<float>Qp;
  409. Qp[0] = p(0,0);
  410. Qp[1] = p(0,1);
  411. Qp[2] = p(0,2);
  412. typename Derivedp::Scalar w = fwn_bvh.ut_solid_angle.computeSolidAngle(Qp,accuracy_scale) / (4.0*igl::PI);
  413. return w;
  414. }
  415. #ifdef IGL_STATIC_LIBRARY
  416. // Explicit template instantiation
  417. // generated by autoexplicit.sh
  418. template void igl::fast_winding_number<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  419. template Eigen::Matrix<float, -1, -1, 0, -1, -1>::Scalar igl::fast_winding_number<Eigen::Matrix<float, -1, -1, 0, -1, -1> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&);
  420. // generated by autoexplicit.sh
  421. template void igl::fast_winding_number<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::Matrix<double, -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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  422. template void igl::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  423. template void igl::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  424. template void igl::fast_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  425. template void igl::fast_winding_number<Eigen::Matrix<double, -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, igl::FastWindingNumberBVH&);
  426. template void igl::fast_winding_number<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
  427. template void igl::fast_winding_number<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, igl::FastWindingNumberBVH&);
  428. // tom did this manually. Unsure how to generate otherwise... sorry.
  429. template Eigen::Matrix<float, 1, 3, 1, 1, 3>::Scalar igl::fast_winding_number<Eigen::Matrix<float, 1, 3, 1, 1, 3> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
  430. template void igl::fast_winding_number<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, igl::FastWindingNumberBVH&);
  431. template void igl::fast_winding_number<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, int, igl::FastWindingNumberBVH&);
  432. template Eigen::CwiseUnaryOp<Eigen::internal::scalar_cast_op<double, float>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const>::Scalar igl::fast_winding_number<Eigen::CwiseUnaryOp<Eigen::internal::scalar_cast_op<double, float>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const> >(igl::FastWindingNumberBVH const&, float, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_cast_op<double, float>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const> > const&);
  433. #endif