signed_distance.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2014 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 "signed_distance.h"
  9. #include "get_seconds.h"
  10. #include "per_edge_normals.h"
  11. #include "per_face_normals.h"
  12. #include "per_vertex_normals.h"
  13. #include "point_mesh_squared_distance.h"
  14. #include "pseudonormal_test.h"
  15. IGL_INLINE void igl::signed_distance(
  16. const Eigen::MatrixXd & P,
  17. const Eigen::MatrixXd & V,
  18. const Eigen::MatrixXi & F,
  19. const SignedDistanceType sign_type,
  20. Eigen::VectorXd & S,
  21. Eigen::VectorXi & I,
  22. Eigen::MatrixXd & C,
  23. Eigen::MatrixXd & N)
  24. {
  25. using namespace Eigen;
  26. using namespace std;
  27. assert(V.cols() == 3 && "V should have 3d positions");
  28. assert(P.cols() == 3 && "P should have 3d positions");
  29. // Only unsigned distance is supported for non-triangles
  30. if(sign_type != SIGNED_DISTANCE_TYPE_UNSIGNED)
  31. {
  32. assert(F.cols() == 3 && "F should have triangles");
  33. }
  34. // Prepare distance computation
  35. AABB<MatrixXd,3> tree;
  36. tree.init(V,F);
  37. Eigen::MatrixXd FN,VN,EN;
  38. Eigen::MatrixXi E;
  39. Eigen::VectorXi EMAP;
  40. WindingNumberAABB<Eigen::Vector3d> hier;
  41. switch(sign_type)
  42. {
  43. default:
  44. assert(false && "Unknown SignedDistanceType");
  45. case SIGNED_DISTANCE_TYPE_UNSIGNED:
  46. // do nothing
  47. break;
  48. case SIGNED_DISTANCE_TYPE_DEFAULT:
  49. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  50. hier.set_mesh(V,F);
  51. hier.grow();
  52. break;
  53. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  54. // "Signed Distance Computation Using the Angle Weighted Pseudonormal"
  55. // [Bærentzen & Aanæs 2005]
  56. per_face_normals(V,F,FN);
  57. per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
  58. per_edge_normals(
  59. V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP);
  60. N.resize(P.rows(),3);
  61. break;
  62. }
  63. S.resize(P.rows(),1);
  64. I.resize(P.rows(),1);
  65. C.resize(P.rows(),3);
  66. for(int p = 0;p<P.rows();p++)
  67. {
  68. const RowVector3d q = P.row(p);
  69. double s,sqrd;
  70. RowVector3d c;
  71. int i=-1;
  72. switch(sign_type)
  73. {
  74. default:
  75. assert(false && "Unknown SignedDistanceType");
  76. case SIGNED_DISTANCE_TYPE_UNSIGNED:
  77. s = 1.;
  78. sqrd = tree.squared_distance(V,F,q,i,c);
  79. break;
  80. case SIGNED_DISTANCE_TYPE_DEFAULT:
  81. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  82. signed_distance_winding_number(tree,V,F,hier,q,s,sqrd,i,c);
  83. break;
  84. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  85. {
  86. Eigen::RowVector3d n;
  87. signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
  88. N.row(p) = n;
  89. break;
  90. }
  91. }
  92. I(p) = i;
  93. S(p) = s*sqrt(sqrd);
  94. C.row(p) = c;
  95. }
  96. }
  97. IGL_INLINE double igl::signed_distance_pseudonormal(
  98. const AABB<Eigen::MatrixXd,3> & tree,
  99. const Eigen::MatrixXd & V,
  100. const Eigen::MatrixXi & F,
  101. const Eigen::MatrixXd & FN,
  102. const Eigen::MatrixXd & VN,
  103. const Eigen::MatrixXd & EN,
  104. const Eigen::VectorXi & EMAP,
  105. const Eigen::RowVector3d & q)
  106. {
  107. double s,sqrd;
  108. Eigen::RowVector3d n,c;
  109. int i = -1;
  110. signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
  111. return s*sqrt(sqrd);
  112. }
  113. IGL_INLINE void igl::signed_distance_pseudonormal(
  114. const Eigen::MatrixXd & P,
  115. const Eigen::MatrixXd & V,
  116. const Eigen::MatrixXi & F,
  117. const AABB<Eigen::MatrixXd,3> & tree,
  118. const Eigen::MatrixXd & FN,
  119. const Eigen::MatrixXd & VN,
  120. const Eigen::MatrixXd & EN,
  121. const Eigen::VectorXi & EMAP,
  122. Eigen::VectorXd & S,
  123. Eigen::VectorXi & I,
  124. Eigen::MatrixXd & C,
  125. Eigen::MatrixXd & N)
  126. {
  127. using namespace Eigen;
  128. const size_t np = P.rows();
  129. S.resize(np,1);
  130. I.resize(np,1);
  131. N.resize(np,3);
  132. C.resize(np,3);
  133. # pragma omp parallel for if(np>1000)
  134. for(size_t p = 0;p<np;p++)
  135. {
  136. double s,sqrd;
  137. RowVector3d n,c;
  138. int i = -1;
  139. RowVector3d q = P.row(p);
  140. signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
  141. S(p) = s*sqrt(sqrd);
  142. I(p) = i;
  143. N.row(p) = n;
  144. C.row(p) = c;
  145. }
  146. // igl::AABB<MatrixXd,3> tree_P;
  147. // MatrixXi J = VectorXi::LinSpaced(P.rows(),0,P.rows()-1);
  148. // tree_P.init(P,J);
  149. // tree.squared_distance(V,F,tree_P,P,J,S,I,C);
  150. //# pragma omp parallel for if(np>1000)
  151. // for(size_t p = 0;p<np;p++)
  152. // {
  153. // RowVector3d c = C.row(p);
  154. // RowVector3d q = P.row(p);
  155. // const int f = I(p);
  156. // double s;
  157. // RowVector3d n;
  158. // pseudonormal_test(V,F,FN,VN,EN,EMAP,q,f,c,s,n);
  159. // N.row(p) = n;
  160. // S(p) = s*sqrt(S(p));
  161. // }
  162. }
  163. IGL_INLINE void igl::signed_distance_pseudonormal(
  164. const AABB<Eigen::MatrixXd,3> & tree,
  165. const Eigen::MatrixXd & V,
  166. const Eigen::MatrixXi & F,
  167. const Eigen::MatrixXd & FN,
  168. const Eigen::MatrixXd & VN,
  169. const Eigen::MatrixXd & EN,
  170. const Eigen::VectorXi & EMAP,
  171. const Eigen::RowVector3d & q,
  172. double & s,
  173. double & sqrd,
  174. int & f,
  175. Eigen::RowVector3d & c,
  176. Eigen::RowVector3d & n)
  177. {
  178. using namespace Eigen;
  179. using namespace std;
  180. sqrd = tree.squared_distance(V,F,q,f,c);
  181. pseudonormal_test(V,F,FN,VN,EN,EMAP,q,f,c,s,n);
  182. }
  183. IGL_INLINE double igl::signed_distance_winding_number(
  184. const AABB<Eigen::MatrixXd,3> & tree,
  185. const Eigen::MatrixXd & V,
  186. const Eigen::MatrixXi & F,
  187. const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
  188. const Eigen::RowVector3d & q)
  189. {
  190. double s,sqrd;
  191. Eigen::RowVector3d c;
  192. int i=-1;
  193. signed_distance_winding_number(tree,V,F,hier,q,s,sqrd,i,c);
  194. return s*sqrt(sqrd);
  195. }
  196. IGL_INLINE void igl::signed_distance_winding_number(
  197. const AABB<Eigen::MatrixXd,3> & tree,
  198. const Eigen::MatrixXd & V,
  199. const Eigen::MatrixXi & F,
  200. const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
  201. const Eigen::RowVector3d & q,
  202. double & s,
  203. double & sqrd,
  204. int & i,
  205. Eigen::RowVector3d & c)
  206. {
  207. using namespace Eigen;
  208. using namespace std;
  209. using namespace igl;
  210. sqrd = tree.squared_distance(V,F,q,i,c);
  211. const double w = hier.winding_number(q.transpose());
  212. s = 1.-2.*w;
  213. }
  214. #ifdef IGL_STATIC_LIBRARY
  215. // This template is necessary for the others to compile with clang
  216. // http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable
  217. #endif