fast_winding_number.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. #include "fast_winding_number.h"
  2. #include "octree.h"
  3. #include "knn.h"
  4. #include "parallel_for.h"
  5. #include <vector>
  6. namespace igl {
  7. template <typename DerivedP, typename DerivedA, typename DerivedN,
  8. typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
  9. typename DerivedEC>
  10. IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
  11. const Eigen::MatrixBase<DerivedN>& N,
  12. const Eigen::MatrixBase<DerivedA>& A,
  13. const std::vector<std::vector<Index> > & point_indices,
  14. const Eigen::MatrixBase<DerivedCH>& CH,
  15. const int expansion_order,
  16. Eigen::PlainObjectBase<DerivedCM>& CM,
  17. Eigen::PlainObjectBase<DerivedR>& R,
  18. Eigen::PlainObjectBase<DerivedEC>& EC)
  19. {
  20. typedef typename DerivedP::Scalar real_p;
  21. typedef typename DerivedN::Scalar real_n;
  22. typedef typename DerivedA::Scalar real_a;
  23. typedef typename DerivedCM::Scalar real_cm;
  24. typedef typename DerivedR::Scalar real_r;
  25. typedef typename DerivedEC::Scalar real_ec;
  26. typedef Eigen::Matrix<real_p,1,3> RowVec3p;
  27. int m = CH.size();
  28. int num_terms;
  29. assert(expansion_order < 3 && expansion_order >= 0 && "m must be less than n");
  30. if(expansion_order == 0){
  31. num_terms = 3;
  32. } else if(expansion_order ==1){
  33. num_terms = 3 + 9;
  34. } else if(expansion_order == 2){
  35. num_terms = 3 + 9 + 27;
  36. }
  37. R.resize(m);
  38. CM.resize(m,3);
  39. EC.resize(m,num_terms);
  40. EC.setZero(m,num_terms);
  41. std::function< void(const int) > helper;
  42. helper = [&helper,
  43. &P,&N,&A,&expansion_order,&point_indices,&CH,&EC,&R,&CM]
  44. (const int index)-> void
  45. {
  46. Eigen::Matrix<real_cm,1,3> masscenter;
  47. masscenter << 0,0,0;
  48. Eigen::Matrix<real_ec,1,3> zeroth_expansion;
  49. zeroth_expansion << 0,0,0;
  50. real_p areatotal = 0.0;
  51. for(int j = 0; j < point_indices.at(index).size(); j++){
  52. int curr_point_index = point_indices.at(index).at(j);
  53. areatotal += A(curr_point_index);
  54. masscenter += A(curr_point_index)*P.row(curr_point_index);
  55. zeroth_expansion += A(curr_point_index)*N.row(curr_point_index);
  56. }
  57. masscenter = masscenter/areatotal;
  58. CM.row(index) = masscenter;
  59. EC.block(index,0,1,3) = zeroth_expansion;
  60. real_r max_norm = 0;
  61. real_r curr_norm;
  62. for(int i = 0; i < point_indices.at(index).size(); i++){
  63. //Get max distance from center of mass:
  64. int curr_point_index = point_indices.at(index).at(i);
  65. Eigen::Matrix<real_r,1,3> point =
  66. P.row(curr_point_index)-masscenter;
  67. curr_norm = point.norm();
  68. if(curr_norm > max_norm){
  69. max_norm = curr_norm;
  70. }
  71. //Calculate higher order terms if necessary
  72. Eigen::Matrix<real_ec,3,3> TempCoeffs;
  73. if(EC.cols() >= (3+9)){
  74. TempCoeffs = A(curr_point_index)*point.transpose()*
  75. N.row(curr_point_index);
  76. EC.block(index,3,1,9) +=
  77. Eigen::Map<Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
  78. TempCoeffs.size());
  79. }
  80. if(EC.cols() == (3+9+27)){
  81. for(int k = 0; k < 3; k++){
  82. TempCoeffs = 0.5 * point(k) * (A(curr_point_index)*
  83. point.transpose()*N.row(curr_point_index));
  84. EC.block(index,12+9*k,1,9) += Eigen::Map<
  85. Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
  86. TempCoeffs.size());
  87. }
  88. }
  89. }
  90. R(index) = max_norm;
  91. if(CH(index,0) != -1)
  92. {
  93. for(int i = 0; i < 8; i++){
  94. int child = CH(index,i);
  95. helper(child);
  96. }
  97. }
  98. };
  99. helper(0);
  100. }
  101. template <typename DerivedP, typename DerivedA, typename DerivedN,
  102. typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
  103. typename DerivedEC, typename DerivedQ, typename BetaType,
  104. typename DerivedWN>
  105. IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
  106. const Eigen::MatrixBase<DerivedN>& N,
  107. const Eigen::MatrixBase<DerivedA>& A,
  108. const std::vector<std::vector<Index> > & point_indices,
  109. const Eigen::MatrixBase<DerivedCH>& CH,
  110. const Eigen::MatrixBase<DerivedCM>& CM,
  111. const Eigen::MatrixBase<DerivedR>& R,
  112. const Eigen::MatrixBase<DerivedEC>& EC,
  113. const Eigen::MatrixBase<DerivedQ>& Q,
  114. const BetaType beta,
  115. Eigen::PlainObjectBase<DerivedWN>& WN){
  116. typedef typename DerivedP::Scalar real_p;
  117. typedef typename DerivedN::Scalar real_n;
  118. typedef typename DerivedA::Scalar real_a;
  119. typedef typename DerivedCM::Scalar real_cm;
  120. typedef typename DerivedR::Scalar real_r;
  121. typedef typename DerivedEC::Scalar real_ec;
  122. typedef typename DerivedQ::Scalar real_q;
  123. typedef typename DerivedWN::Scalar real_wn;
  124. typedef Eigen::Matrix<real_q,1,3> RowVec;
  125. typedef Eigen::Matrix<real_ec,3,3> EC_3by3;
  126. auto direct_eval = [](const RowVec & loc,
  127. const Eigen::Matrix<real_ec,1,3> & anorm){
  128. real_wn wn = (loc(0)*anorm(0)+loc(1)*anorm(1)+loc(2)*anorm(2))
  129. /(4.0*igl::PI*std::pow(loc.norm(),3));
  130. if(std::isnan(wn)){
  131. return 0.5;
  132. }else{
  133. return wn;
  134. }
  135. };
  136. auto expansion_eval = [&direct_eval](const RowVec & loc,
  137. const Eigen::RowVectorXd & EC){
  138. real_wn wn = direct_eval(loc,EC.head<3>());
  139. double r = loc.norm();
  140. if(EC.size()>3){
  141. Eigen::Matrix<real_ec,3,3> SecondDerivative =
  142. Eigen::Matrix<real_ec,3,3>::Identity()/(4.0*igl::PI*std::pow(r,3));
  143. SecondDerivative += -3.0*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,5));
  144. Eigen::Matrix<real_ec,1,9> derivative_vector =
  145. Eigen::Map<Eigen::Matrix<real_ec,1,9> >(SecondDerivative.data(),
  146. SecondDerivative.size());
  147. wn += derivative_vector.cwiseProduct(EC.segment<9>(3)).sum();
  148. }
  149. if(EC.size()>3+9){
  150. Eigen::Matrix<real_ec,3,3> ThirdDerivative;
  151. for(int i = 0; i < 3; i++){
  152. ThirdDerivative =
  153. 15.0*loc(i)*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,7));
  154. Eigen::Matrix<real_ec,3,3> Diagonal;
  155. Diagonal << loc(i), 0, 0,
  156. 0, loc(i), 0,
  157. 0, 0, loc(i);
  158. Eigen::Matrix<real_ec,3,3> RowCol;
  159. RowCol.setZero(3,3);
  160. RowCol.row(i) = loc;
  161. Eigen::Matrix<real_ec,3,3> RowColT = RowCol.transpose();
  162. RowCol = RowCol + RowColT;
  163. ThirdDerivative +=
  164. -3.0/(4.0*igl::PI*std::pow(r,5))*(RowCol+Diagonal);
  165. Eigen::Matrix<real_ec,1,9> derivative_vector =
  166. Eigen::Map<Eigen::Matrix<real_ec,1,9> >(ThirdDerivative.data(),
  167. ThirdDerivative.size());
  168. wn += derivative_vector.cwiseProduct(
  169. EC.segment<9>(12 + i*9)).sum();
  170. }
  171. }
  172. return wn;
  173. };
  174. int m = Q.rows();
  175. WN.resize(m,1);
  176. std::function< real_wn(const RowVec, const std::vector<int>) > helper;
  177. helper = [&helper,
  178. &P,&N,&A,
  179. &point_indices,&CH,
  180. &CM,&R,&EC,&beta,
  181. &direct_eval,&expansion_eval]
  182. (const RowVec query, const std::vector<int> near_indices)-> real_wn
  183. {
  184. std::vector<int> new_near_indices;
  185. real_wn wn = 0;
  186. for(int i = 0; i < near_indices.size(); i++){
  187. int index = near_indices.at(i);
  188. //Leaf Case, Brute force
  189. if(CH(index,0) == -1){
  190. for(int j = 0; j < point_indices.at(index).size(); j++){
  191. int curr_row = point_indices.at(index).at(j);
  192. wn += direct_eval(P.row(curr_row)-query,
  193. N.row(curr_row)*A(curr_row));
  194. }
  195. }
  196. //Non-Leaf Case
  197. else {
  198. for(int child = 0; child < 8; child++){
  199. int child_index = CH(index,child);
  200. if(point_indices.at(child_index).size() > 0){
  201. if((CM.row(child_index)-query).norm() > beta*R(child_index)){
  202. if(CH(child_index,0) == -1){
  203. for(int j=0;j<point_indices.at(child_index).size();j++){
  204. int curr_row = point_indices.at(child_index).at(j);
  205. wn += direct_eval(P.row(curr_row)-query,
  206. N.row(curr_row)*A(curr_row));
  207. }
  208. }else{
  209. wn += expansion_eval(CM.row(child_index)-query,
  210. EC.row(child_index));
  211. }
  212. }else {
  213. new_near_indices.emplace_back(child_index);
  214. }
  215. }
  216. }
  217. }
  218. }
  219. if(new_near_indices.size() > 0){
  220. wn += helper(query,new_near_indices);
  221. }
  222. return wn;
  223. };
  224. if(beta > 0){
  225. std::vector<int> near_indices_start = {0};
  226. igl::parallel_for(m,[&](int iter){
  227. WN(iter) = helper(Q.row(iter),near_indices_start);
  228. },1000);
  229. } else {
  230. igl::parallel_for(m,[&](int iter){
  231. double wn = 0;
  232. for(int j = 0; j <P.rows(); j++){
  233. wn += direct_eval(P.row(j)-Q.row(iter),N.row(j)*A(j));
  234. }
  235. WN(iter) = wn;
  236. },1000);
  237. }
  238. }
  239. template <typename DerivedP, typename DerivedA, typename DerivedN,
  240. typename DerivedQ, typename BetaType, typename DerivedWN>
  241. IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
  242. const Eigen::MatrixBase<DerivedN>& N,
  243. const Eigen::MatrixBase<DerivedA>& A,
  244. const Eigen::MatrixBase<DerivedQ>& Q,
  245. const int expansion_order,
  246. const BetaType beta,
  247. Eigen::PlainObjectBase<DerivedWN>& WN
  248. ){
  249. typedef typename DerivedWN::Scalar real;
  250. std::vector<std::vector<int> > point_indices;
  251. Eigen::Matrix<int,Eigen::Dynamic,8> CH;
  252. Eigen::Matrix<real,Eigen::Dynamic,3> CN;
  253. Eigen::Matrix<real,Eigen::Dynamic,1> W;
  254. octree(P,point_indices,CH,CN,W);
  255. Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
  256. Eigen::Matrix<real,Eigen::Dynamic,3> CM;
  257. Eigen::Matrix<real,Eigen::Dynamic,1> R;
  258. fast_winding_number(P,N,A,point_indices,CH,expansion_order,CM,R,EC);
  259. fast_winding_number(P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
  260. }
  261. template <typename DerivedP, typename DerivedA, typename DerivedN,
  262. typename DerivedQ, typename DerivedWN>
  263. IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
  264. const Eigen::MatrixBase<DerivedN>& N,
  265. const Eigen::MatrixBase<DerivedA>& A,
  266. const Eigen::MatrixBase<DerivedQ>& Q,
  267. Eigen::PlainObjectBase<DerivedWN>& WN
  268. ){
  269. fast_winding_number(P,N,A,Q,2,2.0,WN);
  270. }
  271. }