signed_distance.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. const int dim = V.cols();
  28. assert((V.cols() == 3||V.cols() == 2) && "V should have 3d or 2d positions");
  29. assert((P.cols() == 3||P.cols() == 2) && "P should have 3d or 2d positions");
  30. assert(V.cols() == P.cols() && "V should have same dimension as P");
  31. // Only unsigned distance is supported for non-triangles
  32. if(sign_type != SIGNED_DISTANCE_TYPE_UNSIGNED)
  33. {
  34. assert(F.cols() == dim && "F should have co-dimension 0 simplices");
  35. }
  36. // Prepare distance computation
  37. AABB<MatrixXd,3> tree3;
  38. AABB<MatrixXd,2> tree2;
  39. switch(dim)
  40. {
  41. default:
  42. case 3:
  43. tree3.init(V,F);
  44. break;
  45. case 2:
  46. tree2.init(V,F);
  47. break;
  48. }
  49. Eigen::MatrixXd FN,VN,EN;
  50. Eigen::MatrixXi E;
  51. Eigen::VectorXi EMAP;
  52. WindingNumberAABB<Eigen::Vector3d> hier3;
  53. switch(sign_type)
  54. {
  55. default:
  56. assert(false && "Unknown SignedDistanceType");
  57. case SIGNED_DISTANCE_TYPE_UNSIGNED:
  58. // do nothing
  59. break;
  60. case SIGNED_DISTANCE_TYPE_DEFAULT:
  61. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  62. switch(dim)
  63. {
  64. default:
  65. case 3:
  66. hier3.set_mesh(V,F);
  67. hier3.grow();
  68. break;
  69. case 2:
  70. // no precomp, no hierarchy
  71. break;
  72. }
  73. break;
  74. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  75. switch(dim)
  76. {
  77. default:
  78. case 3:
  79. // "Signed Distance Computation Using the Angle Weighted Pseudonormal"
  80. // [Bærentzen & Aanæs 2005]
  81. per_face_normals(V,F,FN);
  82. per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
  83. per_edge_normals(
  84. V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP);
  85. break;
  86. case 2:
  87. FN.resize(F.rows(),2);
  88. VN = MatrixXd::Zero(V.rows(),2);
  89. for(int e = 0;e<F.rows();e++)
  90. {
  91. // rotate edge vector
  92. FN(e,0) = -(V(F(e,1),1)-V(F(e,0),1));
  93. FN(e,1) = (V(F(e,1),0)-V(F(e,0),0));
  94. FN.row(e).normalize();
  95. // add to vertex normal
  96. VN.row(F(e,1)) += FN.row(e);
  97. VN.row(F(e,0)) += FN.row(e);
  98. }
  99. // normalize to average
  100. VN.rowwise().normalize();
  101. break;
  102. }
  103. N.resize(P.rows(),dim);
  104. break;
  105. }
  106. S.resize(P.rows(),1);
  107. I.resize(P.rows(),1);
  108. C.resize(P.rows(),dim);
  109. for(int p = 0;p<P.rows();p++)
  110. {
  111. RowVector3d q3;
  112. RowVector2d q2;
  113. switch(P.cols())
  114. {
  115. default:
  116. case 3:
  117. q3 = P.row(p);
  118. break;
  119. case 2:
  120. q2 = P.row(p);
  121. break;
  122. }
  123. double s,sqrd;
  124. RowVectorXd c;
  125. RowVector3d c3;
  126. RowVector2d c2;
  127. int i=-1;
  128. switch(sign_type)
  129. {
  130. default:
  131. assert(false && "Unknown SignedDistanceType");
  132. case SIGNED_DISTANCE_TYPE_UNSIGNED:
  133. s = 1.;
  134. sqrd = dim==3?
  135. tree3.squared_distance(V,F,q3,i,c3):
  136. tree2.squared_distance(V,F,q2,i,c2);
  137. break;
  138. case SIGNED_DISTANCE_TYPE_DEFAULT:
  139. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  140. dim==3 ?
  141. signed_distance_winding_number(tree3,V,F,hier3,q3,s,sqrd,i,c3):
  142. signed_distance_winding_number(tree2,V,F,q2,s,sqrd,i,c2);
  143. break;
  144. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  145. {
  146. RowVector3d n3;
  147. RowVector2d n2;
  148. dim==3 ?
  149. signed_distance_pseudonormal(tree3,V,F,FN,VN,EN,EMAP,q3,s,sqrd,i,c3,n3):
  150. signed_distance_pseudonormal(tree2,V,F,FN,VN,q2,s,sqrd,i,c2,n2);
  151. Eigen::RowVectorXd n;
  152. (dim==3 ? n = n3 : n = n2);
  153. N.row(p) = n;
  154. break;
  155. }
  156. }
  157. I(p) = i;
  158. S(p) = s*sqrt(sqrd);
  159. C.row(p) = (dim==3 ? c=c3 : c=c2);
  160. }
  161. }
  162. IGL_INLINE double igl::signed_distance_pseudonormal(
  163. const AABB<Eigen::MatrixXd,3> & tree,
  164. const Eigen::MatrixXd & V,
  165. const Eigen::MatrixXi & F,
  166. const Eigen::MatrixXd & FN,
  167. const Eigen::MatrixXd & VN,
  168. const Eigen::MatrixXd & EN,
  169. const Eigen::VectorXi & EMAP,
  170. const Eigen::RowVector3d & q)
  171. {
  172. double s,sqrd;
  173. Eigen::RowVector3d n,c;
  174. int i = -1;
  175. signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
  176. return s*sqrt(sqrd);
  177. }
  178. IGL_INLINE void igl::signed_distance_pseudonormal(
  179. const Eigen::MatrixXd & P,
  180. const Eigen::MatrixXd & V,
  181. const Eigen::MatrixXi & F,
  182. const AABB<Eigen::MatrixXd,3> & tree,
  183. const Eigen::MatrixXd & FN,
  184. const Eigen::MatrixXd & VN,
  185. const Eigen::MatrixXd & EN,
  186. const Eigen::VectorXi & EMAP,
  187. Eigen::VectorXd & S,
  188. Eigen::VectorXi & I,
  189. Eigen::MatrixXd & C,
  190. Eigen::MatrixXd & N)
  191. {
  192. using namespace Eigen;
  193. const size_t np = P.rows();
  194. S.resize(np,1);
  195. I.resize(np,1);
  196. N.resize(np,3);
  197. C.resize(np,3);
  198. # pragma omp parallel for if(np>1000)
  199. for(size_t p = 0;p<np;p++)
  200. {
  201. double s,sqrd;
  202. RowVector3d n,c;
  203. int i = -1;
  204. RowVector3d q = P.row(p);
  205. signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
  206. S(p) = s*sqrt(sqrd);
  207. I(p) = i;
  208. N.row(p) = n;
  209. C.row(p) = c;
  210. }
  211. // igl::AABB<MatrixXd,3> tree_P;
  212. // MatrixXi J = VectorXi::LinSpaced(P.rows(),0,P.rows()-1);
  213. // tree_P.init(P,J);
  214. // tree.squared_distance(V,F,tree_P,P,J,S,I,C);
  215. //# pragma omp parallel for if(np>1000)
  216. // for(size_t p = 0;p<np;p++)
  217. // {
  218. // RowVector3d c = C.row(p);
  219. // RowVector3d q = P.row(p);
  220. // const int f = I(p);
  221. // double s;
  222. // RowVector3d n;
  223. // pseudonormal_test(V,F,FN,VN,EN,EMAP,q,f,c,s,n);
  224. // N.row(p) = n;
  225. // S(p) = s*sqrt(S(p));
  226. // }
  227. }
  228. IGL_INLINE void igl::signed_distance_pseudonormal(
  229. const AABB<Eigen::MatrixXd,3> & tree,
  230. const Eigen::MatrixXd & V,
  231. const Eigen::MatrixXi & F,
  232. const Eigen::MatrixXd & FN,
  233. const Eigen::MatrixXd & VN,
  234. const Eigen::MatrixXd & EN,
  235. const Eigen::VectorXi & EMAP,
  236. const Eigen::RowVector3d & q,
  237. double & s,
  238. double & sqrd,
  239. int & f,
  240. Eigen::RowVector3d & c,
  241. Eigen::RowVector3d & n)
  242. {
  243. using namespace Eigen;
  244. using namespace std;
  245. sqrd = tree.squared_distance(V,F,q,f,c);
  246. pseudonormal_test(V,F,FN,VN,EN,EMAP,q,f,c,s,n);
  247. }
  248. IGL_INLINE void igl::signed_distance_pseudonormal(
  249. const AABB<Eigen::MatrixXd,2> & tree,
  250. const Eigen::MatrixXd & V,
  251. const Eigen::MatrixXi & F,
  252. const Eigen::MatrixXd & FN,
  253. const Eigen::MatrixXd & VN,
  254. const Eigen::RowVector2d & q,
  255. double & s,
  256. double & sqrd,
  257. int & f,
  258. Eigen::RowVector2d & c,
  259. Eigen::RowVector2d & n)
  260. {
  261. using namespace Eigen;
  262. using namespace std;
  263. sqrd = tree.squared_distance(V,F,q,f,c);
  264. pseudonormal_test(V,F,FN,VN,q,f,c,s,n);
  265. }
  266. IGL_INLINE double igl::signed_distance_winding_number(
  267. const AABB<Eigen::MatrixXd,3> & tree,
  268. const Eigen::MatrixXd & V,
  269. const Eigen::MatrixXi & F,
  270. const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
  271. const Eigen::RowVector3d & q)
  272. {
  273. double s,sqrd;
  274. Eigen::RowVector3d c;
  275. int i=-1;
  276. signed_distance_winding_number(tree,V,F,hier,q,s,sqrd,i,c);
  277. return s*sqrt(sqrd);
  278. }
  279. IGL_INLINE void igl::signed_distance_winding_number(
  280. const AABB<Eigen::MatrixXd,3> & tree,
  281. const Eigen::MatrixXd & V,
  282. const Eigen::MatrixXi & F,
  283. const igl::WindingNumberAABB<Eigen::Matrix<double,3,1> > & hier,
  284. const Eigen::Matrix<double,1,3> & q,
  285. double & s,
  286. double & sqrd,
  287. int & i,
  288. Eigen::Matrix<double,1,3> & c)
  289. {
  290. using namespace Eigen;
  291. using namespace std;
  292. using namespace igl;
  293. sqrd = tree.squared_distance(V,F,q,i,c);
  294. const double w = hier.winding_number(q.transpose());
  295. s = 1.-2.*w;
  296. }
  297. IGL_INLINE void igl::signed_distance_winding_number(
  298. const AABB<Eigen::MatrixXd,2> & tree,
  299. const Eigen::MatrixXd & V,
  300. const Eigen::MatrixXi & F,
  301. const Eigen::Matrix<double,1,2> & q,
  302. double & s,
  303. double & sqrd,
  304. int & i,
  305. Eigen::Matrix<double,1,2> & c)
  306. {
  307. using namespace Eigen;
  308. using namespace std;
  309. using namespace igl;
  310. sqrd = tree.squared_distance(V,F,q,i,c);
  311. double w;
  312. winding_number_2(V.data(), V.rows(), F.data(), F.rows(), q.data(), 1, &w);
  313. s = 1.-2.*w;
  314. }
  315. #ifdef IGL_STATIC_LIBRARY
  316. // This template is necessary for the others to compile with clang
  317. // http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable
  318. #endif