Browse Source

Merge branch 'master' of https://github.com/stefanbrugger/libigl into stefanbrugger-master

Former-commit-id: 47215461dcf2a7ab48b00b0473ebb1cb1b2ecd25
Alec Jacobson 10 năm trước cách đây
mục cha
commit
3be175148c

+ 113 - 81
include/igl/boundary_loop.cpp

@@ -1,105 +1,137 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-//
+// 
 // Copyright (C) 2014 Stefan Brugger <stefanbrugger@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
+// 
+// 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 "boundary_loop.h"
-
+#include "slice.h"
 #include "triangle_triangle_adjacency.h"
 #include "vertex_triangle_adjacency.h"
+#include "is_border_vertex.h"
+#include <set>
 
+template <typename DerivedF, typename Index>
 IGL_INLINE void igl::boundary_loop(
-    const Eigen::MatrixXd& V,
-    const Eigen::MatrixXi& F,
-    Eigen::VectorXi& b)
+    const Eigen::PlainObjectBase<DerivedF> & F, 
+    std::vector<std::vector<Index> >& L)
 {
-  std::vector<int> bnd;
-  bnd.clear();
-  std::vector<bool> isVisited(V.rows(),false);
-
-  // Actually mesh only needs to be manifold near boundary, so this is
-  // over zealous (see gptoolbox's outline_loop for a more general
-  // (and probably faster) implementation)
-  assert(is_edge_manifold(V,F) && "Mesh must be manifold");
-  Eigen::MatrixXi TT,TTi;
-  std::vector<std::vector<int> > VF, VFi;
-  igl::triangle_triangle_adjacency(V,F,TT,TTi);
-  igl::vertex_triangle_adjacency(V,F,VF,VFi);
-
-  // Extract one boundary edge
-  bool done = false;
-  for (int i = 0; i < TT.rows() && !done; i++)
+  using namespace std;
+  using namespace Eigen;
+  using namespace igl;
+
+  MatrixXd Vdummy(F.maxCoeff(),1);
+  MatrixXi TT,TTi;
+  vector<std::vector<int> > VF, VFi;
+  triangle_triangle_adjacency(Vdummy,F,TT,TTi);
+  vertex_triangle_adjacency(Vdummy,F,VF,VFi);
+
+  vector<bool> unvisited = is_border_vertex(Vdummy,F);
+  set<int> unseen;
+  for (int i = 0; i < unvisited.size(); ++i)
   {
-    for (int j = 0; j < TT.cols(); j++)
-    {
-      if (TT(i,j) < 0)
-      {
-        int idx1, idx2;
-        idx1 = F(i,j);
-        idx2 = F(i,(j+1) % F.cols());
-        bnd.push_back(idx1);
-        bnd.push_back(idx2);
-        isVisited[idx1] = true;
-        isVisited[idx2] = true;
-        done = true;
-        break;
-      }
-    }
+    if (unvisited[i])
+      unseen.insert(unseen.end(),i);
   }
 
-  // Traverse boundary
-  while(1)
+  while (!unseen.empty())
   {
-    bool changed = false;
-    int lastV;
-    lastV = bnd[bnd.size()-1];
+    vector<Index> l;
 
-    for (int i = 0; i < (int)VF[lastV].size(); i++)
-    {
-      int curr_neighbor = VF[lastV][i];
+    // Get first vertex of loop
+    int start = *unseen.begin();
+    unseen.erase(unseen.begin());
+    unvisited[start] = false;
+    l.push_back(start);
 
-      if (TT.row(curr_neighbor).minCoeff() < 0.) // Face contains boundary edge
+    bool done = false;
+    while (!done)
+    {
+      // Find next vertex
+      bool newBndEdge = false;
+      int v = l[l.size()-1];
+      int next;
+      for (int i = 0; i < (int)VF[v].size() && !newBndEdge; i++)
       {
-        int idx_lastV_in_face;
-        if (F(curr_neighbor,0) == lastV) idx_lastV_in_face = 0;
-        if (F(curr_neighbor,1) == lastV) idx_lastV_in_face = 1;
-        if (F(curr_neighbor,2) == lastV) idx_lastV_in_face = 2;
-
-        int idx_prev = (idx_lastV_in_face + F.cols()-1) % F.cols();
-        int idx_next = (idx_lastV_in_face + 1) % F.cols();
-        bool isPrevVisited = isVisited[F(curr_neighbor,idx_prev)];
-        bool isNextVisited = isVisited[F(curr_neighbor,idx_next)];
-
-        bool gotBndEdge = false;
-        int next_bnd_vertex;
-        if (!isNextVisited && TT(curr_neighbor,idx_lastV_in_face) < 0)
-        {
-          next_bnd_vertex = idx_next;
-          gotBndEdge = true;
-        }
-        else if (!isPrevVisited && TT(curr_neighbor,(idx_lastV_in_face+2) % F.cols()) < 0)
-        {
-          next_bnd_vertex = idx_prev;
-          gotBndEdge = true;
-        }
+        int fid = VF[v][i];
 
-        if (gotBndEdge)
+        if (TT.row(fid).minCoeff() < 0.) // Face contains boundary edge
         {
-          changed = true;
-          bnd.push_back(F(curr_neighbor,next_bnd_vertex));
-          isVisited[F(curr_neighbor,next_bnd_vertex)] = true;
-          break;
+          int vLoc;
+          if (F(fid,0) == v) vLoc = 0;
+          if (F(fid,1) == v) vLoc = 1;
+          if (F(fid,2) == v) vLoc = 2;
+
+          int vPrev = F(fid,(vLoc + F.cols()-1) % F.cols());
+          int vNext = F(fid,(vLoc + 1) % F.cols());
+
+          bool newBndEdge = false;
+          if (unvisited[vPrev] && TT(fid,(vLoc+2) % F.cols()) < 0)
+          {
+            next = vPrev;
+            newBndEdge = true;
+          }
+          else if (unvisited[vNext] && TT(fid,vLoc) < 0)
+          {
+            next = vNext;
+            newBndEdge = true;
+          }
         }
       }
-    }
 
-    if (!changed)
-      break;
+      if (newBndEdge)
+      {
+        l.push_back(next);
+        unseen.erase(next);
+        unvisited[next] = false;
+      }
+      else
+        done = true;
+    }
+    L.push_back(l);
   }
+}
 
-  b.resize(bnd.size());
-  for(unsigned i=0;i<bnd.size();++i)
-    b(i) = bnd[i];
+template <typename DerivedF, typename Index>
+IGL_INLINE void igl::boundary_loop(
+  const Eigen::PlainObjectBase<DerivedF>& F, 
+  std::vector<Index>& L)
+{
+  using namespace Eigen;
+  using namespace std;
+
+  vector<vector<int> > Lall;
+  boundary_loop(F,Lall);
+
+  int idxMax = -1;
+  int maxLen = 0;
+  for (int i = 0; i < Lall.size(); ++i)
+  {
+    if (Lall[i].size() > maxLen)
+    {
+      maxLen = Lall[i].size();
+      idxMax = i;
+    }
+  }   
+
+  L.resize(Lall[idxMax].size());
+  for (int i = 0; i < Lall[idxMax].size(); ++i)
+    L[i] = Lall[idxMax][i];
 }
+
+template <typename DerivedF, typename DerivedL>
+IGL_INLINE void igl::boundary_loop(
+  const Eigen::PlainObjectBase<DerivedF>& F, 
+  Eigen::PlainObjectBase<DerivedL>& L)
+{
+  using namespace Eigen;
+  using namespace std;
+
+  vector<int> Lvec;
+  boundary_loop(F,Lvec);
+
+  L.resize(Lvec.size());
+  for (int i = 0; i < Lvec.size(); ++i)
+    L(i) = Lvec[i];
+}

+ 39 - 9
include/igl/boundary_loop.h

@@ -7,30 +7,60 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_BOUNDARY_LOOP_H
 #define IGL_BOUNDARY_LOOP_H
-#include <igl/igl_inline.h>
+#include "igl_inline.h"
 
 #include <Eigen/Dense>
 #include <vector>
 
 namespace igl
 {
+  // Compute list of ordered boundary loops for a manifold mesh.
+  //
+  // Templates:
+  //  Index  index type
+  // Inputs:
+  //   F  #V by dim list of mesh faces
+  // Outputs:
+  //   L  list of loops where L[i] = ordered list of boundary vertices in loop i
+  //
+  template <typename DerivedF, typename Index>
+  IGL_INLINE void boundary_loop(
+    const Eigen::PlainObjectBase<DerivedF>& F, 
+    std::vector<std::vector<Index> >& L);
+
+
+  // Compute ordered boundary loops for a manifold mesh and return the 
+  // longest loop in terms of vertices.
+  //
+  // Templates:
+  //  Index  index type
+  // Inputs:
+  //   F  #V by dim list of mesh faces
+  // Outputs:
+  //   L  ordered list of boundary vertices of longest boundary loop
+  //
+  template <typename DerivedF, typename Index>
+  IGL_INLINE void boundary_loop(
+    const Eigen::PlainObjectBase<DerivedF>& F, 
+    std::vector<Index>& L);
 
-  // Compute sorted list of boundary vertices for a manifold mesh with single
-  // boundary.
+  // Compute ordered boundary loops for a manifold mesh and return the 
+  // longest loop in terms of vertices.
   //
+  // Templates:
+  //  Index  index type
   // Inputs:
-  //   V  #V by dim list of mesh vertex positions
   //   F  #V by dim list of mesh faces
   // Outputs:
-  //   bnd   sorted list of boundary vertex indices
+  //   L  ordered list of boundary vertices of longest boundary loop
+  //
+  template <typename DerivedF, typename DerivedL>
   IGL_INLINE void boundary_loop(
-  	const Eigen::MatrixXd& V, 
-  	const Eigen::MatrixXi& F, 
-    Eigen::VectorXi& bnd);
+    const Eigen::PlainObjectBase<DerivedF>& F, 
+    Eigen::PlainObjectBase<DerivedL>& L);
 }
 
 #ifndef IGL_STATIC_LIBRARY
 #  include "boundary_loop.cpp"
 #endif
-
 #endif

+ 0 - 2
include/igl/map_vertices_to_circle.cpp

@@ -8,8 +8,6 @@
 
 #include "map_vertices_to_circle.h"
 
-#include "boundary_loop.h"
-
 IGL_INLINE void igl::map_vertices_to_circle(
   const Eigen::MatrixXd& V,
   const Eigen::VectorXi& bnd,

+ 0 - 62
include/igl/outline_ordered.cpp

@@ -1,62 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2014 Stefan Brugger <stefanbrugger@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 "outline_ordered.h"
-#include "exterior_edges.h"
-#include <set>
-
-template <typename DerivedF, typename Index>
-IGL_INLINE void igl::outline_ordered(
-    const Eigen::PlainObjectBase<DerivedF> & F, 
-    std::vector<std::vector<Index> >& L)
-{
-  using namespace std;
-  using namespace Eigen;
-  // Exterior edges include some non-manifold edges (poor function name). I
-  // suppose `outline_ordered` is not well defined for non-manifold meshes, but
-  // perhaps this should just call `boundary_facets`
-  MatrixXi E = exterior_edges(F);
-
-  set<int> unseen;
-  for (int i = 0; i < E.rows(); ++i)
-  {
-    unseen.insert(unseen.end(),i);
-  }
-
-  while (!unseen.empty())
-  {
-      vector<Index> l;
-
-      // Get first vertex of loop
-      int startEdge = *unseen.begin();
-      unseen.erase(unseen.begin());
-
-      int start = E(startEdge,0);
-      int next = E(startEdge,1);
-      l.push_back(start);
-
-      while (start != next)
-      {
-          l.push_back(next);
-
-          // Find next edge
-          int nextEdge;
-          set<int>::iterator it;
-          for (it=unseen.begin(); it != unseen.end() ; ++it)
-          {
-              if (E(*it,0) == next || E(*it,1) == next)
-              {
-                  nextEdge = *it;
-                  break;
-              }                  
-          }
-          unseen.erase(nextEdge);
-          next = (E(nextEdge,0) == next) ? E(nextEdge,1) : E(nextEdge,0);
-      }
-      L.push_back(l);
-  }
-}

+ 0 - 35
include/igl/outline_ordered.h

@@ -1,35 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2014 Stefan Brugger <stefanbrugger@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_OUTLINE_ORDERED_H
-#define IGL_OUTLINE_ORDERED_H
-#include "igl_inline.h"
-
-#include <Eigen/Dense>
-#include <vector>
-
-namespace igl
-{
-  // Compute list of ordered boundary loops for a manifold mesh.
-  //
-  // Templates:
-  //  Index  index type
-  // Inputs:
-  //   F  #V by dim list of mesh faces
-  // Outputs:
-  //   L  list of loops where L[i] = ordered list of boundary vertices in loop i
-  //
-  template <typename DerivedF, typename Index>
-  IGL_INLINE void outline_ordered(
-    const Eigen::PlainObjectBase<DerivedF> & F, 
-    std::vector<std::vector<Index> >& L);
-}
-
-#ifndef IGL_STATIC_LIBRARY
-#  include "outline_ordered.cpp"
-#endif
-#endif

+ 1 - 1
tutorial/501_HarmonicParam/main.cpp

@@ -35,7 +35,7 @@ int main(int argc, char *argv[])
 
   // Find the open boundary
   Eigen::VectorXi bnd;
-  igl::boundary_loop(V,F,bnd);
+  igl::boundary_loop(F,bnd);
 
   // Map the boundary to a circle, preserving edge proportions
   Eigen::MatrixXd bnd_uv;

+ 1 - 1
tutorial/502_LSCMParam/main.cpp

@@ -39,7 +39,7 @@ int main(int argc, char *argv[])
 
   // Fix two points on the boundary
   VectorXi bnd,b(2,1);
-  igl::boundary_loop(V,F,bnd);
+  igl::boundary_loop(F,bnd);
   b(0) = bnd(0);
   b(1) = bnd(round(bnd.size()/2));
   MatrixXd bc(2,2);

+ 1 - 1
tutorial/503_ARAPParam/main.cpp

@@ -46,7 +46,7 @@ int main(int argc, char *argv[])
 
   // Compute the initial solution for ARAP (harmonic parametrization)
   Eigen::VectorXi bnd;
-  igl::boundary_loop(V,F,bnd);
+  igl::boundary_loop(F,bnd);
   Eigen::MatrixXd bnd_uv;
   igl::map_vertices_to_circle(V,bnd,bnd_uv);