winding_number.cpp 5.8 KB

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