bool read_obj(Surface_mesh& mesh, const std::string& filename) { char s[200]; float x, y, z; std::vector<Surface_mesh::Vertex> vertices; std::vector<Texture_coordinate> all_tex_coords; //individual texture coordinates std::vector<int> halfedge_tex_idx; //texture coordinates sorted for halfedges Surface_mesh::Halfedge_property <Texture_coordinate> tex_coords = mesh.halfedge_property<Texture_coordinate>("h:texcoord"); bool with_tex_coord=false; // clear mesh mesh.clear(); // open file (in ASCII mode) FILE* in = fopen(filename.c_str(), "r"); if (!in) return false; // clear line once memset(&s, 0, 200); // parse line by line (currently only supports vertex positions & faces while(in && !feof(in) && fgets(s, 200, in)) { // comment if (s[0] == '#' || isspace(s[0])) continue; // vertex else if (strncmp(s, "v ", 2) == 0) { if (sscanf(s, "v %f %f %f", &x, &y, &z)) { mesh.add_vertex(Point(x,y,z)); } } // normal else if (strncmp(s, "vn ", 3) == 0) { if (sscanf(s, "vn %f %f %f", &x, &y, &z)) { // problematic as it can be either a vertex property when interpolated // or a halfedge property for hard edges } } // texture coordinate else if (strncmp(s, "vt ", 3) == 0) { if (sscanf(s, "vt %f %f", &x, &y)) { z=1; all_tex_coords.push_back(Texture_coordinate(x,y,z)); } } // face else if (strncmp(s, "f ", 2) == 0) { int component(0), nV(0); bool endOfVertex(false); char *p0, *p1(s+1); vertices.clear(); halfedge_tex_idx.clear(); // skip white-spaces while (*p1==' ') ++p1; while (p1) { p0 = p1; // overwrite next separator // skip '/', '\n', ' ', '\0', '\r' <-- don't forget Windows while (*p1!='/' && *p1!='\r' && *p1!='\n' && *p1!=' ' && *p1!='\0') ++p1; // detect end of vertex if (*p1 != '/') { endOfVertex = true; } // replace separator by '\0' if (*p1 != '\0') { *p1 = '\0'; p1++; // point to next token } // detect end of line and break if (*p1 == '\0' || *p1 == '\n') { p1 = 0; } // read next vertex component if (*p0 != '\0') { switch (component) { case 0: // vertex { vertices.push_back( Surface_mesh::Vertex(atoi(p0) - 1) ); break; } case 1: // texture coord { int idx = atoi(p0)-1; halfedge_tex_idx.push_back(idx); with_tex_coord=true; break; } case 2: // normal break; } } ++component; if (endOfVertex) { component = 0; nV++; endOfVertex = false; } } Surface_mesh::Face f=mesh.add_face(vertices); // add texture coordinates if(with_tex_coord) { Surface_mesh::Halfedge_around_face_circulator h_fit = mesh.halfedges(f); Surface_mesh::Halfedge_around_face_circulator h_end = h_fit; unsigned v_idx =0; do { tex_coords[*h_fit]=all_tex_coords.at(halfedge_tex_idx.at(v_idx)); ++v_idx; ++h_fit; } while(h_fit!=h_end); } } // clear line memset(&s, 0, 200); } fclose(in); return true; }
bool read_off_ascii(Surface_mesh& mesh, FILE* in, const bool has_normals, const bool has_texcoords, const bool has_colors, NamedParameters& np) { char line[100], *lp; unsigned int i, j, items, idx, nc; unsigned int nV, nF, nE; Vec3f p, n, c; Vec2f t; Surface_mesh::Vertex v; typename CGAL::Polygon_mesh_processing::GetVertexPointMap<Surface_mesh, NamedParameters>::const_type vpm = choose_param(get_param(np, CGAL::boost::internal_np::vertex_point), get_const_property_map(CGAL::vertex_point, mesh)); // properties Surface_mesh::Vertex_property<Normal> normals; Surface_mesh::Vertex_property<Texture_coordinate> texcoords; Surface_mesh::Vertex_property<Color> colors; if (has_normals) normals = mesh.vertex_property<Normal>("v:normal"); if (has_texcoords) texcoords = mesh.vertex_property<Texture_coordinate>("v:texcoord"); if (has_colors) colors = mesh.vertex_property<Color>("v:color"); // #Vertice, #Faces, #Edges items = fscanf(in, "%d %d %d\n", (int*)&nV, (int*)&nF, (int*)&nE); mesh.clear(); mesh.reserve(nV, std::max(3*nV, nE), nF); // read vertices: pos [normal] [color] [texcoord] for (i=0; i<nV && !feof(in); ++i) { // read line lp = fgets(line, 100, in); // position items = sscanf(lp, "%f %f %f%n", &p[0], &p[1], &p[2], &nc); assert(items==3); Surface_mesh::Vertex v = mesh.add_vertex(); put(vpm, v, (Point)p); lp += nc; // normal if (has_normals) { if (sscanf(lp, "%f %f %f%n", &n[0], &n[1], &n[2], &nc) == 3) { normals[v] = n; } lp += nc; } // color if (has_colors) { if (sscanf(lp, "%f %f %f%n", &c[0], &c[1], &c[2], &nc) == 3) { if (c[0]>1.0f || c[1]>1.0f || c[2]>1.0f) c *= (1.0/255.0); colors[v] = c; } lp += nc; } // tex coord if (has_texcoords) { items = sscanf(lp, "%f %f%n", &t[0], &t[1], &nc); assert(items == 2); texcoords[v][0] = t[0]; texcoords[v][1] = t[1]; lp += nc; } } // read faces: #N v[1] v[2] ... v[n-1] std::vector<Surface_mesh::Vertex> vertices; for (i=0; i<nF; ++i) { // read line lp = fgets(line, 100, in); // #vertices items = sscanf(lp, "%d%n", (int*)&nV, &nc); assert(items == 1); vertices.resize(nV); lp += nc; // indices for (j=0; j<nV; ++j) { items = sscanf(lp, "%d%n", (int*)&idx, &nc); assert(items == 1); vertices[j] = Surface_mesh::Vertex(idx); lp += nc; } mesh.add_face(vertices); } return true; }
bool read_off(Surface_mesh& mesh, const std::string& filename) { int err = 0; unsigned int i, j, idx; unsigned int nV, nF, nE; Eigen::Vector3d p, n; Eigen::Vector2d t; Surface_mesh::Vertex v; char line[100], *c; bool has_texcoords = false; bool has_normals = false; bool has_colors = false; bool has_hcoords = false; bool has_dim = false; bool is_binary = false; // if mesh is not empty we need an offset for vertex indices const unsigned int voffset = mesh.n_vertices(); // open file (in ASCII mode) FILE* in = fopen(filename.c_str(), "r"); if (!in) return false; // read header: [ST][C][N][4][n]OFF BINARY c = fgets(line, 100, in); assert(c != NULL); c = line; if (c[0] == 'S' && c[1] == 'T') { has_texcoords = true; c += 2; } if (c[0] == 'C') { has_colors = true; ++c; } if (c[0] == 'N') { has_normals = true; ++c; } if (c[0] == '4') { has_hcoords = true; ++c; } if (c[0] == 'n') { has_dim = true; ++c; } if (strncmp(c, "OFF", 3) != 0) { fclose(in); // no OFF return false; } if (strncmp(c+4, "BINARY", 6) == 0) is_binary = true; const bool binary = is_binary; // const might speed things up // colors, homogeneous coords, and vertex dimension != 3 are not supported if (has_colors || has_hcoords || has_dim) { fclose(in); return false; } // properties Surface_mesh::Vertex_property<Surface_mesh::Normal> normals; Surface_mesh::Vertex_property<Surface_mesh::Texture_coordinate> texcoords; if (has_normals) normals = mesh.vertex_property<Surface_mesh::Normal>("v:normal"); if (has_texcoords) texcoords = mesh.vertex_property<Surface_mesh::Texture_coordinate>("v:texcoord"); // if binary: reopen file in binary mode if (binary) { fclose(in); in = fopen(filename.c_str(), "rb"); c = fgets(line, 100, in); assert(c != NULL); } // (ennetws) bug fix for comments, empty lines.. while(!binary && true && !feof(in)) { fgets(line, 100, in); if(strlen(line) > 4 && line[0] != '#') break; } // #Vertice, #Faces, #Edges if (binary) { read(in, nV); read(in, nF); read(in, nE); } else { err = sscanf(line, "%d %d %d", (int*)&nV, (int*)&nF, (int*)&nE); // (ennetws) bug fix } mesh.reserve(nV, std::max(3*nV, nE), nF); // read vertices: pos [norma] [texcoord] if (has_normals && has_texcoords) { for (i=0; i<nV && !feof(in); ++i) { if (binary) { read(in, p); read(in, n); read(in, t); } else { err = fscanf(in, "%lf %lf %lf %lf %lf %lf %lf %lf", &p[0], &p[1], &p[2], &n[0], &n[1], &n[2], &t[0], &t[1]); } v = mesh.add_vertex(p); normals[v] = n; texcoords[v][0] = t[0]; texcoords[v][1] = t[1]; } } else if (has_normals) { for (i=0; i<nV && !feof(in); ++i) { if (binary) { read(in, p); read(in, n); } else { err = fscanf(in, "%lf %lf %lf %lf %lf %lf", &p[0], &p[1], &p[2], &n[0], &n[1], &n[2]); } v = mesh.add_vertex(p); normals[v] = n; } } else if (has_texcoords) { for (i=0; i<nV && !feof(in); ++i) { if (binary) { read(in, p); read(in, t); } else { err = fscanf(in, "%lf %lf %lf %lf %lf", &p[0], &p[1], &p[2], &t[0], &t[1]); } v = mesh.add_vertex(p); texcoords[v][0] = t[0]; texcoords[v][1] = t[1]; } } else { for (i=0; i<nV && !feof(in); ++i) { if (binary) { read(in, p); } else { err = fscanf(in, "%lf %lf %lf", &p[0], &p[1], &p[2]); } mesh.add_vertex(p); } } // read faces: #N v[1] v[2] ... v[n-1] std::vector<Surface_mesh::Vertex> vertices; for (i=0; i<nF; ++i) { if (binary) { read(in, nV); vertices.resize(nV); for (j=0; j<nV; ++j) { read(in, idx); vertices[j] = Surface_mesh::Vertex(idx+voffset); } } else { err = fscanf(in, "%d", (int*)&nV); vertices.resize(nV); for (j=0; j<nV; ++j) { err = fscanf(in, "%d", (int*)&idx); vertices[j] = Surface_mesh::Vertex(idx+voffset); } } mesh.add_face(vertices); } // File was successfully parsed. fclose(in); return true; }
bool read_off_binary(Surface_mesh& mesh, FILE* in, const bool has_normals, const bool has_texcoords, const bool has_colors, NamedParameters& np) { unsigned int i, j, idx; unsigned int nV, nF, nE; Vec3f p, n, c; Vec2f t; Surface_mesh::Vertex v; // binary cannot (yet) read colors if (has_colors) return false; // properties Surface_mesh::Vertex_property<Normal> normals; Surface_mesh::Vertex_property<Texture_coordinate> texcoords; if (has_normals) normals = mesh.vertex_property<Normal>("v:normal"); if (has_texcoords) texcoords = mesh.vertex_property<Texture_coordinate>("v:texcoord"); typename CGAL::Polygon_mesh_processing::GetVertexPointMap<Surface_mesh, NamedParameters>::const_type vpm = choose_param(get_param(np, CGAL::boost::internal_np::vertex_point), get_const_property_map(CGAL::vertex_point, mesh)); // #Vertice, #Faces, #Edges read(in, nV); read(in, nF); read(in, nE); mesh.clear(); mesh.reserve(nV, std::max(3*nV, nE), nF); // read vertices: pos [normal] [color] [texcoord] for (i=0; i<nV && !feof(in); ++i) { // position read(in, p); Surface_mesh::Vertex v = mesh.add_vertex(); put(vpm, v, (Point)p); // normal if (has_normals) { read(in, n); normals[v] = n; } // tex coord if (has_texcoords) { read(in, t); texcoords[v][0] = t[0]; texcoords[v][1] = t[1]; } } // read faces: #N v[1] v[2] ... v[n-1] std::vector<Surface_mesh::Vertex> vertices; for (i=0; i<nF; ++i) { read(in, nV); vertices.resize(nV); for (j=0; j<nV; ++j) { read(in, idx); vertices[j] = Surface_mesh::Vertex(idx); } mesh.add_face(vertices); } return true; }