signed_distance.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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 "get_seconds.h"
  13. #include "point_mesh_squared_distance.h"
  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. // Prepare distance computation
  30. AABB<MatrixXd,3> tree;
  31. tree.init(V,F);
  32. Eigen::MatrixXd FN,VN,EN;
  33. Eigen::MatrixXi E;
  34. Eigen::VectorXi EMAP;
  35. WindingNumberAABB<Eigen::Vector3d> hier;
  36. switch(sign_type)
  37. {
  38. default:
  39. assert(false && "Unknown SignedDistanceType");
  40. case SIGNED_DISTANCE_TYPE_DEFAULT:
  41. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  42. hier.set_mesh(V,F);
  43. hier.grow();
  44. break;
  45. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  46. // "Signed Distance Computation Using the Angle Weighted Pseudonormal"
  47. // [Bærentzen & Aanæs 2005]
  48. per_face_normals(V,F,FN);
  49. per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
  50. per_edge_normals(
  51. V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP);
  52. N.resize(P.rows(),3);
  53. break;
  54. }
  55. S.resize(P.rows(),1);
  56. I.resize(P.rows(),1);
  57. C.resize(P.rows(),3);
  58. for(int p = 0;p<P.rows();p++)
  59. {
  60. const RowVector3d q = P.row(p);
  61. double s,sqrd;
  62. RowVector3d c;
  63. int i=-1;
  64. switch(sign_type)
  65. {
  66. default:
  67. assert(false && "Unknown SignedDistanceType");
  68. case SIGNED_DISTANCE_TYPE_DEFAULT:
  69. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  70. signed_distance_winding_number(tree,V,F,hier,q,s,sqrd,i,c);
  71. break;
  72. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  73. {
  74. Eigen::RowVector3d n;
  75. signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
  76. N.row(p) = n;
  77. break;
  78. }
  79. }
  80. I(p) = i;
  81. S(p) = s*sqrt(sqrd);
  82. C.row(p) = c;
  83. }
  84. }
  85. IGL_INLINE double igl::signed_distance_pseudonormal(
  86. const AABB<Eigen::MatrixXd,3> & tree,
  87. const Eigen::MatrixXd & V,
  88. const Eigen::MatrixXi & F,
  89. const Eigen::MatrixXd & FN,
  90. const Eigen::MatrixXd & VN,
  91. const Eigen::MatrixXd & EN,
  92. const Eigen::VectorXi & EMAP,
  93. const Eigen::RowVector3d & q)
  94. {
  95. double s,sqrd;
  96. Eigen::RowVector3d n,c;
  97. int i = -1;
  98. signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
  99. return s*sqrt(sqrd);
  100. }
  101. IGL_INLINE void igl::signed_distance_pseudonormal(
  102. const AABB<Eigen::MatrixXd,3> & tree,
  103. const Eigen::MatrixXd & V,
  104. const Eigen::MatrixXi & F,
  105. const Eigen::MatrixXd & FN,
  106. const Eigen::MatrixXd & VN,
  107. const Eigen::MatrixXd & EN,
  108. const Eigen::VectorXi & EMAP,
  109. const Eigen::RowVector3d & q,
  110. double & s,
  111. double & sqrd,
  112. int & f,
  113. Eigen::RowVector3d & c,
  114. Eigen::RowVector3d & n)
  115. {
  116. using namespace Eigen;
  117. using namespace std;
  118. sqrd = tree.squared_distance(V,F,q,f,c);
  119. const auto & qc = q-c;
  120. RowVector3d b;
  121. AABB<Eigen::MatrixXd,3>::barycentric_coordinates(
  122. c,V.row(F(f,0)),V.row(F(f,1)),V.row(F(f,2)),b);
  123. // Determine which normal to use
  124. const double epsilon = 1e-12;
  125. const int type = (b.array()<=epsilon).cast<int>().sum();
  126. switch(type)
  127. {
  128. case 2:
  129. // Find vertex
  130. for(int x = 0;x<3;x++)
  131. {
  132. if(b(x)>epsilon)
  133. {
  134. n = VN.row(F(f,x));
  135. break;
  136. }
  137. }
  138. break;
  139. case 1:
  140. // Find edge
  141. for(int x = 0;x<3;x++)
  142. {
  143. if(b(x)<=epsilon)
  144. {
  145. n = EN.row(EMAP(F.rows()*x+f));
  146. break;
  147. }
  148. }
  149. break;
  150. default:
  151. assert(false && "all barycentric coords zero.");
  152. case 0:
  153. n = FN.row(f);
  154. break;
  155. }
  156. s = (qc.dot(n) >= 0 ? 1. : -1.);
  157. }
  158. IGL_INLINE double igl::signed_distance_winding_number(
  159. const AABB<Eigen::MatrixXd,3> & tree,
  160. const Eigen::MatrixXd & V,
  161. const Eigen::MatrixXi & F,
  162. const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
  163. const Eigen::RowVector3d & q)
  164. {
  165. double s,sqrd;
  166. Eigen::RowVector3d c;
  167. int i=-1;
  168. signed_distance_winding_number(tree,V,F,hier,q,s,sqrd,i,c);
  169. return s*sqrt(sqrd);
  170. }
  171. IGL_INLINE void igl::signed_distance_winding_number(
  172. const AABB<Eigen::MatrixXd,3> & tree,
  173. const Eigen::MatrixXd & V,
  174. const Eigen::MatrixXi & F,
  175. const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
  176. const Eigen::RowVector3d & q,
  177. double & s,
  178. double & sqrd,
  179. int & i,
  180. Eigen::RowVector3d & c)
  181. {
  182. using namespace Eigen;
  183. using namespace std;
  184. using namespace igl;
  185. sqrd = tree.squared_distance(V,F,q,i,c);
  186. const double w = hier.winding_number(q.transpose());
  187. s = 1.-2.*w;
  188. }
  189. #ifdef IGL_STATIC_LIBRARY
  190. // This template is necessary for the others to compile with clang
  191. // http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable
  192. #endif