Browse Source

boundaries

Alec Jacobson 2 years ago
parent
commit
0b0cdea5a6

+ 32 - 4
include/igl/euler_characteristic.cpp

@@ -7,8 +7,9 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "euler_characteristic.h"
 
-#include "edge_topology.h"
-#include "edges.h"
+#include "unique_edge_map.h"
+#include <cassert>
+
 template <typename DerivedF>
 IGL_INLINE int igl::euler_characteristic(
   const Eigen::MatrixBase<DerivedF> & F)
@@ -16,9 +17,36 @@ IGL_INLINE int igl::euler_characteristic(
   const int nf = F.rows();
   const int nv = F.maxCoeff()+1;
   Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,2> E;
-  edges(F,E);
+  Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> EMAP;
+  Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,2> uE;
+  unique_edge_map(F,E,uE,EMAP);
+  // The input is assumed manifold so boundary edges are those with exactly one
+  // incident face
+  Eigen::VectorXi count = Eigen::VectorXi::Zero(uE.rows(),1);
+  for(int e = 0;e<EMAP.size();e++)
+  {
+    count(EMAP(e))++;
+  }
+
+  std::vector<Eigen::Triplet<int> > IJV;
+  for(int u = 0;u<uE.rows();u++)
+  {
+    if(count(u) == 1)
+    {
+      IJV.emplace_back(uE(u,0),uE(u,1),1);
+      IJV.emplace_back(uE(u,1),uE(u,0),1);
+    }
+    assert(count(u) == 2);
+  }
+  Eigen::SparseMatrix<int> A(nv,nv);
+  A.setFromTriplets(IJV.begin(),IJV.end());
+  Eigen::VectorXi _C,_K;
+  // Number of boundary connected components
+  const int nb = connected_components(A,_C,_K);
+  std::cout<<"nb: "<<nb<<std::endl;
+
   const int ne = E.rows();
-  return nv - ne + nf;
+  return nv - ne + nf + nb;
 }
 
 #ifdef IGL_STATIC_LIBRARY

+ 12 - 1
include/igl/euler_characteristic.h

@@ -15,7 +15,18 @@
 #include <vector>
 namespace igl
 {
-  /// Computes the Euler characteristic of a given mesh (V,F)
+  /// Computes the Euler characteristic of a given _manifold_ mesh (V,F) with
+  /// boundary.
+  ///
+  /// V - E + F + B = (2-2g) = χ
+  ///
+  /// With:
+  ///   - V number of vertices (assumed to be F.maxCoeff()+1)
+  ///   - E number of edges
+  ///   - F number of faces
+  ///   - B number of boundary components
+  ///   - g genus
+  ///   - χ Euler characteristic
   ///
   /// @param[in] F #F by dim list of mesh faces (must be triangles)
   /// @return An int containing the Euler characteristic

+ 39 - 0
tests/include/igl/euler_characteristic.h

@@ -0,0 +1,39 @@
+#include <test_common.h>
+#include <igl/euler_characteristic.h>
+
+TEST_CASE("euler_characteristic: cube", "[igl]" )
+{
+  Eigen::MatrixXi F(12,3);
+  F <<
+    0,1,2,
+    0,2,3,
+    0,4,5,
+    0,5,1,
+    0,3,7,
+    0,7,4,
+    6,5,4,
+    6,4,7,
+    6,7,3,
+    6,3,2,
+    6,2,1,
+    6,1,5;
+  const int chi = igl::euler_characteristic(F);
+  REQUIRE(chi == 2);
+}
+
+TEST_CASE("euler_characteristic: square", "[igl]" )
+{
+  Eigen::MatrixXi F;
+  igl::triangulated_grid(3,3,F);
+  const int chi = igl::euler_characteristic(F);
+  REQUIRE(chi == 1);
+}
+
+TEST_CASE("euler_characteristic: torus", "[igl]" )
+{
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi F;
+  igl::read_triangle_mesh(test_common::data_path("TinyTorus.obj"), V, F);
+  const int chi = igl::euler_characteristic(F);
+  REQUIRE(chi == 0);
+}