Explorar o código

attempt to comment and cleanup code

Former-commit-id: 83c92b8a0039653598303da9a2e26b36f38f2f2b
Alec Jacobson %!s(int64=9) %!d(string=hai) anos
pai
achega
5cd07a5d68
Modificáronse 2 ficheiros con 320 adicións e 294 borrados
  1. 234 206
      include/igl/copyleft/cgal/extract_cells.cpp
  2. 86 88
      include/igl/copyleft/cgal/extract_cells.h

+ 234 - 206
include/igl/copyleft/cgal/extract_cells.cpp

@@ -53,212 +53,6 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
 }
 
 
-template<
-  typename DerivedV,
-  typename DerivedF,
-  typename DerivedP,
-  typename DeriveduE,
-  typename uE2EType,
-  typename DerivedEMAP,
-  typename DerivedC>
-IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
-  const Eigen::PlainObjectBase<DerivedV>& V,
-  const Eigen::PlainObjectBase<DerivedF>& F,
-  const Eigen::PlainObjectBase<DerivedP>& P,
-  const Eigen::PlainObjectBase<DeriveduE>& uE,
-  const std::vector<std::vector<uE2EType> >& uE2E,
-  const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
-  Eigen::PlainObjectBase<DerivedC>& cells)
-{
-  const size_t num_faces = F.rows();
-  // Input:
-  //   index  index into #F*3 list of undirect edges
-  // Returns index into face
-  const auto edge_index_to_face_index = [&num_faces](size_t index)
-  {
-    return index % num_faces;
-  };
-  // Determine if a face (containing undirected edge {s,d} is consistently
-  // oriented with directed edge {s,d} (or otherwise it is with {d,s})
-  // 
-  // Inputs:
-  //   fid  face index into F
-  //   s  source index of edge
-  //   d  destination index of edge
-  // Returns true if face F(fid,:) is consistent with {s,d}
-  const auto is_consistent = 
-    [&F](const size_t fid, const size_t s, const size_t d) -> bool
-  {
-    if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
-    if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
-    if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
-
-    if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
-    if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
-    if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
-    throw "Invalid face!";
-    return false;
-  };
-
-  const size_t num_unique_edges = uE.rows();
-  const size_t num_patches = P.maxCoeff() + 1;
-
-  // patch_edge_adj[p] --> list {e,f,g,...} such that p is a patch id and
-  //   e,f,g etc. are edge indices into 
-  std::vector<std::vector<size_t> > patch_edge_adj(num_patches);
-  // orders[u] --> J  where u is an index into unique edges uE and J is a
-  //   #adjacent-faces list of face-edge indices into F*3 sorted cyclicaly around
-  //   edge u.
-  std::vector<Eigen::VectorXi> orders(num_unique_edges);
-  // orientations[u] ---> list {f1,f2, ...} where u is an index into unique edges uE
-  //   and points to #adj-facets long list of flags whether faces are oriented
-  //   to point their normals clockwise around edge when looking along the
-  //   edge.
-  std::vector<std::vector<bool> > orientations(num_unique_edges);
-  // Loop over unique edges
-  for (size_t i=0; i<num_unique_edges; i++) 
-  {
-    const size_t s = uE(i,0);
-    const size_t d = uE(i,1);
-    const auto adj_faces = uE2E[i];
-    // If non-manifold (more than two incident faces)
-    if (adj_faces.size() > 2) 
-    {
-      // signed_adj_faces[a] --> sid  where a is an index into adj_faces
-      // (list of face edges on {s,d}) and sid is a signed index for resolve
-      // co-planar duplicates consistently (i.e. using simulation of
-      // simplicity).
-      std::vector<int> signed_adj_faces;
-      for (auto ei : adj_faces)
-      {
-        const size_t fid = edge_index_to_face_index(ei);
-        bool cons = is_consistent(fid, s, d);
-        signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
-      }
-      {
-        // Sort adjacent faces cyclically around {s,d}
-        auto& order = orders[i];
-        // order[f] will reveal the order of face f in signed_adj_faces
-        order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
-        // Determine if each facet is oriented to point its normal clockwise or
-        // not around the {s,d} (normals are not explicitly computed/used)
-        auto& orientation = orientations[i];
-        orientation.resize(order.size());
-        std::transform(
-          order.data(), 
-          order.data() + order.size(),
-          orientation.begin(), 
-          [&signed_adj_faces](const int i){ return signed_adj_faces[i] > 0;});
-        // re-index order from adjacent faces to full face list. Now order
-        // indexes F directly
-        std::transform(
-          order.data(), 
-          order.data() + order.size(),
-          order.data(), 
-          [&adj_faces](const int index){ return adj_faces[index];});
-      }
-      // loop over adjacent faces, remember that patch is adjacent to this edge
-      for(const auto & ei : adj_faces)
-      {
-        const size_t fid = edge_index_to_face_index(ei);
-        patch_edge_adj[P[fid]].push_back(ei);
-      }
-    }
-  }
-
-  // Initialize all patch-to-cell indices as "invalid" (unlabeled)
-  const int INVALID = std::numeric_limits<int>::max();
-  cells.resize(num_patches, 2);
-  cells.setConstant(INVALID);
-
-  // Given a "seed" patch id, a cell id, and which side of the patch that cell
-  // lies, identify all other patches bounding this cell (and tell them that
-  // they do)
-  //
-  // Inputs:
-  //   seed_patch_id  index into patches
-  //   cell_idx  index into cells
-  //   seed_patch_side   0 or 1 depending on whether cell_idx is on left or
-  //     right side of seed_patch_id 
-  //   cells  #cells by 2 list of current assignment of cells incident on each
-  //     side of a patch
-  // Outputs:
-  //   cells  udpated (see input)
-  // 
-  const auto & peel_cell_bd = 
-    [&P,&patch_edge_adj,&EMAP,&orders,&orientations,&num_faces](
-    const size_t seed_patch_id, 
-    const short seed_patch_side, 
-    const size_t cell_idx,
-    Eigen::PlainObjectBase<DerivedC>& cells)
-  {
-    typedef std::pair<size_t, short> PatchSide;
-    // Initialize a queue to BFS over all patches
-    std::queue<PatchSide> Q;
-    Q.emplace(seed_patch_id, seed_patch_side);
-    // assign cell id of seed patch on appropriate side
-    cells(seed_patch_id, seed_patch_side) = cell_idx;
-    while (!Q.empty())
-    {
-      auto entry = Q.front();
-      Q.pop();
-      const size_t patch_id = entry.first;
-      const short side = entry.second;
-      const auto& adj_edges = patch_edge_adj[patch_id];
-      for (const auto& ei : adj_edges)
-      {
-        const size_t uei = EMAP[ei];
-        const auto& order = orders[uei];
-        const auto& orientation = orientations[uei];
-        const size_t edge_valance = order.size();
-        size_t curr_i = 0;
-        for (curr_i=0; curr_i < edge_valance; curr_i++)
-        {
-          if ((size_t)order[curr_i] == ei) break;
-        }
-        assert(curr_i < edge_valance && "Failed to find edge.");
-
-        const bool cons = orientation[curr_i];
-        size_t next;
-        if (side == 0)
-        {
-          next = (cons ? (curr_i + 1) :
-          (curr_i + edge_valance - 1)) % edge_valance;
-        } else {
-          next = (cons ? (curr_i+edge_valance-1) : (curr_i+1))%edge_valance;
-        }
-        const size_t next_ei = order[next];
-        const bool next_cons = orientation[next];
-        const size_t next_patch_id = P[next_ei % num_faces];
-        const short next_patch_side = (next_cons != cons) ?  side:abs(side-1);
-        if (cells(next_patch_id, next_patch_side) == INVALID) 
-        {
-          Q.emplace(next_patch_id, next_patch_side);
-          cells(next_patch_id, next_patch_side) = cell_idx;
-        }else 
-        {
-          assert(
-            (size_t)cells(next_patch_id, next_patch_side) == cell_idx && 
-            "Encountered cell assignment inconsistency");
-        }
-      }
-    }
-  };
-
-    size_t count=0;
-    for (size_t i=0; i<num_patches; i++) {
-        if (cells(i, 0) == INVALID) {
-            peel_cell_bd(i, 0, count,cells);
-            count++;
-        }
-        if (cells(i, 1) == INVALID) {
-            peel_cell_bd(i, 1, count,cells);
-            count++;
-        }
-    }
-    return count;
-}
-
 template<
     typename DerivedV,
     typename DerivedF,
@@ -485,6 +279,240 @@ IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
     return count;
 }
 
+template<
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedP,
+  typename DeriveduE,
+  typename uE2EType,
+  typename DerivedEMAP,
+  typename DerivedC>
+IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
+  const Eigen::PlainObjectBase<DerivedV>& V,
+  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::PlainObjectBase<DerivedP>& P,
+  const Eigen::PlainObjectBase<DeriveduE>& uE,
+  const std::vector<std::vector<uE2EType> >& uE2E,
+  const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+  Eigen::PlainObjectBase<DerivedC>& cells)
+{
+  const size_t num_faces = F.rows();
+  // Input:
+  //   index  index into #F*3 list of undirect edges
+  // Returns index into face
+  const auto edge_index_to_face_index = [&num_faces](size_t index)
+  {
+    return index % num_faces;
+  };
+  // Determine if a face (containing undirected edge {s,d} is consistently
+  // oriented with directed edge {s,d} (or otherwise it is with {d,s})
+  // 
+  // Inputs:
+  //   fid  face index into F
+  //   s  source index of edge
+  //   d  destination index of edge
+  // Returns true if face F(fid,:) is consistent with {s,d}
+  const auto is_consistent = 
+    [&F](const size_t fid, const size_t s, const size_t d) -> bool
+  {
+    if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
+    if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
+    if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
+
+    if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
+    if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
+    if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
+    throw "Invalid face!";
+    return false;
+  };
+
+  const size_t num_unique_edges = uE.rows();
+  const size_t num_patches = P.maxCoeff() + 1;
+
+  // patch_edge_adj[p] --> list {e,f,g,...} such that p is a patch id and
+  //   e,f,g etc. are edge indices into 
+  std::vector<std::vector<size_t> > patch_edge_adj(num_patches);
+  // orders[u] --> J  where u is an index into unique edges uE and J is a
+  //   #adjacent-faces list of face-edge indices into F*3 sorted cyclicaly around
+  //   edge u.
+  std::vector<Eigen::VectorXi> orders(num_unique_edges);
+  // orientations[u] ---> list {f1,f2, ...} where u is an index into unique edges uE
+  //   and points to #adj-facets long list of flags whether faces are oriented
+  //   to point their normals clockwise around edge when looking along the
+  //   edge.
+  std::vector<std::vector<bool> > orientations(num_unique_edges);
+  // Loop over unique edges
+  for (size_t i=0; i<num_unique_edges; i++) 
+  {
+    const size_t s = uE(i,0);
+    const size_t d = uE(i,1);
+    const auto adj_faces = uE2E[i];
+    // If non-manifold (more than two incident faces)
+    if (adj_faces.size() > 2) 
+    {
+      // signed_adj_faces[a] --> sid  where a is an index into adj_faces
+      // (list of face edges on {s,d}) and sid is a signed index for resolve
+      // co-planar duplicates consistently (i.e. using simulation of
+      // simplicity).
+      std::vector<int> signed_adj_faces;
+      for (auto ei : adj_faces)
+      {
+        const size_t fid = edge_index_to_face_index(ei);
+        bool cons = is_consistent(fid, s, d);
+        signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
+      }
+      {
+        // Sort adjacent faces cyclically around {s,d}
+        auto& order = orders[i];
+        // order[f] will reveal the order of face f in signed_adj_faces
+        order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
+        // Determine if each facet is oriented to point its normal clockwise or
+        // not around the {s,d} (normals are not explicitly computed/used)
+        auto& orientation = orientations[i];
+        orientation.resize(order.size());
+        std::transform(
+          order.data(), 
+          order.data() + order.size(),
+          orientation.begin(), 
+          [&signed_adj_faces](const int i){ return signed_adj_faces[i] > 0;});
+        // re-index order from adjacent faces to full face list. Now order
+        // indexes F directly
+        std::transform(
+          order.data(), 
+          order.data() + order.size(),
+          order.data(), 
+          [&adj_faces](const int index){ return adj_faces[index];});
+      }
+      // loop over adjacent faces, remember that patch is adjacent to this edge
+      for(const auto & ei : adj_faces)
+      {
+        const size_t fid = edge_index_to_face_index(ei);
+        patch_edge_adj[P[fid]].push_back(ei);
+      }
+    }
+  }
+
+  // Initialize all patch-to-cell indices as "invalid" (unlabeled)
+  const int INVALID = std::numeric_limits<int>::max();
+  cells.resize(num_patches, 2);
+  cells.setConstant(INVALID);
+
+  // Given a "seed" patch id, a cell id, and which side of the patch that cell
+  // lies, identify all other patches bounding this cell (and tell them that
+  // they do)
+  //
+  // Inputs:
+  //   seed_patch_id  index into patches
+  //   cell_idx  index into cells
+  //   seed_patch_side   0 or 1 depending on whether cell_idx is on left or
+  //     right side of seed_patch_id 
+  //   cells  #cells by 2 list of current assignment of cells incident on each
+  //     side of a patch
+  // Outputs:
+  //   cells  udpated (see input)
+  // 
+  const auto & peel_cell_bd = 
+    [&P,&patch_edge_adj,&EMAP,&orders,&orientations,&num_faces](
+    const size_t seed_patch_id, 
+    const short seed_patch_side, 
+    const size_t cell_idx,
+    Eigen::PlainObjectBase<DerivedC>& cells)
+  {
+    typedef std::pair<size_t, short> PatchSide;
+    // Initialize a queue of {p,side} patch id and patch side pairs to BFS over
+    // all patches
+    std::queue<PatchSide> Q;
+    Q.emplace(seed_patch_id, seed_patch_side);
+    // assign cell id of seed patch on appropriate side
+    cells(seed_patch_id, seed_patch_side) = cell_idx;
+    while (!Q.empty())
+    {
+      // Pop patch from Q
+      const auto entry = Q.front();
+      Q.pop();
+      const size_t patch_id = entry.first;
+      const short side = entry.second;
+      // face-edges adjacent to patch
+      const auto& adj_edges = patch_edge_adj[patch_id];
+      // Loop over **ALL EDGES IN THE ENTIRE PATCH** not even just the boundary
+      // edges, all edges... O(n)
+      for (const auto& ei : adj_edges)
+      {
+        // unique edge
+        const size_t uei = EMAP[ei];
+        // ordering of face-edges stored at edge
+        const auto& order = orders[uei];
+        // consistent orientation flags at face-edges stored at edge
+        const auto& orientation = orientations[uei];
+        const size_t edge_valance = order.size();
+        // Search for ei's (i.e. patch_id's) place in the ordering: O(#patches)
+        size_t curr_i = 0;
+        for (curr_i=0; curr_i < edge_valance; curr_i++)
+        {
+          if ((size_t)order[curr_i] == ei) break;
+        }
+        assert(curr_i < edge_valance && "Failed to find edge.");
+        // is the starting face consistent?
+        const bool cons = orientation[curr_i];
+        // Look clockwise or counter-clockwise for the next face, depending on
+        // whether looking to left or right side and whether consistently
+        // oriented or not.
+        size_t next;
+        if (side == 0)
+        {
+          next = (cons ? (curr_i + 1) :
+          (curr_i + edge_valance - 1)) % edge_valance;
+        } else {
+          next = (cons ? (curr_i+edge_valance-1) : (curr_i+1))%edge_valance;
+        }
+        // Determine face-edge index of next face
+        const size_t next_ei = order[next];
+        // Determine whether next is consistently oriented
+        const bool next_cons = orientation[next];
+        // Determine patch of next
+        const size_t next_patch_id = P[next_ei % num_faces];
+        // Determine which side of patch cell_idx is on, based on whether the
+        // consistency of next matches the consistency of this patch and which
+        // side of this patch we're on.
+        const short next_patch_side = (next_cons != cons) ?  side:abs(side-1);
+        // If that side of next's patch is not labeled, then label and add to
+        // queue
+        if (cells(next_patch_id, next_patch_side) == INVALID) 
+        {
+          Q.emplace(next_patch_id, next_patch_side);
+          cells(next_patch_id, next_patch_side) = cell_idx;
+        }else 
+        {
+          assert(
+            (size_t)cells(next_patch_id, next_patch_side) == cell_idx && 
+            "Encountered cell assignment inconsistency");
+        }
+      }
+    }
+  };
+
+  size_t count=0;
+  // Loop over all patches
+  for (size_t i=0; i<num_patches; i++)
+  {
+    // If left side of patch is still unlabeled, create a new cell and find all
+    // patches also on its boundary
+    if (cells(i, 0) == INVALID)
+    {
+      peel_cell_bd(i, 0, count,cells);
+      count++;
+    }
+    // Likewise for right side
+    if (cells(i, 1) == INVALID)
+    {
+      peel_cell_bd(i, 1, count,cells);
+      count++;
+    }
+  }
+  return count;
+}
+
+
 #ifdef IGL_STATIC_LIBRARY
 #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
 template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -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<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);

+ 86 - 88
include/igl/copyleft/cgal/extract_cells.h

@@ -16,96 +16,94 @@
 namespace igl {
   namespace copyleft
   {
-    namespace cgal {
-        // Extract connected 3D space partitioned by mesh (V, F).
-        //
-        // Inputs:
-        //   V  #V by 3 array of vertices.
-        //   F  #F by 3 array of faces.
-        //
-        // Output:
-        //   cells  #F by 2 array of cell indices.  cells(i,0) represents the
-        //          cell index on the positive side of face i, and cells(i,1)
-        //          represents cell index of the negqtive side.
-        //          By convension cell with index 0 is the infinite cell.
-        template<
-            typename DerivedV,
-            typename DerivedF,
-            typename DerivedC >
-        IGL_INLINE size_t extract_cells(
-                const Eigen::PlainObjectBase<DerivedV>& V,
-                const Eigen::PlainObjectBase<DerivedF>& F,
-                Eigen::PlainObjectBase<DerivedC>& cells);
+    namespace cgal
+    {
+      // Extract connected 3D space partitioned by mesh (V, F).
+      //
+      // Inputs:
+      //   V  #V by 3 array of vertices.
+      //   F  #F by 3 array of faces.
+      //
+      // Output:
+      //   cells  #F by 2 array of cell indices.  cells(i,0) represents the
+      //          cell index on the positive side of face i, and cells(i,1)
+      //          represents cell index of the negqtive side.
+      //          By convension cell with index 0 is the infinite cell.
+      template<
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedC >
+      IGL_INLINE size_t extract_cells(
+        const Eigen::PlainObjectBase<DerivedV>& V,
+        const Eigen::PlainObjectBase<DerivedF>& F,
+        Eigen::PlainObjectBase<DerivedC>& cells);
 
-        // Extract connected 3D space partitioned by mesh (V, F).
-        //
-        // Inputs:
-        //   V  #V by 3 array of vertices.
-        //   F  #F by 3 array of faces.
-        //   P  #F list of patch indices.
-        //   E  #E by 2 array of vertex indices, one edge per row.
-        //  uE    #uE by 2 list of vertex_indices, represents undirected edges.
-        //  uE2E  #uE list of lists that maps uE to E. (a one-to-many map)
-        //  EMAP  #F*3 list of indices into uE.
-        //
-        // Output:
-        //   cells  #P by 2 array of cell indices.  cells(i,0) represents the
-        //          cell index on the positive side of patch i, and cells(i,1)
-        //          represents cell index of the negqtive side.
-        //          By convension cell with index 0 is the infinite cell.
-        template<
-            typename DerivedV,
-            typename DerivedF,
-            typename DerivedP,
-            typename DerivedE,
-            typename DeriveduE,
-            typename uE2EType,
-            typename DerivedEMAP,
-            typename DerivedC >
-        IGL_INLINE size_t extract_cells(
-                const Eigen::PlainObjectBase<DerivedV>& V,
-                const Eigen::PlainObjectBase<DerivedF>& F,
-                const Eigen::PlainObjectBase<DerivedP>& P,
-                const Eigen::PlainObjectBase<DerivedE>& E,
-                const Eigen::PlainObjectBase<DeriveduE>& uE,
-                const std::vector<std::vector<uE2EType> >& uE2E,
-                const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
-                Eigen::PlainObjectBase<DerivedC>& cells);
-
-        // Extract connected 3D space partitioned by mesh (V, F).  Each
-        // connected component of the mesh partitions the ambient space
-        // separately.
-        //
-        // Inputs:
-        //   V  #V by 3 array of vertices.
-        //   F  #F by 3 array of faces.
-        //   P  #F list of patch indices.
-        //   E  #E by 2 array of vertex indices, one edge per row.
-        //  uE    #uE by 2 list of vertex_indices, represents undirected edges.
-        //  uE2E  #uE list of lists that maps uE to E. (a one-to-many map)
-        //  EMAP  #F*3 list of indices into uE.
-        //
-        // Output:
-        //   cells  #P by 2 array of cell indices.  cells(i,0) represents the
-        //          cell index on the positive side of patch i, and cells(i,1)
-        //          represents cell index of the negqtive side.
-        template<
-            typename DerivedV,
-            typename DerivedF,
-            typename DerivedP,
-            typename DeriveduE,
-            typename uE2EType,
-            typename DerivedEMAP,
-            typename DerivedC >
-        IGL_INLINE size_t extract_cells_single_component(
-                const Eigen::PlainObjectBase<DerivedV>& V,
-                const Eigen::PlainObjectBase<DerivedF>& F,
-                const Eigen::PlainObjectBase<DerivedP>& P,
-                const Eigen::PlainObjectBase<DeriveduE>& uE,
-                const std::vector<std::vector<uE2EType> >& uE2E,
-                const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
-                Eigen::PlainObjectBase<DerivedC>& cells);
+      // Extract connected 3D space partitioned by mesh (V, F).
+      //
+      // Inputs:
+      //   V  #V by 3 array of vertices.
+      //   F  #F by 3 array of faces.
+      //   P  #F list of patch indices.
+      //   E  #E by 2 array of vertex indices, one edge per row.
+      //  uE    #uE by 2 list of vertex_indices, represents undirected edges.
+      //  uE2E  #uE list of lists that maps uE to E. (a one-to-many map)
+      //  EMAP  #F*3 list of indices into uE.
+      //
+      // Output:
+      //   cells  #P by 2 array of cell indices.  cells(i,0) represents the
+      //          cell index on the positive side of patch i, and cells(i,1)
+      //          represents cell index of the negqtive side.
+      //          By convension cell with index 0 is the infinite cell.
+      template<
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedP,
+        typename DerivedE,
+        typename DeriveduE,
+        typename uE2EType,
+        typename DerivedEMAP,
+        typename DerivedC >
+      IGL_INLINE size_t extract_cells(
+        const Eigen::PlainObjectBase<DerivedV>& V,
+        const Eigen::PlainObjectBase<DerivedF>& F,
+        const Eigen::PlainObjectBase<DerivedP>& P,
+        const Eigen::PlainObjectBase<DerivedE>& E,
+        const Eigen::PlainObjectBase<DeriveduE>& uE,
+        const std::vector<std::vector<uE2EType> >& uE2E,
+        const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+        Eigen::PlainObjectBase<DerivedC>& cells);
 
+      // Extract connected 3D space partitioned by mesh (V,F) composed of a
+      // **single connected component**. 
+      //
+      // Inputs:
+      //   V  #V by 3 array of vertices.
+      //   F  #F by 3 array of faces.
+      //   P  #F list of patch indices.
+      //   E  #E by 2 array of vertex indices, one edge per row.
+      //  uE    #uE by 2 list of vertex_indices, represents undirected edges.
+      //  uE2E  #uE list of lists that maps uE to E. (a one-to-many map)
+      //  EMAP  #F*3 list of indices into uE.
+      // Output:
+      //  cells  #P by 2 array of cell indices.  cells(i,0) represents the
+      //    cell index on the positive side of patch i, and cells(i,1)
+      //    represents cell index of the negative side.
+      template<
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedP,
+        typename DeriveduE,
+        typename uE2EType,
+        typename DerivedEMAP,
+        typename DerivedC >
+      IGL_INLINE size_t extract_cells_single_component(
+        const Eigen::PlainObjectBase<DerivedV>& V,
+        const Eigen::PlainObjectBase<DerivedF>& F,
+        const Eigen::PlainObjectBase<DerivedP>& P,
+        const Eigen::PlainObjectBase<DeriveduE>& uE,
+        const std::vector<std::vector<uE2EType> >& uE2E,
+        const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+        Eigen::PlainObjectBase<DerivedC>& cells);
     }
   }
 }