Explorar o código

added new readOBJ prototype with more support (per corner normals and texture coordinates and non-triangle faces), along with example for mesh io (work in progress)

Former-commit-id: f89afa70a3997fd581956317de1c6d4399373365
jalec %!s(int64=13) %!d(string=hai) anos
pai
achega
25a30a188f

+ 22 - 0
examples/meshio/Makefile

@@ -0,0 +1,22 @@
+
+.PHONY: all
+
+all: example
+
+.PHONY: example
+
+igl_lib=-I../../
+eigen=-I/usr/local/include/eigen3
+
+CFLAGS=-g
+inc=$(igl_lib) $(eigen)
+lib=
+
+example: example.o
+	g++ $(CFLAGS) -o example example.o $(lib)
+
+example.o: example.cpp
+	g++ $(CFLAGS) -c example.cpp -o example.o $(inc)
+clean:
+	rm -f example.o
+	rm -f example

+ 9 - 0
examples/meshio/README

@@ -0,0 +1,9 @@
+This is a simple example program that shows how to use the mesh IO functions of
+readOBJ.h etc. in the igl library.
+
+
+To Build:
+  make
+
+To Run:
+  ./example [path_1] [path_2] ... [path_n]

+ 33 - 0
examples/meshio/cube.obj

@@ -0,0 +1,33 @@
+# cube.obj
+#
+ 
+g cube
+ 
+v  0.0  0.0  0.0
+v  0.0  0.0  1.0
+v  0.0  1.0  0.0
+v  0.0  1.0  1.0
+v  1.0  0.0  0.0
+v  1.0  0.0  1.0
+v  1.0  1.0  0.0
+v  1.0  1.0  1.0
+
+vn  0.0  0.0  1.0
+vn  0.0  0.0 -1.0
+vn  0.0  1.0  0.0
+vn  0.0 -1.0  0.0
+vn  1.0  0.0  0.0
+vn -1.0  0.0  0.0
+ 
+f  1//2  7//2  5//2
+f  1//2  3//2  7//2 
+f  1//6  4//6  3//6 
+f  1//6  2//6  4//6 
+f  3//3  8//3  7//3 
+f  3//3  4//3  8//3 
+f  5//5  7//5  8//5 
+f  5//5  8//5  6//5 
+f  1//4  5//4  6//4 
+f  1//4  6//4  2//4 
+f  2//1  6//1  8//1 
+f  2//1  8//1  4//1 

+ 51 - 0
examples/meshio/example.cpp

@@ -0,0 +1,51 @@
+#include "readOBJ.h"
+
+#include <cstdio>
+#include <vector>
+
+using namespace igl;
+using namespace std;
+
+// Template:
+//   T  type that can be safely cast to float
+// Inputs:
+//   vv  vector of vectors of type T
+template <typename T>
+void print_vector_of_vectors_as_floats(const std::vector<std::vector<T > > & vv)
+{
+  for(int i = 0;i<vv.size();i++)
+  {
+    for(int j = 0;j<vv[i].size();j++)
+    {
+      printf("%g ",(float)(vv[i][j]));
+    }
+    printf("\n");
+  }
+}
+
+int main(int argc, char * argv[])
+{
+  if(argc <= 1)
+  {
+    printf("USAGE:\n  ./example [path_1] [path_2] ... [path_n]\n");
+    return 1;
+  }
+  std::vector<std::vector<double> > V,TC,N;
+  std::vector<std::vector<int> > F,FTC,FN;
+  // loop over arguments
+  for(int i = 1; i < argc; i++)
+  {
+    if(i != 1)
+    {
+      printf("-----------------------------------------------------------\n");
+    }
+    readOBJ(argv[i],V,TC,N,F,FTC,FN);
+    cout<<"V=[";  print_vector_of_vectors_as_floats(V);  cout<<"];"<<endl;
+    cout<<"TC=["; print_vector_of_vectors_as_floats(TC); cout<<"];"<<endl;
+    cout<<"N=[";  print_vector_of_vectors_as_floats(N);  cout<<"];"<<endl;
+    cout<<"F=[";  print_vector_of_vectors_as_floats(F);  cout<<"];"<<endl;
+    cout<<"FTC=[";print_vector_of_vectors_as_floats(FTC);cout<<"];"<<endl;
+    cout<<"FN=["; print_vector_of_vectors_as_floats(FN); cout<<"];"<<endl;
+  }
+  return 0;
+}

+ 88 - 0
examples/meshio/torus.obj

@@ -0,0 +1,88 @@
+####
+#
+# OBJ File Generated by Meshlab
+#
+####
+# Object TinyTorus.obj
+#
+# Vertices: 24
+# Faces: 48
+#
+####
+v -2.000000 0.000000 0.000000
+v -3.000000 0.000000 -1.000000
+v -4.000000 0.000000 -0.000001
+v -3.000000 0.000000 1.000000
+v -1.000000 -1.732050 0.000000
+v -1.500000 -2.598080 -1.000000
+v -2.000000 -3.464100 -0.000001
+v -1.500000 -2.598080 1.000000
+v 1.000000 -1.732050 0.000000
+v 1.500000 -2.598080 -1.000000
+v 2.000000 -3.464100 -0.000001
+v 1.500000 -2.598080 1.000000
+v 2.000000 0.000000 0.000000
+v 3.000000 0.000000 -1.000000
+v 4.000000 0.000000 -0.000001
+v 3.000000 0.000000 1.000000
+v 1.000000 1.732050 0.000000
+v 1.500000 2.598080 -1.000000
+v 2.000000 3.464100 -0.000001
+v 1.500000 2.598080 1.000000
+v -1.000000 1.732050 0.000000
+v -1.500000 2.598080 -1.000000
+v -2.000000 3.464100 -0.000001
+v -1.500000 2.598080 1.000000
+# 24 vertices, 0 vertices normals
+
+f 2 1 6
+f 5 6 1
+f 3 2 7
+f 6 7 2
+f 4 3 8
+f 7 8 3
+f 1 4 5
+f 8 5 4
+f 6 5 10
+f 9 10 5
+f 7 6 11
+f 10 11 6
+f 8 7 12
+f 11 12 7
+f 5 8 9
+f 12 9 8
+f 10 9 14
+f 13 14 9
+f 11 10 15
+f 14 15 10
+f 12 11 16
+f 15 16 11
+f 9 12 13
+f 16 13 12
+f 14 13 18
+f 17 18 13
+f 15 14 19
+f 18 19 14
+f 16 15 20
+f 19 20 15
+f 13 16 17
+f 20 17 16
+f 18 17 22
+f 21 22 17
+f 19 18 23
+f 22 23 18
+f 20 19 24
+f 23 24 19
+f 17 20 21
+f 24 21 20
+f 22 21 2
+f 1 2 21
+f 23 22 3
+f 2 3 22
+f 24 23 4
+f 3 4 23
+f 21 24 1
+f 4 1 24
+# 48 faces, 0 coords texture
+
+# End of File

+ 229 - 8
readOBJ.h

@@ -5,14 +5,14 @@
 
 // History:
 //  return type changed from void to bool  Alec 18 Sept 2011
+//  added pure vector of vectors version that has much more support Alec 31 Oct
+//    2011
 
 #ifndef IGL_READOBJ_H
 #define IGL_READOBJ_H
 
 #include <Eigen/Core>
 #include <string>
-#include <iostream>
-#include <fstream>
 #include <vector>
 
 namespace igl 
@@ -30,17 +30,46 @@ namespace igl
   // KNOWN BUG: This only knows how to face lines without normal or texture
   // indices. It will probably crash or give garbage on anything else.
   inline bool readOBJ(const std::string str, Eigen::MatrixXd& V, Eigen::MatrixXi& F);
+  // 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>
+  inline bool 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);
 }
 
 // Implementation
+#include <iostream>
+#include <fstream>
+
 inline bool igl::readOBJ(const std::string str, Eigen::MatrixXd& V, Eigen::MatrixXi& F)
 {
-    std::ifstream s(str.c_str());
-    if (s.is_open() == false)
-    {
-      fprintf (stderr, "readOBJ(): could not open file %s", str.c_str());
-      return false;
-    }
+  std::ifstream s(str.c_str());
+  if (s.is_open() == false)
+  {
+    fprintf (stderr, "readOBJ(): could not open file %s", str.c_str());
+    return false;
+  }
     std::vector<Eigen::Vector3d> Vtemp;
     std::vector<Eigen::Vector3i> Ftemp;
     char buf[1000];
@@ -75,4 +104,196 @@ inline bool igl::readOBJ(const std::string str, Eigen::MatrixXd& V, Eigen::Matri
     return true;
 }
 
+template <typename Scalar, typename Index>
+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)
+{
+  // 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());
+    return false;
+  }
+  // File open was succesfull so clear outputs
+  V.clear();
+  TC.clear();
+  N.clear();
+  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;
+  // flag for whether vertex normals exist in file
+  bool has_normals = false;
+  // Constant strings to compare against
+  std::string v("v");
+  std::string vn("vn");
+  std::string vt("vt");
+  std::string f("f");
+  std::string tic_tac_toe("#");
+#ifndef LINE_MAX
+#  define LINE_MAX 2048
+#endif
+
+  char line[LINE_MAX];
+  int line_no = 1;
+  while (fgets(line, LINE_MAX, obj_file) != NULL) 
+  {
+    char type[LINE_MAX];
+    // Read first word containing type
+    if(sscanf(line, "%s",type) == 1)
+    {
+      // Get pointer to rest of line right after type
+      char * l = &line[strlen(type)];
+      if(type == v)
+      {
+        double x[4];
+        int count = 
+          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);
+          fclose(obj_file);
+          return false;
+        }
+        std::vector<Scalar > vertex(count);
+        for(int i = 0;i<count;i++)
+        {
+          vertex[i] = x[i];
+        }
+        V.push_back(vertex);
+      }else if(type == vn)
+      {
+        has_normals = true;
+        double x[3];
+        int count = 
+          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);
+          fclose(obj_file);
+          return false;
+        }
+        std::vector<Scalar > normal(count);
+        for(int i = 0;i<count;i++)
+        {
+          normal[i] = x[i];
+        }
+        N.push_back(normal);
+      }else if(type == vt)
+      {
+        has_texture = true;
+        double x[3];
+        int count = 
+          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);
+          fclose(obj_file);
+          return false;
+        }
+        std::vector<Scalar > tex(count);
+        for(int i = 0;i<count;i++)
+        {
+          tex[i] = x[i];
+        }
+        TC.push_back(tex);
+      }else if(type == f)
+      {
+        std::vector<Index > f;
+        std::vector<Index > ftc;
+        std::vector<Index > fn;
+        // Read each "word" after type
+        char word[LINE_MAX];
+        int offset;
+        while(sscanf(l,"%s%n",word,&offset) == 1)
+        {
+          // adjust offset
+          l += offset;
+          // Process word
+          unsigned int i,it,in;
+          if(sscanf(word,"%u/%u/%u",&i,&it,&in) == 3)
+          {
+            f.push_back(i-1);
+            ftc.push_back(it-1);
+            fn.push_back(in-1);
+          }else if(sscanf(word,"%u/%u",&i,&it) == 2)
+          {
+            f.push_back(i-1);
+            ftc.push_back(it-1);
+          }else if(sscanf(word,"%u//%u",&i,&in) == 2)
+          {
+            f.push_back(i-1);
+            fn.push_back(in-1);
+          }else if(sscanf(word,"%u",&i) == 1)
+          {
+            f.push_back(i-1);
+          }else
+          {
+            fprintf(stderr,
+              "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()))
+        {
+          // No matter what add each type to lists so that lists are the
+          // correct lengths
+          F.push_back(f);
+          FTC.push_back(ftc);
+          FN.push_back(fn);
+        }else
+        {
+          fprintf(stderr,
+            "Error: readOBJ() face on line %d has invalid format\n", line_no);
+          fclose(obj_file);
+          return false;
+        }
+      }else if(strlen(type) >= 1 && type[0] == '#')
+      {
+        //ignore comments
+      }else
+      {
+        //ignore any other lines
+        fprintf(stderr,
+          "Warning: readOBJ() ignored non-comment line %d:\n  %s",
+          line_no,
+          line);
+      }
+    }else
+    {
+      // ignore empty line
+    }
+    line_no++;
+  }
+  fclose(obj_file);
+
+  assert(F.size() == FN.size());
+  assert(F.size() == FTC.size());
+
+  return true;
+}
+
 #endif