fast_winding_number.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #include "fast_winding_number.h"
  2. #include <vector>
  3. #include <iostream>
  4. #include <igl/parallel_for.h>
  5. void fast_winding_number_precompute(const Eigen::MatrixXd & P,
  6. const Eigen::MatrixXd & N,
  7. const Eigen::VectorXd & A,
  8. const std::vector<std::vector<int> > & point_indices,
  9. const std::vector<Eigen::Matrix<int,8,1>, Eigen::aligned_allocator<Eigen::Matrix<int,8,1>>> & children,
  10. const int expansion_order,
  11. Eigen::MatrixXd & CM,
  12. Eigen::VectorXd & R,
  13. Eigen::MatrixXd & EC
  14. ){
  15. int m = children.size();
  16. int num_terms;
  17. if(expansion_order == 0){
  18. num_terms = 3;
  19. } else if(expansion_order ==1){
  20. num_terms = 3 + 9;
  21. } else if(expansion_order == 2){
  22. num_terms = 3 + 9 + 27;
  23. } else {
  24. assert(false);
  25. }
  26. R.resize(m);
  27. CM.resize(m,3);
  28. EC.resize(m,num_terms);
  29. EC = Eigen::MatrixXd::Zero(m,num_terms);
  30. std::function< void(const int) > helper;
  31. helper = [&helper,
  32. &P,&N,&A,&expansion_order,&point_indices,&children,&EC,&R,&CM]
  33. (const int index)-> void
  34. {
  35. double sum_area = 0;
  36. Eigen::RowVector3d masscenter = Eigen::RowVector3d::Zero();
  37. Eigen::RowVector3d zeroth_expansion = Eigen::RowVector3d::Zero();
  38. double areatotal = 0.0;
  39. for(int j = 0; j < point_indices.at(index).size(); j++){
  40. int curr_point_index = point_indices.at(index).at(j);
  41. areatotal += A(curr_point_index);
  42. masscenter += A(curr_point_index)*P.row(curr_point_index);
  43. zeroth_expansion += A(curr_point_index)*N.row(curr_point_index);
  44. }
  45. masscenter = masscenter/areatotal;
  46. CM.row(index) = masscenter;
  47. EC.block<1,3>(index,0) = zeroth_expansion;
  48. double max_norm = 0;
  49. double curr_norm;
  50. for(int i = 0; i < point_indices.at(index).size(); i++){
  51. //Get max distance from center of mass:
  52. int curr_point_index = point_indices.at(index).at(i);
  53. Eigen::RowVector3d point = P.row(curr_point_index)-masscenter;
  54. curr_norm = point.norm();
  55. if(curr_norm > max_norm){
  56. max_norm = curr_norm;
  57. }
  58. //Calculate higher order terms if necessary
  59. Eigen::Matrix3d TempCoeffs;
  60. if(EC.cols() >= (3+9)){
  61. TempCoeffs = A(curr_point_index) * point.transpose() * N.row(curr_point_index);
  62. EC.block<1,9>(index,3) += Eigen::Map<Eigen::RowVectorXd>(TempCoeffs.data(), TempCoeffs.size());
  63. }
  64. if(EC.cols() == (3+9+27)){
  65. for(int k = 0; k < 3; k++){
  66. TempCoeffs = 0.5 * point(k) * (A(curr_point_index) * point.transpose() * N.row(curr_point_index)) ;
  67. EC.block<1,9>(index,12+9*k) += Eigen::Map<Eigen::RowVectorXd>(TempCoeffs.data(), TempCoeffs.size());
  68. }
  69. }
  70. }
  71. R(index) = max_norm;
  72. if(children.at(index)(0) != -1)
  73. {
  74. for(int i = 0; i < 8; i++){
  75. int child = children.at(index)(i);
  76. helper(child);
  77. }
  78. }
  79. };
  80. helper(0);
  81. }
  82. double direct_eval(const Eigen::RowVector3d & loc, const Eigen::RowVector3d & anorm){
  83. double wn = (loc(0)*anorm(0) + loc(1)*anorm(1) + loc(2)*anorm(2))/(4.0*M_PI*std::pow(loc.norm(),3));
  84. if(std::isnan(wn)){
  85. return 0.5;
  86. }else{
  87. return wn;
  88. }
  89. }
  90. double expansion_eval(const Eigen::RowVector3d & loc, const Eigen::RowVectorXd & EC){
  91. double wn = direct_eval(loc,EC.head<3>());
  92. double r = loc.norm();
  93. if(EC.size()>3){
  94. Eigen::Matrix3d SecondDerivative = Eigen::Matrix3d::Identity()/(4.0*M_PI*std::pow(r,3));
  95. SecondDerivative += -3.0*loc.transpose()*loc/(4.0*M_PI*std::pow(r,5));
  96. Eigen::RowVectorXd derivative_vector = Eigen::Map<Eigen::RowVectorXd>(SecondDerivative.data(), SecondDerivative.size());
  97. wn += derivative_vector.cwiseProduct(EC.segment<9>(3)).sum();
  98. }
  99. if(EC.size()>3+9){
  100. Eigen::Matrix3d ThirdDerivative;
  101. for(int i = 0; i < 3; i++){
  102. ThirdDerivative = 15.0*loc(i)*loc.transpose()*loc/(4.0*M_PI*std::pow(r,7));
  103. Eigen::Matrix3d Diagonal;
  104. Diagonal << loc(i), 0, 0,
  105. 0, loc(i), 0,
  106. 0, 0, loc(i);
  107. Eigen::Matrix3d RowCol = Eigen::Matrix3d::Zero();
  108. RowCol.row(i) = loc;
  109. RowCol = RowCol + RowCol.transpose();
  110. ThirdDerivative += -3.0/(4.0*M_PI*std::pow(r,5)) * (RowCol + Diagonal);
  111. Eigen::RowVectorXd derivative_vector = Eigen::Map<Eigen::RowVectorXd>(ThirdDerivative.data(), ThirdDerivative.size());
  112. wn += derivative_vector.cwiseProduct(EC.segment<9>(12 + i*9)).sum();
  113. }
  114. }
  115. return wn;
  116. }
  117. void fast_winding_number(const Eigen::MatrixXd & P,
  118. const Eigen::MatrixXd & N,
  119. const Eigen::VectorXd & A,
  120. const std::vector<std::vector<int> > & point_indices,
  121. const std::vector<Eigen::Matrix<int,8,1>, Eigen::aligned_allocator<Eigen::Matrix<int,8,1>>> & children,
  122. const Eigen::MatrixXd & CM,
  123. const Eigen::VectorXd & R,
  124. const Eigen::MatrixXd & EC,
  125. const Eigen::MatrixXd & Q,
  126. const double & beta,
  127. Eigen::VectorXd & WN
  128. ){
  129. int m = Q.rows();
  130. WN.resize(m);
  131. std::function< double(const Eigen::RowVector3d, const std::vector<int>) > helper;
  132. helper = [&helper,
  133. &P,&N,&A,
  134. &point_indices,&children,
  135. &CM,&R,&EC,&beta]
  136. (const Eigen::RowVector3d query, const std::vector<int> near_indices)-> double
  137. {
  138. std::vector<int> new_near_indices;
  139. double wn = 0;
  140. for(int i = 0; i < near_indices.size(); i++){
  141. int index = near_indices.at(i);
  142. //Leaf Case, Brute force
  143. if(children.at(index)(0) == -1){
  144. for(int j = 0; j < point_indices.at(index).size(); j++){
  145. int curr_row = point_indices.at(index).at(j);
  146. wn += direct_eval(P.row(curr_row)-query,N.row(curr_row)*A(curr_row));
  147. }
  148. }
  149. //Non-Leaf Case
  150. else {
  151. for(int child = 0; child < 8; child++){
  152. int child_index = children.at(index)(child);
  153. if(point_indices.at(child_index).size() > 0){
  154. if((CM.row(child_index)-query).norm() > beta*R(child_index)){
  155. if(children.at(child_index)(0) == -1){
  156. for(int j = 0; j < point_indices.at(child_index).size(); j++){
  157. int curr_row = point_indices.at(child_index).at(j);
  158. wn += direct_eval(P.row(curr_row)-query,N.row(curr_row)*A(curr_row));
  159. }
  160. }else{
  161. wn += expansion_eval(CM.row(child_index)-query,EC.row(child_index));
  162. }
  163. }else {
  164. new_near_indices.emplace_back(child_index);
  165. }
  166. }
  167. }
  168. }
  169. }
  170. if(new_near_indices.size() > 0){
  171. wn += helper(query,new_near_indices);
  172. }
  173. return wn;
  174. };
  175. if(beta >= 0){
  176. std::vector<int> near_indices_start = {0};
  177. igl::parallel_for(m,[&](int iter){
  178. WN(iter) = helper(Q.row(iter),near_indices_start);
  179. },1000);
  180. } else {
  181. igl::parallel_for(m,[&](int iter){
  182. double wn = 0;
  183. for(int j = 0; j <P.rows(); j++){
  184. wn += direct_eval(P.row(j)-Q.row(iter),N.row(j)*A(j));
  185. }
  186. WN(iter) = wn;
  187. },1000);
  188. }
  189. }