extract_feature.cpp 4.3 KB

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