signed_distance.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 "../per_vertex_normals.h"
  10. #include "../per_edge_normals.h"
  11. #include "../per_face_normals.h"
  12. #include "point_mesh_squared_distance.h"
  13. template <typename Kernel>
  14. IGL_INLINE void igl::signed_distance(
  15. const Eigen::MatrixXd & P,
  16. const Eigen::MatrixXd & V,
  17. const Eigen::MatrixXi & F,
  18. const SignedDistanceType sign_type,
  19. Eigen::VectorXd & S,
  20. Eigen::VectorXi & I,
  21. Eigen::MatrixXd & C,
  22. Eigen::MatrixXd & N)
  23. {
  24. using namespace Eigen;
  25. using namespace std;
  26. assert(V.cols() == 3 && "V should have 3d positions");
  27. assert(P.cols() == 3 && "P should have 3d positions");
  28. assert(F.cols() == 3 && "F should have triangles");
  29. typedef typename Kernel::FT FT;
  30. typedef typename Kernel::Point_3 Point_3;
  31. typedef typename CGAL::Triangle_3<Kernel> Triangle_3;
  32. typedef typename std::vector<Triangle_3>::iterator Iterator;
  33. typedef typename CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
  34. typedef typename CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
  35. typedef typename CGAL::AABB_tree<AABB_triangle_traits> Tree;
  36. typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
  37. // Prepare distance computation
  38. Tree tree;
  39. vector<Triangle_3 > T;
  40. point_mesh_squared_distance_precompute(V,F,tree,T);
  41. Eigen::MatrixXd FN,VN,EN;
  42. Eigen::MatrixXi E;
  43. Eigen::VectorXi EMAP;
  44. WindingNumberAABB<Eigen::Vector3d> hier;
  45. switch(sign_type)
  46. {
  47. default:
  48. assert(false && "Unknown SignedDistanceType");
  49. case SIGNED_DISTANCE_TYPE_DEFAULT:
  50. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  51. hier.set_mesh(V,F);
  52. hier.grow();
  53. break;
  54. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  55. // "Signed Distance Computation Using the Angle Weighted Pseudonormal"
  56. // [Bærentzen & Aanæs 2005]
  57. per_face_normals(V,F,FN);
  58. per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
  59. per_edge_normals(
  60. V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,EN,E,EMAP);
  61. N.resize(P.rows(),3);
  62. break;
  63. }
  64. S.resize(P.rows(),1);
  65. I.resize(P.rows(),1);
  66. C.resize(P.rows(),3);
  67. for(int p = 0;p<P.rows();p++)
  68. {
  69. const Point_3 q(P(p,0),P(p,1),P(p,2));
  70. double s,sqrd;
  71. Point_and_primitive_id pp;
  72. switch(sign_type)
  73. {
  74. default:
  75. assert(false && "Unknown SignedDistanceType");
  76. case SIGNED_DISTANCE_TYPE_DEFAULT:
  77. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  78. signed_distance_winding_number(tree,hier,q,s,sqrd,pp);
  79. break;
  80. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  81. {
  82. Vector3d n(0,0,0);
  83. signed_distance_pseudonormal(tree,T,F,FN,VN,EN,EMAP,q,s,sqrd,pp,n);
  84. N.row(p) = n;
  85. break;
  86. }
  87. }
  88. I(p) = pp.second - T.begin();
  89. S(p) = s*sqrt(sqrd);
  90. C(p,0) = pp.first.x();
  91. C(p,1) = pp.first.y();
  92. C(p,2) = pp.first.z();
  93. }
  94. }
  95. template <typename Kernel>
  96. IGL_INLINE typename Kernel::FT igl::signed_distance_pseudonormal(
  97. const CGAL::AABB_tree<
  98. CGAL::AABB_traits<Kernel,
  99. CGAL::AABB_triangle_primitive<Kernel,
  100. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
  101. >
  102. >
  103. > & tree,
  104. const std::vector<CGAL::Triangle_3<Kernel> > & T,
  105. const Eigen::MatrixXi & F,
  106. const Eigen::MatrixXd & FN,
  107. const Eigen::MatrixXd & VN,
  108. const Eigen::MatrixXd & EN,
  109. const Eigen::VectorXi & EMAP,
  110. const typename Kernel::Point_3 & q)
  111. {
  112. typename CGAL::AABB_tree<
  113. CGAL::AABB_traits<Kernel,
  114. CGAL::AABB_triangle_primitive<Kernel,
  115. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator>
  116. >
  117. >::Point_and_primitive_id pp;
  118. typename Kernel::FT s,sqrd;
  119. Eigen::Vector3d n(0,0,0);
  120. signed_distance_pseudonormal<Kernel>(tree,T,F,FN,VN,EN,EMAP,q,s,sqrd,pp,n);
  121. return s*sqrt(sqrd);
  122. }
  123. template <typename Kernel>
  124. IGL_INLINE void igl::signed_distance_pseudonormal(
  125. const CGAL::AABB_tree<
  126. CGAL::AABB_traits<Kernel,
  127. CGAL::AABB_triangle_primitive<Kernel,
  128. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
  129. >
  130. >
  131. > & tree,
  132. const std::vector<CGAL::Triangle_3<Kernel> > & T,
  133. const Eigen::MatrixXi & F,
  134. const Eigen::MatrixXd & FN,
  135. const Eigen::MatrixXd & VN,
  136. const Eigen::MatrixXd & EN,
  137. const Eigen::VectorXi & EMAP,
  138. const typename Kernel::Point_3 & q,
  139. typename Kernel::FT & s,
  140. typename Kernel::FT & sqrd,
  141. typename CGAL::AABB_tree<
  142. CGAL::AABB_traits<Kernel,
  143. CGAL::AABB_triangle_primitive<Kernel,
  144. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator>
  145. >
  146. >::Point_and_primitive_id & pp,
  147. Eigen::Vector3d & n)
  148. {
  149. using namespace Eigen;
  150. using namespace std;
  151. typedef typename Kernel::FT FT;
  152. typedef typename Kernel::Point_3 Point_3;
  153. typedef typename CGAL::Triangle_3<Kernel> Triangle_3;
  154. typedef typename std::vector<Triangle_3>::iterator Iterator;
  155. typedef typename CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
  156. typedef typename CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
  157. typedef typename CGAL::AABB_tree<AABB_triangle_traits> Tree;
  158. typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
  159. pp = tree.closest_point_and_primitive(q);
  160. Point_3 & p = pp.first;
  161. const auto & qp = q-p;
  162. sqrd = qp.squared_length();
  163. Vector3d v(qp.x(),qp.y(),qp.z());
  164. const int f = pp.second - T.begin();
  165. const Triangle_3 & t = *pp.second;
  166. // barycentric coordinates
  167. const auto & area = [&p,&t](const int i, const int j)->FT
  168. {
  169. return sqrt(Triangle_3(p,t.vertex(i),t.vertex(j)).squared_area());
  170. };
  171. Vector3d b(area(1,2),area(2,0),area(0,1));
  172. b /= b.sum();
  173. // Determine which normal to use
  174. const double epsilon = 1e-12;
  175. const int type = (b.array()<=epsilon).cast<int>().sum();
  176. switch(type)
  177. {
  178. case 2:
  179. // Find vertex
  180. for(int c = 0;c<3;c++)
  181. {
  182. if(b(c)>epsilon)
  183. {
  184. n = VN.row(F(f,c));
  185. break;
  186. }
  187. }
  188. break;
  189. case 1:
  190. // Find edge
  191. for(int c = 0;c<3;c++)
  192. {
  193. if(b(c)<=epsilon)
  194. {
  195. n = EN.row(EMAP(F.rows()*c+f));
  196. break;
  197. }
  198. }
  199. break;
  200. default:
  201. assert(false && "all barycentric coords zero.");
  202. case 0:
  203. n = FN.row(f);
  204. break;
  205. }
  206. s = (v.dot(n) >= 0 ? 1. : -1.);
  207. }
  208. template <typename Kernel>
  209. IGL_INLINE typename Kernel::FT igl::signed_distance_winding_number(
  210. const CGAL::AABB_tree<
  211. CGAL::AABB_traits<Kernel,
  212. CGAL::AABB_triangle_primitive<Kernel,
  213. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
  214. >
  215. >
  216. > & tree,
  217. const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
  218. const typename Kernel::Point_3 & q)
  219. {
  220. typename CGAL::AABB_tree<
  221. CGAL::AABB_traits<Kernel,
  222. CGAL::AABB_triangle_primitive<Kernel,
  223. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator>
  224. >
  225. >::Point_and_primitive_id pp;
  226. typename Kernel::FT s,sqrd;
  227. signed_distance_winding_number<Kernel>(tree,hier,q,s,sqrd,pp);
  228. return s*sqrt(sqrd);
  229. }
  230. template <typename Kernel>
  231. IGL_INLINE void igl::signed_distance_winding_number(
  232. const CGAL::AABB_tree<
  233. CGAL::AABB_traits<Kernel,
  234. CGAL::AABB_triangle_primitive<Kernel,
  235. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
  236. >
  237. >
  238. > & tree,
  239. const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
  240. const typename Kernel::Point_3 & q,
  241. typename Kernel::FT & s,
  242. typename Kernel::FT & sqrd,
  243. typename CGAL::AABB_tree<
  244. CGAL::AABB_traits<Kernel,
  245. CGAL::AABB_triangle_primitive<Kernel,
  246. typename std::vector<CGAL::Triangle_3<Kernel> >::iterator>
  247. >
  248. >::Point_and_primitive_id & pp)
  249. {
  250. typedef typename Kernel::FT FT;
  251. typedef typename Kernel::Point_3 Point_3;
  252. typedef typename CGAL::Triangle_3<Kernel> Triangle_3;
  253. typedef typename std::vector<Triangle_3>::iterator Iterator;
  254. typedef typename CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
  255. typedef typename CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
  256. typedef typename CGAL::AABB_tree<AABB_triangle_traits> Tree;
  257. typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
  258. using namespace Eigen;
  259. using namespace std;
  260. using namespace igl;
  261. pp = tree.closest_point_and_primitive(q);
  262. Point_3 & p = pp.first;
  263. const auto & qp = q-p;
  264. const Vector3d eq(q.x(),q.y(),q.z());
  265. sqrd = qp.squared_length();
  266. const double w = hier.winding_number(eq);
  267. s = 1.-2.*w;
  268. }
  269. #ifdef IGL_STATIC_LIBRARY
  270. template CGAL::Epick::FT igl::signed_distance_winding_number<CGAL::Epick>(CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epick, CGAL::AABB_triangle_primitive<CGAL::Epick, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >::iterator, CGAL::Boolean_tag<false> > > > const&, igl::WindingNumberAABB<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, CGAL::Epick::Point_3 const&);
  271. template CGAL::Epick::FT igl::signed_distance_pseudonormal<CGAL::Epick>(CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epick, CGAL::AABB_triangle_primitive<CGAL::Epick, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >::iterator, CGAL::Boolean_tag<false> > > > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, CGAL::Epick::Point_3 const&);
  272. #endif