Browse Source

Add support for extracting feature edges based on dihedral angle.

Former-commit-id: fd2f7f4a0e90fd3f94939e596b947f465070a81a
Qingnan Zhou 8 years ago
parent
commit
9691fca43e

+ 122 - 0
include/igl/copyleft/cgal/extract_feature.cpp

@@ -0,0 +1,122 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "extract_feature.h"
+#include <igl/unique_edge_map.h>
+#include <CGAL/Kernel/global_functions.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+template<
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedE >
+IGL_INLINE void igl::copyleft::cgal::extract_feature(
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedF>& F,
+    const double tol,
+    Eigen::PlainObjectBase<DerivedE>& feature_edges) {
+
+  using IndexType = typename DerivedE::Scalar;
+  DerivedE E, uE;
+  Eigen::VectorXi EMAP;
+  std::vector<std::vector<IndexType> > uE2E;
+  igl::unique_edge_map(F, E, uE, EMAP, uE2E);
+
+  igl::copyleft::cgal::extract_feature(V, F, tol, E, uE, uE2E, feature_edges);
+}
+
+template<
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedE >
+IGL_INLINE void igl::copyleft::cgal::extract_feature(
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedF>& F,
+    const double tol,
+    const Eigen::PlainObjectBase<DerivedE>& E,
+    const Eigen::PlainObjectBase<DerivedE>& uE,
+    const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
+    Eigen::PlainObjectBase<DerivedE>& feature_edges) {
+
+  assert(V.cols() == 3);
+  assert(F.cols() == 3);
+  using Scalar = typename DerivedV::Scalar;
+  using IndexType = typename DerivedE::Scalar;
+  using Vertex = Eigen::Matrix<Scalar, 3, 1>;
+  using Kernel = typename CGAL::Exact_predicates_exact_constructions_kernel;
+  using Point = typename Kernel::Point_3;
+
+  const size_t num_unique_edges = uE.rows();
+  const size_t num_faces = F.rows();
+  // NOTE: CGAL's definition of dihedral angle measures the angle between two
+  // facets instead of facet normals.
+  const double cos_tol = cos(M_PI - tol);
+  std::vector<size_t> result; // Indices into uE
+
+  auto is_non_manifold = [&uE2E](size_t ei) -> bool {
+    return uE2E[ei].size() > 2;
+  };
+
+  auto is_boundary = [&uE2E](size_t ei) -> bool {
+    return uE2E[ei].size() == 1;
+  };
+
+  auto opposite_vertex = [&uE, &F](size_t ei, size_t fi) -> IndexType {
+    const size_t v0 = uE(ei, 0);
+    const size_t v1 = uE(ei, 1);
+    for (size_t i=0; i<3; i++) {
+      const size_t v = F(fi, i);
+      if (v != v0 && v != v1) { return v; }
+    }
+    throw "Input face must be topologically degenerate!";
+  };
+
+  auto is_feature = [&V, &F, &uE, &uE2E, &opposite_vertex, num_faces](
+      size_t ei, double cos_tol) -> bool {
+    auto adj_faces = uE2E[ei];
+    assert(adj_faces.size() == 2);
+    const Vertex v0 = V.row(uE(ei, 0));
+    const Vertex v1 = V.row(uE(ei, 1));
+    const Vertex v2 = V.row(opposite_vertex(ei, adj_faces[0] % num_faces));
+    const Vertex v3 = V.row(opposite_vertex(ei, adj_faces[1] % num_faces));
+    const Point p0(v0[0], v0[1], v0[2]);
+    const Point p1(v1[0], v1[1], v1[2]);
+    const Point p2(v2[0], v2[1], v2[2]);
+    const Point p3(v3[0], v3[1], v3[2]);
+    const auto ori = CGAL::orientation(p0, p1, p2, p3);
+    switch (ori) {
+      case CGAL::POSITIVE:
+        return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
+          CGAL::SMALLER;
+      case CGAL::NEGATIVE:
+        return CGAL::compare_dihedral_angle(p0, p1, p3, p2, cos_tol) ==
+          CGAL::SMALLER;
+      case CGAL::COPLANAR:
+        if (!CGAL::collinear(p0, p1, p2) && CGAL::collinear(p0, p1, p3)) {
+          return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
+            CGAL::SMALLER;
+        } else {
+          return false;
+        }
+      default:
+        throw "Unknown CGAL orientation";
+    }
+  };
+
+  for (size_t i=0; i<num_unique_edges; i++) {
+    if (is_boundary(i) || is_non_manifold(i) || is_feature(i, cos_tol)) {
+      result.push_back(i);
+    }
+  }
+
+  const size_t num_feature_edges = result.size();
+  feature_edges.resize(num_feature_edges, 2);
+  for (size_t i=0; i<num_feature_edges; i++) {
+    feature_edges.row(i) = uE.row(result[i]);
+  }
+}

+ 72 - 0
include/igl/copyleft/cgal/extract_feature.h

@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H
+#define IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+  namespace copyleft
+  {
+    namespace cgal
+    {
+      // Extract feature edges based on dihedral angle.
+      // Here, dihedral angle is defined as the angle between surface
+      // __normals__ as described in
+      // http://mathworld.wolfram.com/DihedralAngle.html
+      //
+      // Non-manifold and boundary edges are automatically considered as
+      // features.
+      //
+      // Inputs:
+      //   V   #V by 3 array of vertices.
+      //   F   #F by 3 array of faces.
+      //   tol Edges with dihedral angle larger than this are considered
+      //       as features.  Angle is measured in radian.
+      //
+      // Output:
+      //   feature_edges: #E by 2 array of edges.  Each edge satisfies at
+      //      least one of the following criteria:
+      //
+      //      * Edge has dihedral angle larger than tol.
+      //      * Edge is boundary.
+      //      * Edge is non-manifold (i.e. it has more than 2 adjacent
+      //        faces).
+      template <
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedE>
+      IGL_INLINE void extract_feature(
+            const Eigen::PlainObjectBase<DerivedV>& V,
+            const Eigen::PlainObjectBase<DerivedF>& F,
+            const double tol,
+            Eigen::PlainObjectBase<DerivedE>& feature_edges);
+
+      template <
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedE>
+      IGL_INLINE void extract_feature(
+            const Eigen::PlainObjectBase<DerivedV>& V,
+            const Eigen::PlainObjectBase<DerivedF>& F,
+            const double tol,
+            const Eigen::PlainObjectBase<DerivedE>& E,
+            const Eigen::PlainObjectBase<DerivedE>& uE,
+            const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
+            Eigen::PlainObjectBase<DerivedE>& feature_edges);
+    }
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "extract_feature.cpp"
+#endif
+#endif