winding_number.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "winding_number.h"
  2. #include "WindingNumberAABB.h"
  3. #include <igl/PI.h>
  4. #include <cmath>
  5. IGL_INLINE void igl::winding_number(
  6. const Eigen::MatrixXd & V,
  7. const Eigen::MatrixXi & F,
  8. const Eigen::MatrixXd & O,
  9. Eigen::VectorXd & W)
  10. {
  11. using namespace Eigen;
  12. // make room for output
  13. W.resize(O.rows(),1);
  14. switch(F.cols())
  15. {
  16. case 2:
  17. return winding_number_2(
  18. V.data(),
  19. V.rows(),
  20. F.data(),
  21. F.rows(),
  22. O.data(),
  23. O.rows(),
  24. W.data());
  25. case 3:
  26. {
  27. WindingNumberAABB<Vector3d> hier(V,F);
  28. hier.grow();
  29. // loop over origins
  30. const int no = O.rows();
  31. # pragma omp parallel for if (no>IGL_WINDING_NUMBER_OMP_MIN_VALUE)
  32. for(int o = 0;o<no;o++)
  33. {
  34. Vector3d p = O.row(o);
  35. W(o) = hier.winding_number(p);
  36. }
  37. }
  38. default: assert(false && "Bad simplex size"); break;
  39. }
  40. }
  41. template <typename DerivedF>
  42. IGL_INLINE void igl::winding_number_3(
  43. const double * V,
  44. const int n,
  45. const DerivedF * F,
  46. const int m,
  47. const double * O,
  48. const int no,
  49. double * S)
  50. {
  51. // Initialize output
  52. // loop over origins
  53. #pragma omp parallel for if (no>IGL_WINDING_NUMBER_OMP_MIN_VALUE)
  54. for(int o = 0;o<no;o++)
  55. {
  56. S[o] = 0;
  57. }
  58. // Only use parallel for if there are many facets and more than one origin.
  59. // Assumes that if there is exactly one origin then this is being called
  60. // within an outer for loop which may be parallel
  61. #pragma omp parallel for if (m>IGL_WINDING_NUMBER_OMP_MIN_VALUE && no>1)
  62. // loop over faces
  63. for(int f = 0;f<m;f++)
  64. {
  65. // Gather corners
  66. double C[3][3];
  67. // loop around triangle
  68. for(int t=0;t<3;t++)
  69. {
  70. // loop over dimensions
  71. for(int d = 0;d<3;d++)
  72. {
  73. // Indices are offset by 1
  74. int Ff = F[m*t + f];
  75. C[t][d] = V[d*n + Ff];
  76. }
  77. }
  78. // loop over origins
  79. for(int o = 0;o<no;o++)
  80. {
  81. // Gather vectors to corners
  82. double v[3][3];
  83. double vl[3];
  84. // loop around triangle
  85. for(int t=0;t<3;t++)
  86. {
  87. vl[t] = 0;
  88. // loop over dimensions
  89. for(int d = 0;d<3;d++)
  90. {
  91. v[t][d] = C[t][d] - O[d*no + o];
  92. // compute edge length contribution
  93. vl[t] += v[t][d]*v[t][d];
  94. }
  95. // finish edge length computation
  96. // Matlab crashes on NaN
  97. if(vl[t]!=0)
  98. {
  99. vl[t] /= sqrt(vl[t]);
  100. }
  101. }
  102. //printf("\n");
  103. // Compute determinant
  104. double detf =
  105. v[0][0]*v[1][1]*v[2][2]+
  106. v[1][0]*v[2][1]*v[0][2]+
  107. v[2][0]*v[0][1]*v[1][2]-
  108. v[2][0]*v[1][1]*v[0][2]-
  109. v[1][0]*v[0][1]*v[2][2]-
  110. v[0][0]*v[2][1]*v[1][2];
  111. // Compute pairwise dotproducts
  112. double dp[3];
  113. dp[0] = v[1][0]*v[2][0];
  114. dp[0] += v[1][1]*v[2][1];
  115. dp[0] += v[1][2]*v[2][2];
  116. dp[1] = v[2][0]*v[0][0];
  117. dp[1] += v[2][1]*v[0][1];
  118. dp[1] += v[2][2]*v[0][2];
  119. dp[2] = v[0][0]*v[1][0];
  120. dp[2] += v[0][1]*v[1][1];
  121. dp[2] += v[0][2]*v[1][2];
  122. // Compute winding number
  123. // Only divide by TWO_PI instead of 4*pi because there was a 2 out front
  124. double val = atan2(detf,
  125. vl[0]*vl[1]*vl[2] +
  126. dp[0]*vl[0] +
  127. dp[1]*vl[1] +
  128. dp[2]*vl[2]) / (2.*igl::PI);
  129. #pragma omp atomic
  130. S[o] += val;
  131. }
  132. }
  133. }
  134. template <typename DerivedF>
  135. IGL_INLINE void igl::winding_number_2(
  136. const double * V,
  137. const int n,
  138. const DerivedF * F,
  139. const int m,
  140. const double * O,
  141. const int no,
  142. double * S)
  143. {
  144. // Initialize output
  145. // loop over origins
  146. #pragma omp parallel for if (no>IGL_WINDING_NUMBER_OMP_MIN_VALUE)
  147. for(int o = 0;o<no;o++)
  148. {
  149. S[o] = 0;
  150. }
  151. #pragma omp parallel for if (m>IGL_WINDING_NUMBER_OMP_MIN_VALUE && no>1)
  152. // loop over faces
  153. for(int f = 0;f<m;f++)
  154. {
  155. // Index of source and destination
  156. int s = F[m*0 + f];
  157. int d = F[m*1 + f];
  158. // Positions of source and destination
  159. double vs[2];
  160. double vd[2];
  161. vs[0] = V[0*n + s];
  162. vs[1] = V[1*n + s];
  163. vd[0] = V[0*n + d];
  164. vd[1] = V[1*n + d];
  165. // loop over origins
  166. for(int o = 0;o<no;o++)
  167. {
  168. // Gather vectors to source and destination
  169. double o2vs[2];
  170. double o2vd[2];
  171. // and lengths
  172. double o2vsl = 0;
  173. double o2vdl = 0;
  174. for(int i = 0;i<2;i++)
  175. {
  176. o2vs[i] = O[i*no + o] - vs[i];
  177. o2vd[i] = O[i*no + o] - vd[i];
  178. o2vsl += o2vs[i]*o2vs[i];
  179. o2vdl += o2vd[i]*o2vd[i];
  180. }
  181. o2vsl = sqrt(o2vsl);
  182. o2vdl = sqrt(o2vdl);
  183. // Normalize
  184. for(int i = 0;i<2;i++)
  185. {
  186. // Matlab crashes on NaN
  187. if(o2vsl!=0)
  188. {
  189. o2vs[i] /= o2vsl;
  190. }
  191. if(o2vdl!=0)
  192. {
  193. o2vd[i] /= o2vdl;
  194. }
  195. }
  196. double val =
  197. atan2(o2vd[0]*o2vs[1]-o2vd[1]*o2vs[0],o2vd[0]*o2vs[0]+o2vd[1]*o2vs[1])/
  198. (2.*igl::PI);
  199. #pragma omp atomic
  200. S[o] += val;
  201. }
  202. }
  203. }
  204. #ifndef IGL_HEADER_ONLY
  205. // Explicit template specialization
  206. template void igl::winding_number_3<int>(double const*, int, int const*, int, double const*, int, double*);
  207. template void igl::winding_number_2<double>(double const*, int, double const*, int, double const*, int, double*);
  208. template void igl::winding_number_3<double>(double const*, int, double const*, int, double const*, int, double*);
  209. #endif