Pārlūkot izejas kodu

cosmetic reformatting and templates

Former-commit-id: a13a68f3f264b0878c43941ec83265eb4e85d913
Alec Jacobson 8 gadi atpakaļ
vecāks
revīzija
af2594ad1c
2 mainītis faili ar 226 papildinājumiem un 179 dzēšanām
  1. 178 138
      include/igl/seam_edges.cpp
  2. 48 41
      include/igl/seam_edges.h

+ 178 - 138
include/igl/seam_edges.cpp

@@ -11,161 +11,201 @@
 #include <unordered_set>
 #include <cassert>
 
-// I have verified that this function produces the exact same output as
+// Yotam has verified that this function produces the exact same output as
 // `find_seam_fast.py` for `cow_triangled.obj`.
-template <typename DerivedV, typename DerivedF, typename DerivedT>
+template <
+  typename DerivedV, 
+  typename DerivedTC,
+  typename DerivedF, 
+  typename DerivedFTC,
+  typename Derivedseams,
+  typename Derivedboundaries,
+  typename Derivedfoldovers>
 IGL_INLINE void igl::seam_edges(
-    const Eigen::PlainObjectBase<DerivedV>& V,
-    const Eigen::PlainObjectBase<DerivedT>& TC,
-    const Eigen::PlainObjectBase<DerivedF>& F,
-    const Eigen::PlainObjectBase<DerivedF>& FTC,
-    Eigen::PlainObjectBase<DerivedF>& seams,
-    Eigen::PlainObjectBase<DerivedF>& boundaries,
-    Eigen::PlainObjectBase<DerivedF>& foldovers
-    )
+  const Eigen::PlainObjectBase<DerivedV>& V,
+  const Eigen::PlainObjectBase<DerivedTC>& TC,
+  const Eigen::PlainObjectBase<DerivedF>& F,
+  const Eigen::PlainObjectBase<DerivedFTC>& FTC,
+  Eigen::PlainObjectBase<Derivedseams>& seams,
+  Eigen::PlainObjectBase<Derivedboundaries>& boundaries,
+  Eigen::PlainObjectBase<Derivedfoldovers>& foldovers)
 {
-    // Assume triangles.
-    assert( F.cols() == 3 );
-    assert( F.cols() == FTC.cols() );
-    assert( F.rows() == FTC.rows() );
+  // Assume triangles.
+  assert( F.cols() == 3 );
+  assert( F.cols() == FTC.cols() );
+  assert( F.rows() == FTC.rows() );
     
-    // Assume 2D texture coordinates (foldovers tests).
-    assert( TC.cols() == 2 );
-    typedef Eigen::Matrix< typename DerivedT::Scalar, 2, 1 > Vector2S;
-    // Computes the orientation of `c` relative to the line between `a` and `b`.
-    // Assumes 2D vector input.
-    // Based on: https://www.cs.cmu.edu/~quake/robust.html
-    const auto& Orientation = []( const Vector2S& a, const Vector2S& b, const Vector2S& c ) -> typename DerivedT::Scalar
-    {
-        const Vector2S row0 = a - c;
-        const Vector2S row1 = b - c;
-        return row0(0)*row1(1) - row1(0)*row0(1);
-    };
+  // Assume 2D texture coordinates (foldovers tests).
+  assert( TC.cols() == 2 );
+  typedef Eigen::Matrix< typename DerivedTC::Scalar, 2, 1 > Vector2S;
+  // Computes the orientation of `c` relative to the line between `a` and `b`.
+  // Assumes 2D vector input.
+  // Based on: https://www.cs.cmu.edu/~quake/robust.html
+  const auto& Orientation = []( 
+    const Vector2S& a, 
+    const Vector2S& b, 
+    const Vector2S& c ) -> typename DerivedTC::Scalar
+  {
+      const Vector2S row0 = a - c;
+      const Vector2S row1 = b - c;
+      return row0(0)*row1(1) - row1(0)*row0(1);
+  };
     
-    seams     .setZero( 3*F.rows(), 4 );
-    boundaries.setZero( 3*F.rows(), 2 );
-    foldovers .setZero( 3*F.rows(), 4 );
+  seams     .setZero( 3*F.rows(), 4 );
+  boundaries.setZero( 3*F.rows(), 2 );
+  foldovers .setZero( 3*F.rows(), 4 );
     
-    int num_seams = 0;
-    int num_boundaries = 0;
-    int num_foldovers = 0;
+  int num_seams = 0;
+  int num_boundaries = 0;
+  int num_foldovers = 0;
     
-    // A map from a pair of vertex indices to the index (face and endpoints)
-    // into face_position_indices.
-    // The following should be true for every key, value pair:
-    //    key == face_position_indices[ value ]
-    // This gives us a "reverse map" so that we can look up other face
-    // attributes based on position edges.
-    // The value are written in the format returned by numpy.where(),
-    // which stores multi-dimensional indices such as array[a0,b0], array[a1,b1]
-    // as ( (a0,a1), (b0,b1) ).
+  // A map from a pair of vertex indices to the index (face and endpoints)
+  // into face_position_indices.
+  // The following should be true for every key, value pair:
+  //    key == face_position_indices[ value ]
+  // This gives us a "reverse map" so that we can look up other face
+  // attributes based on position edges.
+  // The value are written in the format returned by numpy.where(),
+  // which stores multi-dimensional indices such as array[a0,b0], array[a1,b1]
+  // as ( (a0,a1), (b0,b1) ).
     
-    // We need to make a hash function for our directed edges.
-    // We'll use i*V.rows() + j.
-    typedef std::pair< typename DerivedF::Scalar, typename DerivedF::Scalar > directed_edge;
+  // We need to make a hash function for our directed edges.
+  // We'll use i*V.rows() + j.
+  typedef std::pair< typename DerivedF::Scalar, typename DerivedF::Scalar > 
+    directed_edge;
 	const int numV = V.rows();
 	const int numF = F.rows();
-	const auto& edge_hasher = [numV]( directed_edge const& e ) { return e.first*numV + e.second; };
-	// When we pass a hash function object, we also need to specify the number of buckets.
-	// The Euler characteristic says that the number of undirected edges is numV + numF -2*genus.
-	std::unordered_map< directed_edge, std::pair< int, int >, decltype( edge_hasher ) > directed_position_edge2face_position_index( 2*( numV + numF ), edge_hasher );
-    for( int fi = 0; fi < F.rows(); ++fi ) {
-        for( int i = 0; i < 3; ++i ) {
-            const int j = ( i+1 ) % 3;
-            directed_position_edge2face_position_index[ std::make_pair( F(fi,i), F(fi,j) ) ] = std::make_pair( fi, i );
-        }
+	const auto& edge_hasher = 
+    [numV]( directed_edge const& e ) { return e.first*numV + e.second; };
+  // When we pass a hash function object, we also need to specify the number of
+  // buckets. The Euler characteristic says that the number of undirected edges
+  // is numV + numF -2*genus.
+	std::unordered_map<directed_edge,std::pair<int,int>,decltype(edge_hasher) > 
+    directed_position_edge2face_position_index(2*( numV + numF ), edge_hasher);
+  for( int fi = 0; fi < F.rows(); ++fi ) 
+  {
+    for( int i = 0; i < 3; ++i )
+    {
+      const int j = ( i+1 ) % 3;
+      directed_position_edge2face_position_index[ 
+        std::make_pair( F(fi,i), F(fi,j) ) ] = std::make_pair( fi, i );
     }
+  }
     
-    // First find all undirected position edges (collect a canonical orientation of
-    // the directed edges).
-    std::unordered_set< directed_edge, decltype( edge_hasher ) > undirected_position_edges( numV + numF, edge_hasher );
-    for( const auto& el : directed_position_edge2face_position_index ) {
-        // The canonical orientation is the one where the smaller of
-        // the two vertex indices is first.
-        undirected_position_edges.insert( std::make_pair( std::min( el.first.first, el.first.second ), std::max( el.first.first, el.first.second ) ) );
-    }
+  // First find all undirected position edges (collect a canonical orientation
+  // of the directed edges).
+  std::unordered_set< directed_edge, decltype( edge_hasher ) > 
+    undirected_position_edges( numV + numF, edge_hasher );
+  for( const auto& el : directed_position_edge2face_position_index ) 
+  {
+    // The canonical orientation is the one where the smaller of
+    // the two vertex indices is first.
+    undirected_position_edges.insert( std::make_pair( 
+      std::min( el.first.first, el.first.second ), 
+      std::max( el.first.first, el.first.second ) ) );
+  }
     
-    // Now we will iterate over all position edges.
-    // Seam edges are the edges whose two opposite directed edges have different
-    // texcoord indices (or one doesn't exist at all in the case of a mesh
-    // boundary).
-    for( const auto& vp_edge : undirected_position_edges ) {
-        // We should only see canonical edges,
-        // where the first vertex index is smaller.
-        assert( vp_edge.first < vp_edge.second );
+  // Now we will iterate over all position edges.
+  // Seam edges are the edges whose two opposite directed edges have different
+  // texcoord indices (or one doesn't exist at all in the case of a mesh
+  // boundary).
+  for( const auto& vp_edge : undirected_position_edges ) 
+  {
+    // We should only see canonical edges,
+    // where the first vertex index is smaller.
+    assert( vp_edge.first < vp_edge.second );
         
-        const auto vp_edge_reverse = std::make_pair( vp_edge.second, vp_edge.first );
-        // If it and its opposite exist as directed edges, check if their
-        // texture coordinate indices match.
-        if( directed_position_edge2face_position_index.count( vp_edge ) &&
-            directed_position_edge2face_position_index.count( vp_edge_reverse ) ) {
-            const auto forwards = directed_position_edge2face_position_index[ vp_edge ];
-            const auto backwards = directed_position_edge2face_position_index[ vp_edge_reverse ];
-            
-            // NOTE: They should never be equal.
-            assert( forwards != backwards );
+    const auto vp_edge_reverse = std::make_pair(vp_edge.second, vp_edge.first);
+    // If it and its opposite exist as directed edges, check if their
+    // texture coordinate indices match.
+    if( directed_position_edge2face_position_index.count( vp_edge ) &&
+      directed_position_edge2face_position_index.count( vp_edge_reverse ) ) 
+    {
+      const auto forwards = 
+        directed_position_edge2face_position_index[ vp_edge ];
+      const auto backwards = 
+        directed_position_edge2face_position_index[ vp_edge_reverse ];
             
-            // If the texcoord indices match (are similarly flipped),
-            // this edge is not a seam. It could be a foldover.
-            if( std::make_pair( FTC( forwards.first, forwards.second ), FTC( forwards.first, ( forwards.second+1 ) % 3 ) )
-                ==
-                std::make_pair( FTC( backwards.first, ( backwards.second+1 ) % 3 ), FTC( backwards.first, backwards.second ) )
-                ) {
-                
-                // Check for foldovers in UV space.
-                // Get the edge (a,b) and the two opposite vertices's texture coordinates.
-                const Vector2S a = TC.row( FTC( forwards.first,  forwards.second ) );
-                const Vector2S b = TC.row( FTC( forwards.first, (forwards.second+1) % 3 ) );
-                const Vector2S c_forwards  = TC.row( FTC( forwards .first, (forwards .second+2) % 3 ) );
-                const Vector2S c_backwards = TC.row( FTC( backwards.first, (backwards.second+2) % 3 ) );
-                // If the opposite vertices' texture coordinates fall on the same side
-                // of the edge, we have a UV-space foldover.
-                const auto orientation_forwards = Orientation( a, b, c_forwards );
-                const auto orientation_backwards = Orientation( a, b, c_backwards );
-                if( ( orientation_forwards > 0 && orientation_backwards > 0 ) ||
-                    ( orientation_forwards < 0 && orientation_backwards < 0 )
-                    ) {
-                    foldovers( num_foldovers, 0 ) = forwards.first;
-                    foldovers( num_foldovers, 1 ) = forwards.second;
-                    foldovers( num_foldovers, 2 ) = backwards.first;
-                    foldovers( num_foldovers, 3 ) = backwards.second;
-                    num_foldovers += 1;
-                }
-            }
+      // NOTE: They should never be equal.
+      assert( forwards != backwards );
             
-            // Otherwise, we have a non-matching seam edge.
-            else {
-                seams( num_seams, 0 ) = forwards.first;
-                seams( num_seams, 1 ) = forwards.second;
-                seams( num_seams, 2 ) = backwards.first;
-                seams( num_seams, 3 ) = backwards.second;
-                num_seams += 1;
-            }
-        }
-        // Otherwise, the edge and its opposite aren't both in the directed
-        // edges. One of them should be.
-        else if( directed_position_edge2face_position_index.count( vp_edge ) ) {
-            const auto forwards = directed_position_edge2face_position_index[ vp_edge ];
-            boundaries( num_boundaries, 0 ) = forwards.first;
-            boundaries( num_boundaries, 1 ) = forwards.second;
-            num_boundaries += 1;
-        }
-        else if( directed_position_edge2face_position_index.count( vp_edge_reverse ) ) {
-            const auto backwards = directed_position_edge2face_position_index[ vp_edge_reverse ];
-            boundaries( num_boundaries, 0 ) = backwards.first;
-            boundaries( num_boundaries, 1 ) = backwards.second;
-            num_boundaries += 1;
-        }
-        else {
-            // This should never happen! One of these two must have been seen.
-            assert(
-                directed_position_edge2face_position_index.count( vp_edge ) ||
-                directed_position_edge2face_position_index.count( vp_edge_reverse )
-                );
+      // If the texcoord indices match (are similarly flipped),
+      // this edge is not a seam. It could be a foldover.
+      if( 
+        std::make_pair( 
+          FTC( forwards.first, forwards.second ), 
+          FTC( forwards.first, ( forwards.second+1 ) % 3 ) )
+        ==
+        std::make_pair( 
+          FTC( backwards.first, ( backwards.second+1 ) % 3 ), 
+          FTC( backwards.first, backwards.second ) )) 
+      {
+        // Check for foldovers in UV space.
+        // Get the edge (a,b) and the two opposite vertices's texture
+        // coordinates.
+        const Vector2S a = TC.row( FTC( forwards.first,  forwards.second ) );
+        const Vector2S b = 
+          TC.row( FTC( forwards.first, (forwards.second+1) % 3 ) );
+        const Vector2S c_forwards  = 
+          TC.row( FTC( forwards .first, (forwards .second+2) % 3 ) );
+        const Vector2S c_backwards = 
+          TC.row( FTC( backwards.first, (backwards.second+2) % 3 ) );
+        // If the opposite vertices' texture coordinates fall on the same side
+        // of the edge, we have a UV-space foldover.
+        const auto orientation_forwards = Orientation( a, b, c_forwards );
+        const auto orientation_backwards = Orientation( a, b, c_backwards );
+        if( ( orientation_forwards > 0 && orientation_backwards > 0 ) ||
+            ( orientation_forwards < 0 && orientation_backwards < 0 )
+            ) {
+            foldovers( num_foldovers, 0 ) = forwards.first;
+            foldovers( num_foldovers, 1 ) = forwards.second;
+            foldovers( num_foldovers, 2 ) = backwards.first;
+            foldovers( num_foldovers, 3 ) = backwards.second;
+            num_foldovers += 1;
         }
+      }
+      // Otherwise, we have a non-matching seam edge.
+      else 
+      {
+        seams( num_seams, 0 ) = forwards.first;
+        seams( num_seams, 1 ) = forwards.second;
+        seams( num_seams, 2 ) = backwards.first;
+        seams( num_seams, 3 ) = backwards.second;
+        num_seams += 1;
+      }
+    }
+    // Otherwise, the edge and its opposite aren't both in the directed edges.
+    // One of them should be.
+    else if( directed_position_edge2face_position_index.count( vp_edge ) ) 
+    {
+      const auto forwards = directed_position_edge2face_position_index[vp_edge];
+      boundaries( num_boundaries, 0 ) = forwards.first;
+      boundaries( num_boundaries, 1 ) = forwards.second;
+      num_boundaries += 1;
+    } else if( 
+      directed_position_edge2face_position_index.count( vp_edge_reverse ) ) 
+    {
+      const auto backwards = 
+        directed_position_edge2face_position_index[ vp_edge_reverse ];
+      boundaries( num_boundaries, 0 ) = backwards.first;
+      boundaries( num_boundaries, 1 ) = backwards.second;
+      num_boundaries += 1;
+    } else {
+      // This should never happen! One of these two must have been seen.
+      assert(
+        directed_position_edge2face_position_index.count( vp_edge ) ||
+        directed_position_edge2face_position_index.count( vp_edge_reverse )
+      );
     }
+  }
     
-    seams     .conservativeResize( num_seams,      Eigen::NoChange_t() );
-    boundaries.conservativeResize( num_boundaries, Eigen::NoChange_t() );
-    foldovers .conservativeResize( num_foldovers,  Eigen::NoChange_t() );
+  seams     .conservativeResize( num_seams,      Eigen::NoChange_t() );
+  boundaries.conservativeResize( num_boundaries, Eigen::NoChange_t() );
+  foldovers .conservativeResize( num_foldovers,  Eigen::NoChange_t() );
 }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+// generated by autoexplicit.sh
+template void igl::seam_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 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::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<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<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif

+ 48 - 41
include/igl/seam_edges.h

@@ -11,47 +11,54 @@
 #include <Eigen/Core>
 namespace igl
 {
-    /*
-    Returns all UV-space boundaries of a mesh.
-    Inputs:
-        V: The positions of the input mesh.
-        TC: The 2D texture coordinates of the input mesh (2 columns).
-        F: A manifold-with-boundary triangle mesh, as vertex indices into `V` for the three vertices of each triangle.
-        FTC: Indices into `TC` for the three vertices of each triangle.
-    Outputs:
-        seams: Edges where the forwards and backwards directions have different texture
-               coordinates, as a #seams-by-4 matrix of indices.
-               Each row is organized as [ forward_face_index, forward_face_vertex_index,
-               backwards_face_index, backwards_face_vertex_index ]
-               such that one side of the seam is the edge:
-                    F[ seams( i, 0 ), seams( i, 1 ) ], F[ seams( i, 0 ), (seams( i, 1 ) + 1) % 3 ]
-               and the other side is the edge:
-                    F[ seams( i, 2 ), seams( i, 3 ) ], F[ seams( i, 2 ), (seams( i, 3 ) + 1) % 3 ]
-        boundaries: Edges with only one incident triangle, as a #boundaries-by-2 matrix of
-                    indices. Each row is organized as [ face_index, face_vertex_index ]
-                    such that the edge is:
-                        F[ boundaries( i, 0 ), boundaries( i, 1 ) ], F[ boundaries( i, 0 ), (boundaries( i, 1 ) + 1) % 3 ]
-        foldovers: Edges where the two incident triangles fold over each other in UV-space,
-                   as a #foldovers-by-4 matrix of indices.
-                   Each row is organized as [ forward_face_index, forward_face_vertex_index,
-                   backwards_face_index, backwards_face_vertex_index ]
-                   such that one side of the foldover is the edge:
-                        F[ foldovers( i, 0 ), foldovers( i, 1 ) ], F[ foldovers( i, 0 ), (foldovers( i, 1 ) + 1) % 3 ]
-                   and the other side is the edge:
-                        F[ foldovers( i, 2 ), foldovers( i, 3 ) ], F[ foldovers( i, 2 ), (foldovers( i, 3 ) + 1) % 3 ]
-    */
-    template <typename DerivedV, typename DerivedF, typename DerivedT>
-    IGL_INLINE void seam_edges(
-        const Eigen::PlainObjectBase<DerivedV>& V,
-        const Eigen::PlainObjectBase<DerivedT>& TC,
-        const Eigen::PlainObjectBase<DerivedF>& F,
-        const Eigen::PlainObjectBase<DerivedF>& FTC,
-        Eigen::PlainObjectBase<DerivedF>& seams,
-        Eigen::PlainObjectBase<DerivedF>& boundaries,
-        Eigen::PlainObjectBase<DerivedF>& foldovers
-        );
+  // Finds all UV-space boundaries of a mesh.
+  //
+  // Inputs:
+  //   V  #V by dim list of positions of the input mesh.
+  //   TC  #TC by 2 list of 2D texture coordinates of the input mesh
+  //   F  #F by 3 list of triange indices into V representing a
+  //     manifold-with-boundary triangle mesh
+  //   FTC  #F by 3 list of indices into TC for each corner
+  // Outputs:
+  //   seams  Edges where the forwards and backwards directions have different
+  //     texture coordinates, as a #seams-by-4 matrix of indices. Each row is
+  //     organized as [ forward_face_index, forward_face_vertex_index,
+  //     backwards_face_index, backwards_face_vertex_index ] such that one side
+  //     of the seam is the edge:
+  //         F[ seams( i, 0 ), seams( i, 1 ) ], F[ seams( i, 0 ), (seams( i, 1 ) + 1) % 3 ]
+  //     and the other side is the edge:
+  //         F[ seams( i, 2 ), seams( i, 3 ) ], F[ seams( i, 2 ), (seams( i, 3 ) + 1) % 3 ]
+  //   boundaries  Edges with only one incident triangle, as a #boundaries-by-2
+  //     matrix of indices. Each row is organized as 
+  //         [ face_index, face_vertex_index ]
+  //     such that the edge is:
+  //         F[ boundaries( i, 0 ), boundaries( i, 1 ) ], F[ boundaries( i, 0 ), (boundaries( i, 1 ) + 1) % 3 ]
+  //   foldovers  Edges where the two incident triangles fold over each other
+  //     in UV-space, as a #foldovers-by-4 matrix of indices.
+  //     Each row is organized as [ forward_face_index, forward_face_vertex_index,
+  //     backwards_face_index, backwards_face_vertex_index ]
+  //     such that one side of the foldover is the edge:
+  //       F[ foldovers( i, 0 ), foldovers( i, 1 ) ], F[ foldovers( i, 0 ), (foldovers( i, 1 ) + 1) % 3 ]
+  //     and the other side is the edge:
+  //       F[ foldovers( i, 2 ), foldovers( i, 3 ) ], F[ foldovers( i, 2 ), (foldovers( i, 3 ) + 1) % 3 ]
+  template <
+    typename DerivedV, 
+    typename DerivedTC,
+    typename DerivedF, 
+    typename DerivedFTC,
+    typename Derivedseams,
+    typename Derivedboundaries,
+    typename Derivedfoldovers>
+  IGL_INLINE void seam_edges(
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedTC>& TC,
+    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::PlainObjectBase<DerivedFTC>& FTC,
+    Eigen::PlainObjectBase<Derivedseams>& seams,
+    Eigen::PlainObjectBase<Derivedboundaries>& boundaries,
+    Eigen::PlainObjectBase<Derivedfoldovers>& foldovers);
 }
 #ifndef IGL_STATIC_LIBRARY
-#   include "seam_edges.cpp"
+#  include "seam_edges.cpp"
+#endif
 #endif
-#endif // IGL_SEAM_EDGES_H