signed_distance_isosurface.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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_isosurface.h"
  9. #include "point_mesh_squared_distance.h"
  10. #include "complex_to_mesh.h"
  11. #include "../AABB.h"
  12. #include "../per_face_normals.h"
  13. #include "../per_edge_normals.h"
  14. #include "../per_vertex_normals.h"
  15. #include "../centroid.h"
  16. #include "../WindingNumberAABB.h"
  17. #include "../matlab_format.h"
  18. #include <CGAL/Surface_mesh_default_triangulation_3.h>
  19. #include <CGAL/Complex_2_in_triangulation_3.h>
  20. #include <CGAL/make_surface_mesh.h>
  21. #include <CGAL/Implicit_surface_3.h>
  22. #include <CGAL/IO/output_surface_facets_to_polyhedron.h>
  23. // Axis-aligned bounding box tree for tet tri intersection
  24. #include <CGAL/AABB_tree.h>
  25. #include <CGAL/AABB_traits.h>
  26. #include <CGAL/AABB_triangle_primitive.h>
  27. #include <vector>
  28. IGL_INLINE bool igl::cgal::signed_distance_isosurface(
  29. const Eigen::MatrixXd & IV,
  30. const Eigen::MatrixXi & IF,
  31. const double level,
  32. const double angle_bound,
  33. const double radius_bound,
  34. const double distance_bound,
  35. const SignedDistanceType sign_type,
  36. Eigen::MatrixXd & V,
  37. Eigen::MatrixXi & F)
  38. {
  39. using namespace std;
  40. using namespace Eigen;
  41. // default triangulation for Surface_mesher
  42. typedef CGAL::Surface_mesh_default_triangulation_3 Tr;
  43. // c2t3
  44. typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
  45. typedef Tr::Geom_traits GT;//Kernel
  46. typedef GT::Sphere_3 Sphere_3;
  47. typedef GT::Point_3 Point_3;
  48. typedef GT::FT FT;
  49. typedef std::function<FT (Point_3)> Function;
  50. typedef CGAL::Implicit_surface_3<GT, Function> Surface_3;
  51. AABB<Eigen::MatrixXd,3> tree;
  52. tree.init(IV,IF);
  53. Eigen::MatrixXd FN,VN,EN;
  54. Eigen::MatrixXi E;
  55. Eigen::VectorXi EMAP;
  56. WindingNumberAABB<Eigen::Vector3d> hier;
  57. switch(sign_type)
  58. {
  59. default:
  60. assert(false && "Unknown SignedDistanceType");
  61. case SIGNED_DISTANCE_TYPE_UNSIGNED:
  62. // do nothing
  63. break;
  64. case SIGNED_DISTANCE_TYPE_DEFAULT:
  65. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  66. hier.set_mesh(IV,IF);
  67. hier.grow();
  68. break;
  69. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  70. // "Signed Distance Computation Using the Angle Weighted Pseudonormal"
  71. // [Bærentzen & Aanæs 2005]
  72. per_face_normals(IV,IF,FN);
  73. per_vertex_normals(IV,IF,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
  74. per_edge_normals(
  75. IV,IF,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP);
  76. break;
  77. }
  78. Tr tr; // 3D-Delaunay triangulation
  79. C2t3 c2t3 (tr); // 2D-complex in 3D-Delaunay triangulation
  80. // defining the surface
  81. const auto & IVmax = IV.colwise().maxCoeff();
  82. const auto & IVmin = IV.colwise().minCoeff();
  83. const double bbd = (IVmax-IVmin).norm();
  84. const double r = bbd/2.;
  85. const auto & IVmid = 0.5*(IVmax + IVmin);
  86. // Supposedly the implict needs to evaluate to <0 at cmid...
  87. // http://doc.cgal.org/latest/Surface_mesher/classCGAL_1_1Implicit__surface__3.html
  88. Point_3 cmid(IVmid(0),IVmid(1),IVmid(2));
  89. Function fun;
  90. switch(sign_type)
  91. {
  92. default:
  93. assert(false && "Unknown SignedDistanceType");
  94. case SIGNED_DISTANCE_TYPE_UNSIGNED:
  95. fun =
  96. [&tree,&IV,&IF,&level](const Point_3 & q) -> FT
  97. {
  98. int i;
  99. RowVector3d c;
  100. const double sd = tree.squared_distance(
  101. IV,IF,RowVector3d(q.x(),q.y(),q.z()),i,c);
  102. return sd-level;
  103. };
  104. case SIGNED_DISTANCE_TYPE_DEFAULT:
  105. case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
  106. fun =
  107. [&tree,&IV,&IF,&hier,&level](const Point_3 & q) -> FT
  108. {
  109. const double sd = signed_distance_winding_number(
  110. tree,IV,IF,hier,RowVector3d(q.x(),q.y(),q.z()));
  111. return sd-level;
  112. };
  113. break;
  114. case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
  115. fun = [&tree,&IV,&IF,&FN,&VN,&EN,&EMAP,&level](const Point_3 & q) -> FT
  116. {
  117. const double sd =
  118. igl::signed_distance_pseudonormal(
  119. tree,IV,IF,FN,VN,EN,EMAP,RowVector3d(q.x(),q.y(),q.z()));
  120. return sd- level;
  121. };
  122. break;
  123. }
  124. Sphere_3 bounding_sphere(cmid, (r+level)*(r+level));
  125. Surface_3 surface(fun,bounding_sphere);
  126. CGAL::Surface_mesh_default_criteria_3<Tr>
  127. criteria(angle_bound,radius_bound,distance_bound);
  128. // meshing surface
  129. CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Manifold_tag());
  130. // complex to (V,F)
  131. return igl::cgal::complex_to_mesh(c2t3,V,F);
  132. }