Browse Source

refactor cut_mesh

Hank Shen 6 years ago
parent
commit
b4faebf34e
4 changed files with 250 additions and 355 deletions
  1. 4 0
      include/igl/HalfEdgeIterator.cpp
  2. 122 310
      include/igl/cut_mesh.cpp
  3. 36 45
      include/igl/cut_mesh.h
  4. 88 0
      tests/include/igl/cut_mesh.cpp

+ 4 - 0
include/igl/HalfEdgeIterator.cpp

@@ -150,9 +150,13 @@ template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen:
 template      igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
 template      igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
 template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
 template int  igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipE();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipE();
+template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipE();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipF();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipF();
+template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::flipF();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipV();
 template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipV();
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::operator==(igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::operator==(igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
 template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
 template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >::isBorder();
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::isBorder();
 #endif
 #endif

+ 122 - 310
include/igl/cut_mesh.cpp

@@ -1,330 +1,142 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2016 Alec Jacobson <[email protected]>
-// 
-// 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 
+//
+// Copyright (C) 2019 Hanxiao Shen <[email protected]>
+//
+// 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include <igl/cut_mesh.h>
 #include <igl/cut_mesh.h>
-#include <igl/vertex_triangle_adjacency.h>
 #include <igl/triangle_triangle_adjacency.h>
 #include <igl/triangle_triangle_adjacency.h>
-#include <igl/is_border_vertex.h>
 #include <igl/HalfEdgeIterator.h>
 #include <igl/HalfEdgeIterator.h>
-#include <set>
-
-// This file violates many of the libigl style guidelines.
-
-namespace igl {
-
-
-  template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-  class MeshCutterMini
-  {
-  public:
-    // Input
-    //mesh
-    const Eigen::PlainObjectBase<DerivedV> &V;
-    const Eigen::PlainObjectBase<DerivedF> &F;
-    // TT is the same type as TTi? This is likely to break at some point
-    const Eigen::PlainObjectBase<DerivedTT> &TT;
-    const Eigen::PlainObjectBase<DerivedTT> &TTi;
-    const std::vector<std::vector<VFType> >& VF;
-    const std::vector<std::vector<VFType> >& VFi;
-    const std::vector<bool> &V_border; // bool
-    //edges to cut
-    const Eigen::PlainObjectBase<DerivedC> &Handle_Seams; // 3 bool
-
-    // total number of scalar variables
-    int num_scalar_variables;
-
-    // per face indexes of vertex in the solver
-    DerivedF HandleS_Index;
-
-    // per vertex variable indexes
-    std::vector<std::vector<int> > HandleV_Integer;
-
-    IGL_INLINE MeshCutterMini(
-      const Eigen::PlainObjectBase<DerivedV> &_V,
-      const Eigen::PlainObjectBase<DerivedF> &_F,
-      const Eigen::PlainObjectBase<DerivedTT> &_TT,
-      const Eigen::PlainObjectBase<DerivedTT> &_TTi,
-      const std::vector<std::vector<VFType> > &_VF,
-      const std::vector<std::vector<VFType> > &_VFi,
-      const std::vector<bool> &_V_border,
-      const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams);
-
-    // vertex to variable mapping
-    // initialize the mapping for a given sampled mesh
-    IGL_INLINE void InitMappingSeam();
-
-  private:
-
-    IGL_INLINE void FirstPos(const int v, int &f, int &edge);
-
-    IGL_INLINE int AddNewIndex(const int v0);
-
-    IGL_INLINE bool IsSeam(const int f0, const int f1);
-
-    // find initial position of the pos to
-    // assing face to vert inxex correctly
-    IGL_INLINE void FindInitialPos(const int vert, int &edge, int &face);
-
-
-    // initialize the mapping given an initial pos
-    // whih must be initialized with FindInitialPos
-    IGL_INLINE void MapIndexes(const int  vert, const int edge_init, const int f_init);
-
-    // initialize the mapping for a given vertex
-    IGL_INLINE void InitMappingSeam(const int vert);
-
-  };
-}
-
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-MeshCutterMini(
-  const Eigen::PlainObjectBase<DerivedV> &_V,
-  const Eigen::PlainObjectBase<DerivedF> &_F,
-  const Eigen::PlainObjectBase<DerivedTT> &_TT,
-  const Eigen::PlainObjectBase<DerivedTT> &_TTi,
-  const std::vector<std::vector<VFType> > &_VF,
-  const std::vector<std::vector<VFType> > &_VFi,
-  const std::vector<bool> &_V_border,
-  const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams):
-  V(_V),
-  F(_F),
-  TT(_TT),
-  TTi(_TTi),
-  VF(_VF),
-  VFi(_VFi),
-  V_border(_V_border),
-  Handle_Seams(_Handle_Seams)
-{
-  num_scalar_variables=0;
-  HandleS_Index.setConstant(F.rows(),3,-1);
-  HandleV_Integer.resize(V.rows());
-}
-
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-FirstPos(const int v, int &f, int &edge)
-{
-  f    = VF[v][0];  // f=v->cVFp();
-  edge = VFi[v][0]; // edge=v->cVFi();
-}
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE int igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-AddNewIndex(const int v0)
-{
-  num_scalar_variables++;
-  HandleV_Integer[v0].push_back(num_scalar_variables);
-  return num_scalar_variables;
-}
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE bool igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-IsSeam(const int f0, const int f1)
-{
-  for (int i=0;i<3;i++)
-  {
-    int f_clos = TT(f0,i);
-
-    if (f_clos == -1)
-      continue; ///border
+#include <igl/is_border_vertex.h>
 
 
-    if (f_clos == f1)
-      return(Handle_Seams(f0,i));
-  }
-  assert(0);
-  return false;
+// wrapper for input/output style
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::cut_mesh(
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedC>& C,
+  Eigen::PlainObjectBase<DerivedV>& Vn,
+  Eigen::PlainObjectBase<DerivedF>& Fn
+){
+  Vn = V;
+  Fn = F;
+  typedef typename DerivedF::Scalar Index;
+  Eigen::Matrix<Index,Eigen::Dynamic,1> _I;
+  cut_mesh(Vn,Fn,C,_I);
 }
 }
 
 
-///find initial position of the pos to
-// assing face to vert inxex correctly
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-FindInitialPos(const int vert,
-               int &edge,
-               int &face)
-{
-  int f_init;
-  int edge_init;
-  FirstPos(vert,f_init,edge_init); // todo manually the function
-  igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
-
-  bool vertexB = V_border[vert];
-  bool possible_split=false;
-  bool complete_turn=false;
-  do
-  {
-    int curr_f = VFI.Fi();
-    int curr_edge=VFI.Ei();
-    VFI.NextFE();
-    int next_f=VFI.Fi();
-    ///test if I've just crossed a border
-    bool on_border=(TT(curr_f,curr_edge)==-1);
-    //bool mismatch=false;
-    bool seam=false;
-
-    ///or if I've just crossed a seam
-    ///if I'm on a border I MUST start from the one next t othe border
-    if (!vertexB)
-      //seam=curr_f->IsSeam(next_f);
-      seam=IsSeam(curr_f,next_f);
-    //    if (vertexB)
-    //      assert(!Handle_Singular(vert));
-    //    ;
-    //assert(!vert->IsSingular());
-    possible_split=((on_border)||(seam));
-    complete_turn = next_f == f_init;
-  } while ((!possible_split)&&(!complete_turn));
-  face=VFI.Fi();
-  edge=VFI.Ei();
+template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
+IGL_INLINE void igl::cut_mesh(
+  const Eigen::MatrixBase<DerivedV>& V,
+  const Eigen::MatrixBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedC>& C,
+  Eigen::PlainObjectBase<DerivedV>& Vn,
+  Eigen::PlainObjectBase<DerivedF>& Fn,
+  Eigen::PlainObjectBase<DerivedI>& I
+){
+  Vn = V;
+  Fn = F;
+  cut_mesh(Vn,Fn,C,I);
 }
 }
 
 
 
 
-
-///initialize the mapping given an initial pos
-///whih must be initialized with FindInitialPos
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-MapIndexes(const int  vert,
-           const int edge_init,
-           const int f_init)
-{
-  ///check that is not on border..
-  ///in such case maybe it's non manyfold
-  ///insert an initial index
-  int curr_index=AddNewIndex(vert);
-  ///and initialize the jumping pos
-  igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
-  bool complete_turn=false;
-  do
-  {
-    int curr_f = VFI.Fi();
-    int curr_edge = VFI.Ei();
-    ///assing the current index
-    HandleS_Index(curr_f,curr_edge) = curr_index;
-    VFI.NextFE();
-    int next_f = VFI.Fi();
-    ///test if I've finiseh with the face exploration
-    complete_turn = (next_f==f_init);
-    ///or if I've just crossed a mismatch
-    if (!complete_turn)
-    {
-      bool seam=false;
-      //seam=curr_f->IsSeam(next_f);
-      seam=IsSeam(curr_f,next_f);
-      if (seam)
-      {
-        ///then add a new index
-        curr_index=AddNewIndex(vert);
+template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
+IGL_INLINE void igl::cut_mesh(
+  Eigen::PlainObjectBase<DerivedV>& V,
+  Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::MatrixBase<DerivedC>& C,
+  Eigen::PlainObjectBase<DerivedI>& I
+){
+
+  typedef typename DerivedF::Scalar Index;
+  DerivedF FF, FFi;
+  igl::triangle_triangle_adjacency(F,FF,FFi);
+
+  // store current number of occurance of each vertex as the alg proceed
+  Eigen::Matrix<Index,Eigen::Dynamic,1> o(V.rows());
+  o.setConstant(1);
+  
+  // set target number of occurance of each vertex
+  Eigen::Matrix<Index,Eigen::Dynamic,1> g(V.rows());
+  g.setZero();
+  for(Index i=0;i<F.rows();i++){
+    for(Index k=0;k<3;k++){
+      if(C(i,k) == 1){
+        Index u = F(i,k);
+        Index v = F(i,(k+1)%3);
+        if(FF(i,k) == -1) continue;
+        if(u > v) continue; // only compute every (undirected) edge ones
+        g(u) += 1;
+        g(v) += 1;
       }
       }
     }
     }
-  } while (!complete_turn);
-}
-
-///initialize the mapping for a given vertex
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-InitMappingSeam(const int vert)
-{
-  ///first rotate until find the first pos after a mismatch
-  ///or a border or return to the first position...
-  int f_init = VF[vert][0];
-  int indexE = VFi[vert][0];
-
-  igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,indexE);
-
-  int edge_init;
-  int face_init;
-  FindInitialPos(vert,edge_init,face_init);
-  MapIndexes(vert,edge_init,face_init);
-}
-
-///vertex to variable mapping
-///initialize the mapping for a given sampled mesh
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
-InitMappingSeam()
-{
-  num_scalar_variables=-1;
-  for (unsigned int i=0;i<V.rows();i++)
-    InitMappingSeam(i);
-
-  for (unsigned int j=0;j<V.rows();j++)
-    assert(HandleV_Integer[j].size()>0);
-}
-
-
-template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
-IGL_INLINE void igl::cut_mesh(
-  const Eigen::PlainObjectBase<DerivedV> &V,
-  const Eigen::PlainObjectBase<DerivedF> &F,
-  const std::vector<std::vector<VFType> >& VF,
-  const std::vector<std::vector<VFType> >& VFi,
-  const Eigen::PlainObjectBase<DerivedTT>& TT,
-  const Eigen::PlainObjectBase<DerivedTT>& TTi,
-  const std::vector<bool> &V_border,
-  const Eigen::PlainObjectBase<DerivedC> &cuts,
-  Eigen::PlainObjectBase<DerivedV> &Vcut,
-  Eigen::PlainObjectBase<DerivedF> &Fcut)
-{
-  //finding the cuts is done, now we need to actually generate a cut mesh
-  igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC> mc(V, F, TT, TTi, VF, VFi, V_border, cuts);
-  mc.InitMappingSeam();
-
-  Fcut = mc.HandleS_Index;
-  //we have the faces, we need the vertices;
-  int newNumV = Fcut.maxCoeff()+1;
-  Vcut.setZero(newNumV,3);
-  for (int vi=0; vi<V.rows(); ++vi)
-    for (int i=0; i<mc.HandleV_Integer[vi].size();++i)
-      Vcut.row(mc.HandleV_Integer[vi][i]) = V.row(vi);
-
-  //ugly hack to fix some problematic cases (border vertex that is also on the boundary of the hole
-  for (int fi =0; fi<Fcut.rows(); ++fi)
-    for (int k=0; k<3; ++k)
-      if (Fcut(fi,k)==-1)
-      {
-        //we need to add a vertex
-        Fcut(fi,k) = newNumV;
-        newNumV ++;
-        Vcut.conservativeResize(newNumV, Eigen::NoChange);
-        Vcut.row(newNumV-1) = V.row(F(fi,k));
+  }
+  // add one extra occurance for boundary vertices
+  auto is_border = igl::is_border_vertex(F);
+  for(Index i=0;i<V.rows();i++)
+    if(is_border[i])
+      g(i) += 1;
+  
+  // original number of vertices
+  Index n_v = V.rows(); 
+  
+  // estimate number of new vertices and resize V
+  Index n_new = 0;
+  for(Index i=0;i<g.rows();i++)
+    n_new += ((g(i) > 0) ? g(i)-1 : 0);
+  V.conservativeResize(n_v+n_new,Eigen::NoChange);
+  I = DerivedI::LinSpaced(V.rows(),0,V.rows());
+  
+  // pointing to the current bottom of V
+  Index pos = n_v;
+  for(Index f=0;f<C.rows();f++){
+    for(Index k=0;k<3;k++){
+      Index v0 = F(f,k);
+      if(F(f,k) >= n_v) continue; // ignore new vertices
+      if(C(f,k) == 1 && o(v0) != g(v0)){
+        igl::HalfEdgeIterator<DerivedF,DerivedF,DerivedF> he(F,FF,FFi,f,k);
+
+        // rotate clock-wise around v0 until hit another cut
+        std::vector<Index> fan;
+        Index fi = he.Fi();
+        Index ei = he.Ei();
+        do{
+          fan.push_back(fi);
+          he.flipE();
+          he.flipF();
+          fi = he.Fi();
+          ei = he.Ei();
+        }while(C(fi,ei) == 0 && !he.isBorder());
+        
+        // make a copy
+        V.row(pos) << V.row(v0);
+        I(pos) = v0;
+        // add one occurance to v0
+        o(v0) += 1;
+        
+        // replace old v0
+        for(Index f0: fan)
+          for(Index j=0;j<3;j++)
+            if(F(f0,j) == v0)
+              F(f0,j) = pos;
+        
+        // mark cuts as boundary
+        FF(f,k) = -1;
+        FF(fi,ei) = -1;
+        
+        pos++;
       }
       }
-
-
+    }
+  }
+  
 }
 }
 
 
 
 
-//Wrapper of the above with only vertices and faces as mesh input
-template <typename DerivedV, typename DerivedF, typename DerivedC>
-IGL_INLINE void igl::cut_mesh(
-  const Eigen::PlainObjectBase<DerivedV> &V,
-  const Eigen::PlainObjectBase<DerivedF> &F,
-  const Eigen::PlainObjectBase<DerivedC> &cuts,
-  Eigen::PlainObjectBase<DerivedV> &Vcut,
-  Eigen::PlainObjectBase<DerivedF> &Fcut)
-{
-  std::vector<std::vector<int> > VF, VFi;
-  igl::vertex_triangle_adjacency(V,F,VF,VFi);
-  // Alec: Cast? Why? This is likely to break.
-  DerivedV Vt = V;
-  DerivedF Ft = F;
-  DerivedF TT, TTi;
-  igl::triangle_triangle_adjacency(Ft,TT,TTi);
-  std::vector<bool> V_border = igl::is_border_vertex(V,F);
-  igl::cut_mesh(V, F, VF, VFi, TT, TTi, V_border, cuts, Vcut, Fcut);
-}
-
 #ifdef IGL_STATIC_LIBRARY
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
 // Explicit template instantiation
-template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::cut_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
-template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif
 #endif

+ 36 - 45
include/igl/cut_mesh.h

@@ -1,78 +1,69 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
 //
 //
-// Copyright (C) 2015 Olga Diamanti <[email protected]>
+// Copyright (C) 2019 Hanxiao Shen <[email protected]>
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_CUT_MESH
-#define IGL_CUT_MESH
+#ifndef IGL_CUT_MESH_H
+#define IGL_CUT_MESH_H
 #include "igl_inline.h"
 #include "igl_inline.h"
 
 
 #include <Eigen/Core>
 #include <Eigen/Core>
-#include <vector>
 
 
 namespace igl
 namespace igl
 {
 {
   // Given a mesh and a list of edges that are to be cut, the function
   // Given a mesh and a list of edges that are to be cut, the function
   // generates a new disk-topology mesh that has the cuts at its boundary.
   // generates a new disk-topology mesh that has the cuts at its boundary.
   //
   //
-  // Todo: this combinatorial operation should not depend on the vertex
-  // positions V.
   //
   //
   // Known issues: Assumes mesh is edge-manifold.
   // Known issues: Assumes mesh is edge-manifold.
   //
   //
   // Inputs:
   // Inputs:
   //   V  #V by 3 list of the vertex positions
   //   V  #V by 3 list of the vertex positions
-  //   F  #F by 3 list of the faces (must be triangles)
-  //   VF  #V list of lists of incident faces (adjacency list), e.g.  as
-  //     returned by igl::vertex_triangle_adjacency
-  //   VFi  #V list of lists of index of incidence within incident faces listed
-  //     in VF, e.g. as returned by igl::vertex_triangle_adjacency
-  //   TT  #F by 3 triangle to triangle adjacent matrix (e.g. computed via
-  //     igl:triangle_triangle_adjacency)
-  //   TTi  #F by 3 adjacent matrix, the element i,j is the id of edge of the
-  //     triangle TT(i,j) that is adjacent with triangle i (e.g. computed via
-  //     igl:triangle_triangle_adjacency)
-  //   V_border  #V by 1 list of booleans, indicating if the corresponging
-  //     vertex is at the mesh boundary, e.g. as returned by
-  //     igl::is_border_vertex
+  //   F  #F by 3 list of the faces
   //   cuts  #F by 3 list of boolean flags, indicating the edges that need to
   //   cuts  #F by 3 list of boolean flags, indicating the edges that need to
   //     be cut (has 1 at the face edges that are to be cut, 0 otherwise)
   //     be cut (has 1 at the face edges that are to be cut, 0 otherwise)
   // Outputs:
   // Outputs:
-  //   Vcut  #V by 3 list of the vertex positions of the cut mesh. This matrix
+  //   Vn  #V by 3 list of the vertex positions of the cut mesh. This matrix
   //     will be similar to the original vertices except some rows will be
   //     will be similar to the original vertices except some rows will be
   //     duplicated.
   //     duplicated.
-  //   Fcut  #F by 3 list of the faces of the cut mesh(must be triangles). This
+  //   Fn  #F by 3 list of the faces of the cut mesh(must be triangles). This
   //     matrix will be similar to the original face matrix except some indices
   //     matrix will be similar to the original face matrix except some indices
   //     will be redirected to point to the newly duplicated vertices.
   //     will be redirected to point to the newly duplicated vertices.
-  //
-  template <
-    typename DerivedV, 
-    typename DerivedF, 
-    typename VFType, 
-    typename DerivedTT, 
-    typename DerivedC>
+  //   I   #V by 1 list of the map between Vn to original V index.
+
+  // In place mesh cut
+  template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
   IGL_INLINE void cut_mesh(
   IGL_INLINE void cut_mesh(
-    const Eigen::PlainObjectBase<DerivedV> &V,
-    const Eigen::PlainObjectBase<DerivedF> &F,
-    const std::vector<std::vector<VFType> >& VF,
-    const std::vector<std::vector<VFType> >& VFi,
-    const Eigen::PlainObjectBase<DerivedTT>& TT,
-    const Eigen::PlainObjectBase<DerivedTT>& TTi,
-    const std::vector<bool> &V_border,
-    const Eigen::PlainObjectBase<DerivedC> &cuts,
-    Eigen::PlainObjectBase<DerivedV> &Vcut,
-    Eigen::PlainObjectBase<DerivedF> &Fcut);
-  //Wrapper of the above with only vertices and faces as mesh input
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedC>& cuts,
+    Eigen::PlainObjectBase<DerivedI>& I
+  );
+
   template <typename DerivedV, typename DerivedF, typename DerivedC>
   template <typename DerivedV, typename DerivedF, typename DerivedC>
   IGL_INLINE void cut_mesh(
   IGL_INLINE void cut_mesh(
-    const Eigen::PlainObjectBase<DerivedV> &V,
-    const Eigen::PlainObjectBase<DerivedF> &F,
-    const Eigen::PlainObjectBase<DerivedC> &cuts,
-    Eigen::PlainObjectBase<DerivedV> &Vcut,
-    Eigen::PlainObjectBase<DerivedF> &Fcut);
-};
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedC>& cuts,
+    Eigen::PlainObjectBase<DerivedV>& Vn,
+    Eigen::PlainObjectBase<DerivedF>& Fn
+  );
+
+  template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedI>
+  IGL_INLINE void cut_mesh(
+    const Eigen::MatrixBase<DerivedV>& V,
+    const Eigen::MatrixBase<DerivedF>& F,
+    const Eigen::MatrixBase<DerivedC>& cuts,
+    Eigen::PlainObjectBase<DerivedV>& Vn,
+    Eigen::PlainObjectBase<DerivedF>& Fn,
+    Eigen::PlainObjectBase<DerivedI>& I
+  );
+
+
+  
+}
 
 
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY

+ 88 - 0
tests/include/igl/cut_mesh.cpp

@@ -0,0 +1,88 @@
+#include <test_common.h>
+#include <igl/cut_mesh.h>
+#include <igl/boundary_loop.h>
+#include <igl/vertex_components.h>
+#include <igl/edges.h>
+
+TEST_CASE("seperate mesh", "[igl]") {
+  
+  Eigen::MatrixXd V(9,3);
+  V << 0,0,0,
+       0,1,0,
+       0,2,0,
+       1,2,0,
+       2,2,0,
+       2,1,0,
+       2,0,0,
+       1,0,0,
+       1,1,0;
+  Eigen::MatrixXi F(8,3);
+  F << 0,1,8,
+       1,2,8,
+       2,3,8,
+       3,4,8,
+       4,5,8,
+       5,6,8,
+       6,7,8,
+       7,0,8;
+  
+  Eigen::MatrixXi C(8,3);
+  C << 1,0,0,
+       1,0,0,
+       1,1,0,
+       1,1,1,
+       1,1,1,
+       1,1,1,
+       1,1,1,
+       1,0,1;
+  C = 1 - C.array();
+  Eigen::VectorXi I;
+  igl::cut_mesh(V,F,C,I);
+  Eigen::VectorXi count;
+  igl::vertex_components(F, count);
+  REQUIRE(count.maxCoeff() == 2);
+
+}
+
+TEST_CASE("single edge", "[igl]") {
+  
+  Eigen::MatrixXd V(9,3);
+  V << 0,0,0,
+       0,1,0,
+       0,2,0,
+       1,2,0,
+       2,2,0,
+       2,1,0,
+       2,0,0,
+       1,0,0,
+       1,1,0;
+  Eigen::MatrixXi F(8,3);
+  F << 0,1,8,
+       1,2,8,
+       2,3,8,
+       3,4,8,
+       4,5,8,
+       5,6,8,
+       6,7,8,
+       7,0,8;
+  
+  Eigen::MatrixXi C(8,3);
+  C << 1,0,1,
+       1,1,0,
+       1,1,1,
+       1,1,1,
+       1,1,1,
+       1,1,1,
+       1,1,1,
+       1,1,1;
+  C = 1 - C.array();
+  Eigen::VectorXi I;
+  igl::cut_mesh(V,F,C,I);
+  Eigen::VectorXi count;
+  igl::vertex_components(F, count);
+  Eigen::MatrixXi E;
+  igl::edges(F, E);
+  const auto euler = V.rows() - E.rows() + F.rows();
+  CHECK ( 1 == euler );
+
+}