extract_feature.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 Qingnan Zhou <qnzhou@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 "extract_feature.h"
  9. #include "../../unique_edge_map.h"
  10. #include "../../PI.h"
  11. #include <CGAL/Kernel/global_functions.h>
  12. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  13. template<
  14. typename DerivedV,
  15. typename DerivedF,
  16. typename DerivedE >
  17. IGL_INLINE void igl::copyleft::cgal::extract_feature(
  18. const Eigen::PlainObjectBase<DerivedV>& V,
  19. const Eigen::PlainObjectBase<DerivedF>& F,
  20. const double tol,
  21. Eigen::PlainObjectBase<DerivedE>& feature_edges) {
  22. using IndexType = typename DerivedE::Scalar;
  23. DerivedE E, uE;
  24. Eigen::VectorXi EMAP;
  25. std::vector<std::vector<IndexType> > uE2E;
  26. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  27. igl::copyleft::cgal::extract_feature(V, F, tol, E, uE, uE2E, feature_edges);
  28. }
  29. template<
  30. typename DerivedV,
  31. typename DerivedF,
  32. typename DerivedE >
  33. IGL_INLINE void igl::copyleft::cgal::extract_feature(
  34. const Eigen::PlainObjectBase<DerivedV>& V,
  35. const Eigen::PlainObjectBase<DerivedF>& F,
  36. const double tol,
  37. const Eigen::PlainObjectBase<DerivedE>& E,
  38. const Eigen::PlainObjectBase<DerivedE>& uE,
  39. const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
  40. Eigen::PlainObjectBase<DerivedE>& feature_edges) {
  41. assert(V.cols() == 3);
  42. assert(F.cols() == 3);
  43. using Scalar = typename DerivedV::Scalar;
  44. using IndexType = typename DerivedE::Scalar;
  45. using Vertex = Eigen::Matrix<Scalar, 3, 1>;
  46. using Kernel = typename CGAL::Exact_predicates_exact_constructions_kernel;
  47. using Point = typename Kernel::Point_3;
  48. const size_t num_unique_edges = uE.rows();
  49. const size_t num_faces = F.rows();
  50. // NOTE: CGAL's definition of dihedral angle measures the angle between two
  51. // facets instead of facet normals.
  52. const double cos_tol = cos(igl::PI - tol);
  53. std::vector<size_t> result; // Indices into uE
  54. auto is_non_manifold = [&uE2E](size_t ei) -> bool {
  55. return uE2E[ei].size() > 2;
  56. };
  57. auto is_boundary = [&uE2E](size_t ei) -> bool {
  58. return uE2E[ei].size() == 1;
  59. };
  60. auto opposite_vertex = [&uE, &F](size_t ei, size_t fi) -> IndexType {
  61. const size_t v0 = uE(ei, 0);
  62. const size_t v1 = uE(ei, 1);
  63. for (size_t i=0; i<3; i++) {
  64. const size_t v = F(fi, i);
  65. if (v != v0 && v != v1) { return v; }
  66. }
  67. throw "Input face must be topologically degenerate!";
  68. };
  69. auto is_feature = [&V, &F, &uE, &uE2E, &opposite_vertex, num_faces](
  70. size_t ei, double cos_tol) -> bool {
  71. auto adj_faces = uE2E[ei];
  72. assert(adj_faces.size() == 2);
  73. const Vertex v0 = V.row(uE(ei, 0));
  74. const Vertex v1 = V.row(uE(ei, 1));
  75. const Vertex v2 = V.row(opposite_vertex(ei, adj_faces[0] % num_faces));
  76. const Vertex v3 = V.row(opposite_vertex(ei, adj_faces[1] % num_faces));
  77. const Point p0(v0[0], v0[1], v0[2]);
  78. const Point p1(v1[0], v1[1], v1[2]);
  79. const Point p2(v2[0], v2[1], v2[2]);
  80. const Point p3(v3[0], v3[1], v3[2]);
  81. const auto ori = CGAL::orientation(p0, p1, p2, p3);
  82. switch (ori) {
  83. case CGAL::POSITIVE:
  84. return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
  85. CGAL::SMALLER;
  86. case CGAL::NEGATIVE:
  87. return CGAL::compare_dihedral_angle(p0, p1, p3, p2, cos_tol) ==
  88. CGAL::SMALLER;
  89. case CGAL::COPLANAR:
  90. if (!CGAL::collinear(p0, p1, p2) && !CGAL::collinear(p0, p1, p3)) {
  91. return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
  92. CGAL::SMALLER;
  93. } else {
  94. throw "Dihedral angle (and feature edge) is not well defined for"
  95. " degenerate triangles!";
  96. }
  97. default:
  98. throw "Unknown CGAL orientation";
  99. }
  100. };
  101. for (size_t i=0; i<num_unique_edges; i++) {
  102. if (is_boundary(i) || is_non_manifold(i) || is_feature(i, cos_tol)) {
  103. result.push_back(i);
  104. }
  105. }
  106. const size_t num_feature_edges = result.size();
  107. feature_edges.resize(num_feature_edges, 2);
  108. for (size_t i=0; i<num_feature_edges; i++) {
  109. feature_edges.row(i) = uE.row(result[i]);
  110. }
  111. }