Эх сурвалжийг харах

templates mesh reading/writing and normal computation functions

Former-commit-id: c71c80a660d02f72e7a7d841cee66ed14d713cbd
dolga 13 жил өмнө
parent
commit
b06ba7383e
26 өөрчлөгдсөн 567 нэмэгдсэн , 176 устгасан
  1. 1 1
      adjacency_list.cpp
  2. 4 0
      igl_inline.h
  3. 5 13
      normalize_rows.cpp
  4. 4 1
      normalize_rows.h
  5. 23 19
      per_corner_normals.cpp
  6. 12 10
      per_corner_normals.h
  7. 7 21
      per_face_normals.cpp
  8. 4 3
      per_face_normals.h
  9. 29 14
      per_vertex_normals.cpp
  10. 12 3
      per_vertex_normals.h
  11. 10 2
      read.cpp
  12. 5 1
      read.h
  13. 6 4
      readMESH.cpp
  14. 5 4
      readMESH.h
  15. 123 35
      readOBJ.cpp
  16. 30 3
      readOBJ.h
  17. 131 21
      readOFF.cpp
  18. 30 1
      readOFF.h
  19. 6 5
      vf.cpp
  20. 6 5
      vf.h
  21. 4 3
      write.cpp
  22. 4 3
      write.h
  23. 80 1
      writeOBJ.cpp
  24. 16 1
      writeOBJ.h
  25. 5 1
      writeOFF.cpp
  26. 5 1
      writeOFF.h

+ 1 - 1
adjacency_list.cpp

@@ -61,7 +61,7 @@ IGL_INLINE void igl::adjacency_list(
     
     for(int v=0; v<(int)SR.size();++v)
     {
-      std::vector<int>& vv = A.at(v);
+      std::vector<T>& vv = A.at(v);
       std::vector<std::vector<int> >& sr = SR[v];
       
       std::vector<std::vector<int> > pn = sr;

+ 4 - 0
igl_inline.h

@@ -1,5 +1,9 @@
 // This should *NOT* be contained in a IGL_*_H ifdef, since it may be defined
 // differently based on when it is included
+#ifdef IGL_INLINE
+#undef IGL_INLINE
+#endif
+
 #ifdef IGL_HEADER_ONLY
 #  define IGL_INLINE inline
 #else

+ 5 - 13
normalize_rows.cpp

@@ -1,6 +1,9 @@
 #include "normalize_rows.h"
 
-IGL_INLINE void igl::normalize_rows(const Eigen::MatrixXd & A, Eigen::MatrixXd & B)
+template <typename DerivedV>
+IGL_INLINE void igl::normalize_rows(
+                               const Eigen::PlainObjectBase<DerivedV>& A,
+                               Eigen::PlainObjectBase<DerivedV> & B)
 {
   // Resize output
   B.resize(A.rows(),A.cols());
@@ -8,17 +11,6 @@ IGL_INLINE void igl::normalize_rows(const Eigen::MatrixXd & A, Eigen::MatrixXd &
   // loop over rows
   for(int i = 0; i < A.rows();i++)
   {
-    double length = 0;
-    // loop over cols
-    for(int j = 0; j < A.cols();j++)
-    {
-      length += A(i,j)*A(i,j);
-    }
-    length = sqrt(length);
-    // loop over cols
-    for(int j = 0; j < A.cols();j++)
-    {
-      B(i,j) = A(i,j) / length;
-    }
+    B.row(i) = A.row(i).normalized();
   }
 }

+ 4 - 1
normalize_rows.h

@@ -11,7 +11,10 @@ namespace igl
   //   A  #rows by k input matrix
   // Outputs:
   //   B  #rows by k input matrix, can be the same as A
-  IGL_INLINE void normalize_rows(const Eigen::MatrixXd & A, Eigen::MatrixXd & B);
+  template <typename DerivedV>
+  IGL_INLINE void normalize_rows(
+                                 const Eigen::PlainObjectBase<DerivedV>& A,
+                                 Eigen::PlainObjectBase<DerivedV> & B);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 23 - 19
per_corner_normals.cpp

@@ -4,29 +4,31 @@
 #include "per_face_normals.h"
 #include "PI.h"
 
+template <typename DerivedV, typename DerivedF>
 IGL_INLINE void igl::per_corner_normals(
-  const Eigen::MatrixXd & V,
-  const Eigen::MatrixXi & F,
-  const double corner_threshold,
-  Eigen::MatrixXd & CN)
+                                   const Eigen::PlainObjectBase<DerivedV>& V,
+                                   const Eigen::PlainObjectBase<DerivedF>& F,
+                                   const double corner_threshold,
+                                   Eigen::PlainObjectBase<DerivedV> & CN)
 {
   using namespace igl;
   using namespace Eigen;
   using namespace std;
-  MatrixXd FN;
+  Eigen::PlainObjectBase<DerivedV> FN;
   per_face_normals(V,F,FN);
   vector<vector<int> > VF,VFi;
   vf(V,F,VF,VFi);
   return per_corner_normals(V,F,FN,VF,corner_threshold,CN);
 }
 
+template <typename DerivedV, typename DerivedF, typename IndexType>
 IGL_INLINE void igl::per_corner_normals(
-    const Eigen::MatrixXd & V,
-    const Eigen::MatrixXi & F,
-    const Eigen::MatrixXd & FN,
-    const std::vector<std::vector<int> >& VF,
-    const double corner_threshold,
-    Eigen::MatrixXd & CN)
+                                   const Eigen::PlainObjectBase<DerivedV>& V,
+                                   const Eigen::PlainObjectBase<DerivedF>& F,
+                                   const Eigen::PlainObjectBase<DerivedV>& FN,
+                                   const std::vector<std::vector<IndexType> >& VF,
+                                   const double corner_threshold,
+                                   Eigen::PlainObjectBase<DerivedV> & CN)
 {
   using namespace igl;
   using namespace Eigen;
@@ -34,37 +36,39 @@ IGL_INLINE void igl::per_corner_normals(
 
   // number of faces
   const int m = F.rows();
+  // valence of faces
+  const int n = F.cols();
+
   // initialize output to zero
-  CN = MatrixXd::Constant(m*3,3,0);
+  CN.resize(m*n,3);
 
   // loop over faces
   for(size_t i = 0;i<m;i++)
   {
     // Normal of this face
-    Vector3d fn = FN.row(i);
+    Eigen::Matrix<typename DerivedV::Scalar,3,1> fn = FN.row(i);
     // loop over corners
-    for(size_t j = 0;j<3;j++)
+    for(size_t j = 0;j<n;j++)
     {
-      std::vector<int> incident_faces = VF[F(i,j)];
+      const std::vector<IndexType> &incident_faces = VF[F(i,j)];
       // loop over faces sharing vertex of this corner
       for(int k = 0;k<(int)incident_faces.size();k++)
       {
-        Vector3d ifn = FN.row(incident_faces[k]);
+        Eigen::Matrix<typename DerivedV::Scalar,3,1> ifn = FN.row(incident_faces[k]);
         // dot product between face's normal and other face's normal
         double dp = fn.dot(ifn);
         // if difference in normal is slight then add to average
         if(dp > cos(corner_threshold*PI/180))
         {
           // add to running sum
-          CN.row(i*3+j) += ifn;
+          CN.row(i*n+j) += ifn;
         // else ignore
         }else
         {
         }
       }
       // normalize to take average
-      double length = CN.row(i*3+j).norm();
-      CN.row(i*3+j) /= length;
+      CN.row(i*n+j).normalize();
     }
   }
 }

+ 12 - 10
per_corner_normals.h

@@ -14,21 +14,23 @@ namespace igl
   // Output:
   //   CN  #F*3 by 3 eigen Matrix of mesh vertex 3D normals, where the normal
   //     for corner F(i,j) is at CN(i*3+j,:) 
+  template <typename DerivedV, typename DerivedF>
   IGL_INLINE void per_corner_normals(
-    const Eigen::MatrixXd & V,
-    const Eigen::MatrixXi & F,
-    const double corner_threshold,
-    Eigen::MatrixXd & CN);
+                                     const Eigen::PlainObjectBase<DerivedV>& V,
+                                     const Eigen::PlainObjectBase<DerivedF>& F,
+                                     const double corner_threshold,
+                                     Eigen::PlainObjectBase<DerivedV> & CN);
   // Other Inputs:
   //   FN  #F by 3 eigen Matrix of face normals
   //   VF  map from vertices to list of incident faces
+  template <typename DerivedV, typename DerivedF, typename IndexType>
   IGL_INLINE void per_corner_normals(
-    const Eigen::MatrixXd & V,
-    const Eigen::MatrixXi & F,
-    const Eigen::MatrixXd & FN,
-    const std::vector<std::vector<int> >& VF,
-    const double corner_threshold,
-    Eigen::MatrixXd & CN);
+                                     const Eigen::PlainObjectBase<DerivedV>& V,
+                                     const Eigen::PlainObjectBase<DerivedF>& F,
+                                     const Eigen::PlainObjectBase<DerivedV>& FN,
+                                     const std::vector<std::vector<IndexType> >& VF,
+                                     const double corner_threshold,
+                                     Eigen::PlainObjectBase<DerivedV> & CN);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 7 - 21
per_face_normals.cpp

@@ -1,31 +1,17 @@
 #include "per_face_normals.h"
 
+template <typename DerivedV, typename DerivedF>
 IGL_INLINE void igl::per_face_normals(
-  const Eigen::MatrixXd & V,
-  const Eigen::MatrixXi & F,
-  Eigen::MatrixXd & N)
+                                 const Eigen::PlainObjectBase<DerivedV>& V,
+                                 const Eigen::PlainObjectBase<DerivedF>& F,
+                                 Eigen::PlainObjectBase<DerivedV> & N)
 {
   N.resize(F.rows(),3);
   // loop over faces
   for(int i = 0; i < F.rows();i++)
   {
-    float v1[3];
-    v1[0] = V(F(i,1),0) - V(F(i,0),0);
-    v1[1] = V(F(i,1),1) - V(F(i,0),1);
-    v1[2] = V(F(i,1),2) - V(F(i,0),2);
-    float v2[3];
-    v2[0] = V(F(i,2),0) - V(F(i,0),0);
-    v2[1] = V(F(i,2),1) - V(F(i,0),1);
-    v2[2] = V(F(i,2),2) - V(F(i,0),2);
-    N(i,0) = v1[1]*v2[2] - v1[2]*v2[1];
-    N(i,1) = -(v1[0]*v2[2] - v1[2]*v2[0]);
-    N(i,2) = v1[0]*v2[1] - v1[1]*v2[0];
-    float length = sqrt(
-      N(i,0)*N(i,0) +
-      N(i,1)*N(i,1) +
-      N(i,2)*N(i,2));
-    N(i,0) /= length;
-    N(i,1) /=  length;
-    N(i,2) /=  length;
+    Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v1 = V.row(F(i,1)) - V.row(F(i,0));
+    Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v2 = V.row(F(i,2)) - V.row(F(i,0));
+    N.row(i) = (v1.cross(v2)).normalized();
   }
 }

+ 4 - 3
per_face_normals.h

@@ -10,10 +10,11 @@ namespace igl
   //   F  #F by 3 eigne Matrix of face (triangle) indices
   // Output:
   //   N  #F by 3 eigen Matrix of mesh face (triangle) 3D normals
+  template <typename DerivedV, typename DerivedF>
   IGL_INLINE void per_face_normals(
-    const Eigen::MatrixXd & V,
-    const Eigen::MatrixXi & F,
-    Eigen::MatrixXd & N);
+                                     const Eigen::PlainObjectBase<DerivedV>& V,
+                                     const Eigen::PlainObjectBase<DerivedF>& F,
+                                     Eigen::PlainObjectBase<DerivedV> & N);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 29 - 14
per_vertex_normals.cpp

@@ -3,35 +3,50 @@
 #include "per_face_normals.h"
 #include "normalize_rows.h"
 
+template <typename DerivedV, typename DerivedF>
 IGL_INLINE void igl::per_vertex_normals(
-  const Eigen::MatrixXd & V,
-  const Eigen::MatrixXi & F,
-  Eigen::MatrixXd & N)
+                                   const Eigen::PlainObjectBase<DerivedV>& V,
+                                   const Eigen::PlainObjectBase<DerivedF>& F,
+                                   Eigen::PlainObjectBase<DerivedV> & N)
 {
-  Eigen::MatrixXd PFN;
+  Eigen::PlainObjectBase<DerivedV> PFN;
   igl::per_face_normals(V,F,PFN);
 
   // Resize for output
-  N.resize(V.rows(),3);
-  // loop over vertices, setting normalize to 0
-  for(int i = 0; i < N.rows();i++)
+  N = Eigen::PlainObjectBase<DerivedV>::Zero(V.rows(),3);
+
+  // loop over faces
+  for(int i = 0; i < F.rows();i++)
   {
-    N(i,0) = 0;
-    N(i,1) = 0;
-    N(i,2) = 0;
+    // throw normal at each corner
+    for(int j = 0; j < 3;j++)
+    {
+      N.row(F(i,j)) += PFN.row(i);
+    }
   }
+  // normalize each row
+  igl::normalize_rows(N,N);
+}
 
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::per_vertex_normals(
+                                        const Eigen::PlainObjectBase<DerivedV>& V,
+                                        const Eigen::PlainObjectBase<DerivedF>& F,
+                                        const Eigen::PlainObjectBase<DerivedV>& FN,
+                                        Eigen::PlainObjectBase<DerivedV> & N)
+{
+  // Resize for output
+  N = Eigen::PlainObjectBase<DerivedV>::Zero(V.rows(),3);
+  
   // loop over faces
   for(int i = 0; i < F.rows();i++)
   {
     // throw normal at each corner
     for(int j = 0; j < 3;j++)
     {
-      N(F(i,j),0) += PFN(i,0);
-      N(F(i,j),1) += PFN(i,1);
-      N(F(i,j),2) += PFN(i,2);
+      N.row(F(i,j)) += FN.row(i);
     }
   }
   // normalize each row
   igl::normalize_rows(N,N);
-}
+}

+ 12 - 3
per_vertex_normals.h

@@ -14,10 +14,19 @@ namespace igl
   //   F  #F by 3 eigne Matrix of face (triangle) indices
   // Output:
   //   N  #V by 3 eigen Matrix of mesh vertex 3D normals
+  template <typename DerivedV, typename DerivedF>
   IGL_INLINE void per_vertex_normals(
-    const Eigen::MatrixXd & V,
-    const Eigen::MatrixXi & F,
-    Eigen::MatrixXd & N);
+                                   const Eigen::PlainObjectBase<DerivedV>& V,
+                                   const Eigen::PlainObjectBase<DerivedF>& F,
+                                   Eigen::PlainObjectBase<DerivedV> & N);
+
+  template <typename DerivedV, typename DerivedF>
+  IGL_INLINE void per_vertex_normals(
+                                     const Eigen::PlainObjectBase<DerivedV>& V,
+                                     const Eigen::PlainObjectBase<DerivedF>& F,
+                                     const Eigen::PlainObjectBase<DerivedV>& FN,
+                                     Eigen::PlainObjectBase<DerivedV> & N);
+
 }
 
 #ifdef IGL_HEADER_ONLY

+ 10 - 2
read.cpp

@@ -2,7 +2,11 @@
 
 #include "readOBJ.h"
 #include "readOFF.h"
-IGL_INLINE bool igl::read(const std::string str, Eigen::MatrixXd& V, Eigen::MatrixXi& F)
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::read(
+                     const std::string str,
+                     Eigen::PlainObjectBase<DerivedV>& V,
+                     Eigen::PlainObjectBase<DerivedF>& F)
 {
     const char* p;
     for (p = str.c_str(); *p != '\0'; p++)
@@ -16,9 +20,13 @@ IGL_INLINE bool igl::read(const std::string str, Eigen::MatrixXd& V, Eigen::Matr
     }else if (!strcmp(p, ".off") || !strcmp(p, ".OFF"))
     {
         return igl::readOFF(str,V,F);
-    }else
+    }
+    else 
     {
       fprintf(stderr,"read() does not recognize extension: %s\n",p);
       return false;
     }
 }
+
+#ifndef IGL_HEADER_ONLY
+#endif

+ 5 - 1
read.h

@@ -22,7 +22,11 @@ namespace igl
   // Outputs:
   //   V  eigen double matrix #V by 3
   //   F  eigen int matrix #F by 3
-  IGL_INLINE bool read(const std::string str, Eigen::MatrixXd& V, Eigen::MatrixXi& F);
+  template <typename DerivedV, typename DerivedF>
+  IGL_INLINE bool read(
+                       const std::string str,
+                       Eigen::PlainObjectBase<DerivedV>& V,
+                       Eigen::PlainObjectBase<DerivedF>& F);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 6 - 4
readMESH.cpp

@@ -241,11 +241,13 @@ IGL_INLINE bool igl::readMESH(
 #include <Eigen/Core>
 #include "list_to_matrix.h"
 
+
+template <typename DerivedV, typename DerivedF, typename DerivedT>
 IGL_INLINE bool igl::readMESH(
-  const std::string str,
-  Eigen::MatrixXd& V,
-  Eigen::MatrixXi& T,
-  Eigen::MatrixXi& F)
+                         const std::string str,
+                         Eigen::PlainObjectBase<DerivedV>& V,
+                         Eigen::PlainObjectBase<DerivedT>& T,
+                         Eigen::PlainObjectBase<DerivedF>& F)
 {
   std::vector<std::vector<double> > vV,vT,vF;
   bool success = igl::readMESH(str,vV,vT,vF);

+ 5 - 4
readMESH.h

@@ -33,11 +33,12 @@ namespace igl
   //   V  eigen double matrix #V by 3
   //   T  eigen int matrix #T by 4
   //   F  eigen int matrix #F by 3
+  template <typename DerivedV, typename DerivedF, typename DerivedT>
   IGL_INLINE bool readMESH(
-    const std::string str,
-    Eigen::MatrixXd& V,
-    Eigen::MatrixXi& T,
-    Eigen::MatrixXi& F);
+                           const std::string str,
+                           Eigen::PlainObjectBase<DerivedV>& V,
+                           Eigen::PlainObjectBase<DerivedT>& T,
+                           Eigen::PlainObjectBase<DerivedF>& F);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 123 - 35
readOBJ.cpp

@@ -7,20 +7,20 @@
 
 template <typename Scalar, typename Index>
 IGL_INLINE bool igl::readOBJ(
-  const std::string obj_file_name, 
-  std::vector<std::vector<Scalar > > & V,
-  std::vector<std::vector<Scalar > > & TC,
-  std::vector<std::vector<Scalar > > & N,
-  std::vector<std::vector<Index > > & F,
-  std::vector<std::vector<Index > > & FTC,
-  std::vector<std::vector<Index > > & FN)
+                             const std::string obj_file_name, 
+                             std::vector<std::vector<Scalar > > & V,
+                             std::vector<std::vector<Scalar > > & TC,
+                             std::vector<std::vector<Scalar > > & N,
+                             std::vector<std::vector<Index > > & F,
+                             std::vector<std::vector<Index > > & FTC,
+                             std::vector<std::vector<Index > > & FN)
 {
   // Open file, and check for error
   FILE * obj_file = fopen(obj_file_name.c_str(),"r");
   if(NULL==obj_file)
   {
     fprintf(stderr,"IOError: %s could not be opened...\n",
-      obj_file_name.c_str());
+            obj_file_name.c_str());
     return false;
   }
   // File open was succesfull so clear outputs
@@ -30,7 +30,7 @@ IGL_INLINE bool igl::readOBJ(
   F.clear();
   FTC.clear();
   FN.clear();
-
+  
   // variables an constants to assist parsing the .obj file
   // flag for whether vertex texture coordinates exist in file
   bool has_texture = false;
@@ -45,7 +45,7 @@ IGL_INLINE bool igl::readOBJ(
 #ifndef LINE_MAX
 #  define LINE_MAX 2048
 #endif
-
+  
   char line[LINE_MAX];
   int line_no = 1;
   while (fgets(line, LINE_MAX, obj_file) != NULL) 
@@ -60,12 +60,12 @@ IGL_INLINE bool igl::readOBJ(
       {
         double x[4];
         int count = 
-          sscanf(l,"%lf %lf %lf %lf\n",&x[0],&x[1],&x[2],&x[3]);
+        sscanf(l,"%lf %lf %lf %lf\n",&x[0],&x[1],&x[2],&x[3]);
         if(count != 3 && count != 4)
         {
           fprintf(stderr, 
-            "Error: readOBJ() vertex on line %d should have 3 or 4 coordinates", 
-            line_no);
+                  "Error: readOBJ() vertex on line %d should have 3 or 4 coordinates", 
+                  line_no);
           fclose(obj_file);
           return false;
         }
@@ -80,12 +80,12 @@ IGL_INLINE bool igl::readOBJ(
         has_normals = true;
         double x[3];
         int count = 
-          sscanf(l,"%lf %lf %lf\n",&x[0],&x[1],&x[2]);
+        sscanf(l,"%lf %lf %lf\n",&x[0],&x[1],&x[2]);
         if(count != 3)
         {
           fprintf(stderr, 
-            "Error: readOBJ() normal on line %d should have 3 coordinates", 
-            line_no);
+                  "Error: readOBJ() normal on line %d should have 3 coordinates", 
+                  line_no);
           fclose(obj_file);
           return false;
         }
@@ -100,12 +100,12 @@ IGL_INLINE bool igl::readOBJ(
         has_texture = true;
         double x[3];
         int count = 
-          sscanf(l,"%lf %lf %lf\n",&x[0],&x[1],&x[2]);
+        sscanf(l,"%lf %lf %lf\n",&x[0],&x[1],&x[2]);
         if(count != 2 && count != 3)
         {
           fprintf(stderr, 
-            "Error: readOBJ() vertex on line %d should have 2 or 3 coordinates", 
-            line_no);
+                  "Error: readOBJ() vertex on line %d should have 2 or 3 coordinates", 
+                  line_no);
           fclose(obj_file);
           return false;
         }
@@ -148,17 +148,17 @@ IGL_INLINE bool igl::readOBJ(
           }else
           {
             fprintf(stderr,
-              "Error: readOBJ() face on line %d has invalid element format\n",
-              line_no);
+                    "Error: readOBJ() face on line %d has invalid element format\n",
+                    line_no);
             fclose(obj_file);
             return false;
           }
         }
         if(
-          (f.size()>0 && fn.size() == 0 && ftc.size() == 0) ||
-          (f.size()>0 && fn.size() == f.size() && ftc.size() == 0) ||
-          (f.size()>0 && fn.size() == 0 && ftc.size() == f.size()) ||
-          (f.size()>0 && fn.size() == f.size() && ftc.size() == f.size()))
+           (f.size()>0 && fn.size() == 0 && ftc.size() == 0) ||
+           (f.size()>0 && fn.size() == f.size() && ftc.size() == 0) ||
+           (f.size()>0 && fn.size() == 0 && ftc.size() == f.size()) ||
+           (f.size()>0 && fn.size() == f.size() && ftc.size() == f.size()))
         {
           // No matter what add each type to lists so that lists are the
           // correct lengths
@@ -168,7 +168,7 @@ IGL_INLINE bool igl::readOBJ(
         }else
         {
           fprintf(stderr,
-            "Error: readOBJ() face on line %d has invalid format\n", line_no);
+                  "Error: readOBJ() face on line %d has invalid format\n", line_no);
           fclose(obj_file);
           return false;
         }
@@ -179,9 +179,9 @@ IGL_INLINE bool igl::readOBJ(
       {
         //ignore any other lines
         fprintf(stderr,
-          "Warning: readOBJ() ignored non-comment line %d:\n  %s",
-          line_no,
-          line);
+                "Warning: readOBJ() ignored non-comment line %d:\n  %s",
+                line_no,
+                line);
       }
     }else
     {
@@ -190,14 +190,102 @@ IGL_INLINE bool igl::readOBJ(
     line_no++;
   }
   fclose(obj_file);
-
+  
   assert(F.size() == FN.size());
   assert(F.size() == FTC.size());
+  
+  return true;
+}
 
+template <typename DerivedV, typename DerivedF, typename DerivedT>
+IGL_INLINE bool igl::readOBJ(
+                             const std::string str,
+                             Eigen::PlainObjectBase<DerivedV>& V,
+                             Eigen::PlainObjectBase<DerivedF>& F,
+                             Eigen::PlainObjectBase<DerivedV>& CN,
+                             Eigen::PlainObjectBase<DerivedF>& FN,
+                             Eigen::PlainObjectBase<DerivedT>& TC,
+                             Eigen::PlainObjectBase<DerivedF>& FTC)
+{
+  std::vector<std::vector<double> > vV,vTC,vN;
+  std::vector<std::vector<int> > vF,vFTC,vFN;
+  bool success = igl::readOBJ(str,vV,vTC,vN,vF,vFTC,vFN);
+  if(!success)
+  {
+    // readOBJ(str,vV,vTC,vN,vF,vFTC,vFN) should have already printed an error
+    // message to stderr
+    return false;
+  }
+  bool V_rect = igl::list_to_matrix(vV,V);
+  if(!V_rect)
+  {
+    // igl::list_to_matrix(vV,V) already printed error message to std err
+    return false;
+  }
+  bool F_rect = igl::list_to_matrix(vF,F);
+  if(!F_rect)
+  {
+    // igl::list_to_matrix(vF,F) already printed error message to std err
+    return false;
+  }
+  if(!vN.empty())
+  {
+    bool VN_rect = igl::list_to_matrix(vN,CN);
+    if(!VN_rect)
+    {
+      // igl::list_to_matrix(vV,V) already printed error message to std err
+      return false;
+    }
+  }
+  
+  if(!vFN.empty())
+  {
+    bool FN_rect = igl::list_to_matrix(vFN,FN);
+    if(!FN_rect)
+    {
+      // igl::list_to_matrix(vV,V) already printed error message to std err
+      return false;
+    }
+  }
+  
+  if(!vTC.empty())
+  {
+    
+    bool T_rect = igl::list_to_matrix(vTC,TC);
+    if(!T_rect)
+    {
+      // igl::list_to_matrix(vTC,T) already printed error message to std err
+      return false;
+    }
+  }
+  if(!vFTC.empty())
+  {
+    
+    bool FTC_rect = igl::list_to_matrix(vFTC,FTC);
+    if(!FTC_rect)
+    {
+      // igl::list_to_matrix(vF,F) already printed error message to std err
+      return false;
+    }
+  }
+  // Legacy
+  if(F.cols() != 3)
+  {
+    fprintf(stderr,
+            "Error: readOBJ(filename,V,F) is meant for reading triangle-only"
+            " meshes. This mesh has faces all with size %d. See readOBJ.h for other"
+            " options.\n",
+            (int)F.cols());
+    return false;
+  }
   return true;
 }
 
-IGL_INLINE bool igl::readOBJ(const std::string str, Eigen::MatrixXd& V, Eigen::MatrixXi& F)
+template <typename DerivedV, typename DerivedF, typename DerivedT>
+IGL_INLINE bool igl::readOBJ(
+                             const std::string str,
+                             Eigen::PlainObjectBase<DerivedV>& V,
+                             Eigen::PlainObjectBase<DerivedF>& F)
 {
   std::vector<std::vector<double> > vV,vTC,vN;
   std::vector<std::vector<int> > vF,vFTC,vFN;
@@ -224,10 +312,10 @@ IGL_INLINE bool igl::readOBJ(const std::string str, Eigen::MatrixXd& V, Eigen::M
   if(F.cols() != 3)
   {
     fprintf(stderr,
-      "Error: readOBJ(filename,V,F) is meant for reading triangle-only"
-      " meshes. This mesh has faces all with size %d. See readOBJ.h for other"
-      " options.\n",
-      (int)F.cols());
+            "Error: readOBJ(filename,V,F) is meant for reading triangle-only"
+            " meshes. This mesh has faces all with size %d. See readOBJ.h for other"
+            " options.\n",
+            (int)F.cols());
     return false;
   }
   return true;

+ 30 - 3
readOBJ.h

@@ -49,15 +49,42 @@ namespace igl
   // Inputs:
   //   str  path to .obj file
   // Outputs:
-  //   V  eigen double matrix #V by 3
-  //   F  eigen int matrix #F by 3
+  //   V  eigen matrix #V by 3
+  //   F  eigen matrix #F by 3
   //
   // KNOWN BUG: This only knows how to read *triangle* meshes. It will probably
   // crash or give garbage on anything else.
   //
   // KNOWN BUG: This only knows how to face lines without normal or texture
   // indices. It will probably crash or give garbage on anything else.
-  IGL_INLINE bool readOBJ(const std::string str, Eigen::MatrixXd& V, Eigen::MatrixXi& F);
+  template <typename DerivedV, typename DerivedF, typename DerivedT>
+  IGL_INLINE bool readOBJ(
+                          const std::string str,
+                          Eigen::PlainObjectBase<DerivedV>& V,
+                          Eigen::PlainObjectBase<DerivedF>& F,
+                          Eigen::PlainObjectBase<DerivedV>& CN,
+                          Eigen::PlainObjectBase<DerivedF>& FN,
+                          Eigen::PlainObjectBase<DerivedT>& TC,
+                          Eigen::PlainObjectBase<DerivedF>& FTC);
+
+  //! Read a mesh from an ascii obj file
+  // Inputs:
+  //   str  path to .obj file
+  // Outputs:
+  //   V  eigen matrix #V by 3
+  //   F  eigen matrix #F by 3
+  //
+  // KNOWN BUG: This only knows how to read *triangle* meshes. It will probably
+  // crash or give garbage on anything else.
+  //
+  // KNOWN BUG: This only knows how to face lines without normal or texture
+  // indices. It will probably crash or give garbage on anything else.
+  template <typename DerivedV, typename DerivedF, typename DerivedT>
+  IGL_INLINE bool readOBJ(
+                          const std::string str,
+                          Eigen::PlainObjectBase<DerivedV>& V,
+                          Eigen::PlainObjectBase<DerivedF>& F);
+
 }
 
 #ifdef IGL_HEADER_ONLY

+ 131 - 21
readOFF.cpp

@@ -1,27 +1,137 @@
 #include "readOFF.h"
-
-IGL_INLINE bool igl::readOFF (const std::string meshfile, Eigen::MatrixXd& V, Eigen::MatrixXi& F)
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readOFF(
+                             const std::string off_file_name, 
+                             std::vector<std::vector<Scalar > > & V,
+                             std::vector<std::vector<Index > > & F)
 {
-    int vnum, fnum;
-    FILE *fp = fopen (meshfile.c_str(), "r");
-    
-    if (!fp)
+  FILE * off_file = fopen(off_file_name.c_str(),"r");                                       
+  if(NULL==off_file)
+  {
+    printf("IOError: %s could not be opened...",off_file_name.c_str());
+    return false; 
+  }
+  V.clear();
+  F.clear();
+  // First line is always OFF
+  char header[1000];
+  const std::string OFF("OFF");
+  const std::string NOFF("NOFF");
+  if(!fscanf(off_file,"%s\n",header)==1
+     || !(OFF == header || NOFF == header))
+  {
+    printf("Error: %s's first line should be OFF or NOFF not %s...",off_file_name.c_str(),header);
+    fclose(off_file);
+    return false; 
+  }
+  bool has_normals = NOFF==header;
+  // Second line is #vertices #faces #edges
+  int number_of_vertices;
+  int number_of_faces;
+  int number_of_edges;
+  char tic_tac_toe;
+  char line[1000];
+  bool still_comments = true;
+  while(still_comments)
+  {
+    fgets(line,1000,off_file);
+    still_comments = line[0] == '#';
+  }
+  sscanf(line,"%d %d %d",&number_of_vertices,&number_of_faces,&number_of_edges);
+  V.resize(number_of_vertices);
+  F.resize(number_of_faces);
+  //printf("%s %d %d %d\n",(has_normals ? "NOFF" : "OFF"),number_of_vertices,number_of_faces,number_of_edges);
+  // Read vertices
+  for(int i = 0;i<number_of_vertices;)
+  {
+    float x,y,z,nx,ny,nz;
+    if((has_normals && fscanf(off_file, "%g %g %g %g %g %g\n",&x,&y,&z,&nx,&ny,&nz)==6) || 
+       (!has_normals && fscanf(off_file, "%g %g %g\n",&x,&y,&z)==3))
+    {
+      std::vector<Scalar > vertex;
+      vertex.resize(3);
+      vertex[0] = x;
+      vertex[1] = y;
+      vertex[2] = z;
+      V[i] = vertex;
+      i++;
+    }else if(
+             fscanf(off_file,"%[#]",&tic_tac_toe)==1)
+    {
+      char comment[1000];
+      fscanf(off_file,"%[^\n]",comment);
+    }else
+    {
+      printf("Error: bad line in %s\n",off_file_name.c_str());
+      fclose(off_file);
+      return false;
+    }
+  }
+  // Read faces
+  for(int i = 0;i<number_of_faces;)
+  {
+    std::vector<Index > face;
+    int valence;
+    if(fscanf(off_file,"%d",&valence)==1)
     {
-      fprintf (stderr, "readOFF(): could not open file %s", meshfile.c_str());
+      face.resize(valence);
+      for(int j = 0;j<valence;j++)
+      {
+        int index;
+        if(j<valence-1)
+        {
+          fscanf(off_file,"%d",&index);
+        }else{
+          fscanf(off_file,"%d%*[^\n]",&index);
+        }
+        
+        face[j] = index;
+      }
+      F[i] = face;
+      i++;
+    }else if(
+             fscanf(off_file,"%[#]",&tic_tac_toe)==1)
+    {
+      char comment[1000];
+      fscanf(off_file,"%[^\n]",comment);
+    }else
+    {
+      printf("Error: bad line in %s\n",off_file_name.c_str());
+      fclose(off_file);
       return false;
     }
-    
-    fscanf (fp, "OFF\n%d %d 0\n",  &vnum, &fnum);
-    
-    V = Eigen::MatrixXd (vnum, 3);
-    F = Eigen::MatrixXi (fnum, 3);
-    
-    for (unsigned i = 0; i < V.rows(); i++)
-        fscanf (fp, "%lf %lf %lf\n", &V(i,0), &V(i,1), &V(i,2));
-    
-    for (unsigned i = 0; i < F.rows(); i++)
-        fscanf (fp, "3 %d %d %d\n", &F(i,0), &F(i,1), &F(i,2));
-    
-    fclose (fp);
-    return true;
+  }
+  fclose(off_file);
+  return true;
+}
+
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::readOFF(
+                        const std::string str,
+                        Eigen::PlainObjectBase<DerivedV>& V,
+                        Eigen::PlainObjectBase<DerivedF>& F)
+{
+  std::vector<std::vector<double> > vV;
+  std::vector<std::vector<int> > vF;
+  bool success = igl::readOFF(str,vV,vF);
+  if(!success)
+  {
+    // readOFF(str,vV,vF) should have already printed an error
+    // message to stderr
+    return false;
+  }
+  bool V_rect = igl::list_to_matrix(vV,V);
+  if(!V_rect)
+  {
+    // igl::list_to_matrix(vV,V) already printed error message to std err
+    return false;
+  }
+  bool F_rect = igl::list_to_matrix(vF,F);
+  if(!F_rect)
+  {
+    // igl::list_to_matrix(vF,F) already printed error message to std err
+    return false;
+  }
+  return true;
 }

+ 30 - 1
readOFF.h

@@ -15,13 +15,42 @@
 
 namespace igl 
 {
+  
+  // Read a mesh from an ascii obj file, filling in vertex positions, normals
+  // and texture coordinates. Mesh may have faces of any number of degree
+  //
+  // Templates:
+  //   Scalar  type for positions and vectors (will be read as double and cast
+  //     to Scalar)
+  //   Index  type for indices (will be read as int and cast to Index)
+  // Inputs:
+  //  str  path to .obj file
+  // Outputs:
+  //   V  double matrix of vertex positions  #V by 3
+  //   F  #F list of face indices into vertex positions
+  //   TC  double matrix of texture coordinats #TC by 2
+  //   FTC  #F list of face indices into vertex texture coordinates
+  //   N  double matrix of corner normals #N by 3
+  //   FN  #F list of face indices into vertex normals
+  // Returns true on success, false on errors
+  template <typename Scalar, typename Index>
+  IGL_INLINE bool readOFF(
+                          const std::string off_file_name, 
+                          std::vector<std::vector<Scalar > > & V,
+                          std::vector<std::vector<Index > > & F);
+  
+  
   // read mesh from a ascii off file
   // Inputs:
   //   str  path to .off file
   // Outputs:
   //   V  eigen double matrix #V by 3
   //   F  eigen int matrix #F by 3
-  IGL_INLINE bool readOFF (const std::string meshfile, Eigen::MatrixXd& V, Eigen::MatrixXi& F);
+  template <typename DerivedV, typename DerivedF>
+  IGL_INLINE bool readOFF(
+                          const std::string str,
+                          Eigen::PlainObjectBase<DerivedV>& V,
+                          Eigen::PlainObjectBase<DerivedF>& F);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 6 - 5
vf.cpp

@@ -2,11 +2,12 @@
 
 #include "verbose.h"
 
-template <typename T, typename S>
+template <typename DerivedV, typename DerivedF, typename IndexType>
 IGL_INLINE void igl::vf(
-  const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> & V, 
-  const Eigen::MatrixXi & F, 
-  std::vector<std::vector<T> >& VF, std::vector<std::vector<T> >& VFi)
+                   const Eigen::PlainObjectBase<DerivedV>& V,
+                   const Eigen::PlainObjectBase<DerivedF>& F,
+                   std::vector<std::vector<IndexType> >& VF,
+                   std::vector<std::vector<IndexType> >& VFi)
 {
   VF.clear();
   VFi.clear();
@@ -16,7 +17,7 @@ IGL_INLINE void igl::vf(
   
   for(int fi=0; fi<F.rows(); ++fi)
   {
-    for(int i = 0; i < 3; ++i)
+    for(int i = 0; i < F.cols(); ++i)
     {
       VF[F(fi,i)].push_back(fi);
       VFi[F(fi,i)].push_back(i);

+ 6 - 5
vf.h

@@ -16,11 +16,12 @@ namespace igl
   //
   // See also: edges, cotmatrix, diag, vv
     
-  template <typename T, typename S>
-  IGL_INLINE void vf( 
-    const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> & V, 
-    const Eigen::MatrixXi & F, 
-    std::vector<std::vector<T> >& VF, std::vector<std::vector<T> >& VFi);
+  template <typename DerivedV, typename DerivedF, typename IndexType>
+  IGL_INLINE void vf(
+                     const Eigen::PlainObjectBase<DerivedV>& V,
+                     const Eigen::PlainObjectBase<DerivedF>& F,
+                     std::vector<std::vector<IndexType> >& VF,
+                     std::vector<std::vector<IndexType> >& VFi);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 4 - 3
write.cpp

@@ -3,10 +3,11 @@
 #include "writeOBJ.h"
 #include "writeOFF.h"
 
+template <typename DerivedV, typename DerivedF>
 IGL_INLINE bool igl::write(
-  const std::string str, 
-  const Eigen::MatrixXd& V, 
-  const Eigen::MatrixXi& F)
+                      const std::string str,
+                      const Eigen::PlainObjectBase<DerivedV>& V,
+                      const Eigen::PlainObjectBase<DerivedF>& F)
 {
   const char* p;
   for (p = str.c_str(); *p != '\0'; p++)

+ 4 - 3
write.h

@@ -15,10 +15,11 @@ namespace igl
   // write mesh to an ascii file with automatic detection of file format. supported: obj, off)
   // Known Bugs:
   //  Does not correctly find file extensions: myfile.foo.off 
+  template <typename DerivedV, typename DerivedF>
   IGL_INLINE bool write(
-    const std::string str, 
-    const Eigen::MatrixXd& V, 
-    const Eigen::MatrixXi& F);
+                        const std::string str,
+                        const Eigen::PlainObjectBase<DerivedV>& V,
+                        const Eigen::PlainObjectBase<DerivedF>& F);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 80 - 1
writeOBJ.cpp

@@ -4,7 +4,11 @@
 #include <fstream>
 #include <cstdio>
 
-IGL_INLINE bool igl::writeOBJ(const std::string str, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::writeOBJ(
+                              const std::string str,
+                              const Eigen::PlainObjectBase<DerivedV>& V,
+                              const Eigen::PlainObjectBase<DerivedF>& F)
 {
   std::ofstream s(str.c_str());
 
@@ -23,3 +27,78 @@ IGL_INLINE bool igl::writeOBJ(const std::string str, const Eigen::MatrixXd& V, c
   s.close();
   return true;
 }
+
+template <typename DerivedV, typename DerivedF, typename DerivedT>
+IGL_INLINE bool igl::writeOBJ(
+                         const std::string str,
+                         const Eigen::PlainObjectBase<DerivedV>& V,
+                         const Eigen::PlainObjectBase<DerivedF>& F,
+                         const Eigen::PlainObjectBase<DerivedV>& CN,
+                         const Eigen::PlainObjectBase<DerivedF>& FN,
+                         const Eigen::PlainObjectBase<DerivedT>& TC,
+                         const Eigen::PlainObjectBase<DerivedF>& FTC)
+{
+  FILE * obj_file = fopen(str.c_str(),"w");
+  if(NULL==obj_file)
+  {
+    printf("IOError: %s could not be opened for writing...",str.c_str());
+    return false;                                              
+  }
+  // Loop over V
+  for(size_t i = 0;i<V.rows();i++)
+  {
+    fprintf(obj_file,"v %0.15g %0.15g %0.15g\n",
+            V(i,0),
+            V(i,1),
+            V(i,2)
+            );
+  }
+  bool write_N = CN.rows() >0;
+  
+  if(write_N)
+  {
+    for(size_t i = 0;i<CN.rows();i++)
+    {
+      fprintf(obj_file,"v %0.15g %0.15g %0.15g\n",
+              CN(i,0),
+              CN(i,1),
+              CN(i,2)
+              );
+    }
+    fprintf(obj_file,"\n");
+  }
+  
+  bool write_texture_coords = TC.rows() >0;
+  
+  if(write_texture_coords)
+  {
+    for(size_t i = 0;i<TC.rows();i++)
+    {
+      fprintf(obj_file, "vt %0.15g %0.15g\n",TC(i,0),1-TC(i,1));
+    }
+    fprintf(obj_file,"\n");
+  }
+  
+  // loop over F
+  for(size_t i = 0;i<F.rows();++i)
+  {
+    fprintf(obj_file,"f");
+    for(size_t j = 0; j<F.cols();++j)
+    {
+      // OBJ is 1-indexed
+      fprintf(obj_file," %u",F(i,j)+1);
+      
+      if(write_texture_coords)
+        fprintf(obj_file,"/%u",FTC(i,j)+1);
+      if(write_N)
+        if (write_texture_coords)
+          fprintf(obj_file,"/%u",FN(i,j)+1);
+        else
+          fprintf(obj_file,"//%u",FN(i,j)+1);
+      
+    }
+    fprintf(obj_file,"\n");
+  }
+  fclose(obj_file);
+  return true;  
+}

+ 16 - 1
writeOBJ.h

@@ -21,7 +21,22 @@ namespace igl
   //   V  eigen double matrix #V by 3 (mesh vertices)
   //   F  eigen int matrix #F by 3 (mesh indices)
   // Returns true on success, false on error
-  IGL_INLINE bool writeOBJ(const std::string str, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
+  template <typename DerivedV, typename DerivedF>
+  IGL_INLINE bool writeOBJ(
+                        const std::string str,
+                        const Eigen::PlainObjectBase<DerivedV>& V,
+                        const Eigen::PlainObjectBase<DerivedF>& F);
+  
+  template <typename DerivedV, typename DerivedF, typename DerivedT>
+  IGL_INLINE bool writeOBJ(
+                           const std::string str,
+                           const Eigen::PlainObjectBase<DerivedV>& V,
+                           const Eigen::PlainObjectBase<DerivedF>& F,
+                           const Eigen::PlainObjectBase<DerivedV>& CN,
+                           const Eigen::PlainObjectBase<DerivedF>& FN,
+                           const Eigen::PlainObjectBase<DerivedT>& TC,
+                           const Eigen::PlainObjectBase<DerivedF>& FTC);
+
 }
 
 #ifdef IGL_HEADER_ONLY

+ 5 - 1
writeOFF.cpp

@@ -1,7 +1,11 @@
 #include "writeOFF.h"
 
 // write mesh to an ascii off file
-IGL_INLINE bool igl::writeOFF(const std::string fname, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::writeOFF(
+                              const std::string fname,
+                              const Eigen::PlainObjectBase<DerivedV>& V,
+                              const Eigen::PlainObjectBase<DerivedF>& F)
 {
     FILE *fp = fopen (fname.c_str(), "w");
   

+ 5 - 1
writeOFF.h

@@ -12,7 +12,11 @@
 
 namespace igl 
 {
-    IGL_INLINE bool writeOFF(const std::string fname, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
+  template <typename DerivedV, typename DerivedF>
+  IGL_INLINE bool writeOFF(
+                        const std::string str,
+                        const Eigen::PlainObjectBase<DerivedV>& V,
+                        const Eigen::PlainObjectBase<DerivedF>& F);
 }
 
 #ifdef IGL_HEADER_ONLY