|
|
@@ -1,290 +1,322 @@
|
|
|
// This file is part of libigl, a simple c++ geometry processing library.
|
|
|
-//
|
|
|
+//
|
|
|
// Copyright (C) 2014 Alec Jacobson <[email protected]>
|
|
|
-//
|
|
|
-// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
|
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
|
+// Copyright (C) 2018 Qingnan Zhou <[email protected]>
|
|
|
+// Copyright (C) 2020 Jérémie Dumas <[email protected]>
|
|
|
+//
|
|
|
+// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
|
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
#include "readSTL.h"
|
|
|
#include "list_to_matrix.h"
|
|
|
+#include "string_utils.h"
|
|
|
+#include "file_utils.h"
|
|
|
|
|
|
#include <iostream>
|
|
|
+
|
|
|
+namespace igl {
|
|
|
+
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedN>
|
|
|
-IGL_INLINE bool igl::readSTL(
|
|
|
- const std::string & filename,
|
|
|
- Eigen::PlainObjectBase<DerivedV> & V,
|
|
|
- Eigen::PlainObjectBase<DerivedF> & F,
|
|
|
- Eigen::PlainObjectBase<DerivedN> & N)
|
|
|
-{
|
|
|
- using namespace std;
|
|
|
- vector<vector<typename DerivedV::Scalar> > vV;
|
|
|
- vector<vector<typename DerivedN::Scalar> > vN;
|
|
|
- vector<vector<typename DerivedF::Scalar> > vF;
|
|
|
- if(!readSTL(filename,vV,vF,vN))
|
|
|
- {
|
|
|
+IGL_INLINE bool readSTL(std::istream &input,
|
|
|
+ Eigen::PlainObjectBase<DerivedV> &V,
|
|
|
+ Eigen::PlainObjectBase<DerivedF> &F,
|
|
|
+ Eigen::PlainObjectBase<DerivedN> &N) {
|
|
|
+ std::vector<std::array<typename DerivedV::Scalar, 3>> vV;
|
|
|
+ std::vector<std::array<typename DerivedN::Scalar, 3>> vN;
|
|
|
+ std::vector<std::array<typename DerivedF::Scalar, 3>> vF;
|
|
|
+ if (!readSTL(input, vV, vF, vN)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if(!list_to_matrix(vV,V))
|
|
|
- {
|
|
|
+ if (!list_to_matrix(vV, V)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if(!list_to_matrix(vF,F))
|
|
|
- {
|
|
|
+ if (!list_to_matrix(vF, F)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if(!list_to_matrix(vN,N))
|
|
|
- {
|
|
|
+ if (!list_to_matrix(vN, N)) {
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-template <typename TypeV, typename TypeF, typename TypeN>
|
|
|
-IGL_INLINE bool igl::readSTL(
|
|
|
- const std::string & filename,
|
|
|
- std::vector<std::vector<TypeV> > & V,
|
|
|
- std::vector<std::vector<TypeF> > & F,
|
|
|
- std::vector<std::vector<TypeN> > & N)
|
|
|
-{
|
|
|
- using namespace std;
|
|
|
- // Should test for ascii
|
|
|
-
|
|
|
- // Open file, and check for error
|
|
|
- FILE * stl_file = fopen(filename.c_str(),"rb");
|
|
|
- if(NULL==stl_file)
|
|
|
- {
|
|
|
- fprintf(stderr,"IOError: %s could not be opened...\n",
|
|
|
- filename.c_str());
|
|
|
- return false;
|
|
|
- }
|
|
|
- return readSTL(stl_file,V,F,N);
|
|
|
-}
|
|
|
+IGL_INLINE bool is_stl_binary(std::istream &input) {
|
|
|
+ std::streampos start_pos = input.tellg();
|
|
|
|
|
|
-template <typename TypeV, typename TypeF, typename TypeN>
|
|
|
-IGL_INLINE bool igl::readSTL(
|
|
|
- FILE * stl_file,
|
|
|
- std::vector<std::vector<TypeV> > & V,
|
|
|
- std::vector<std::vector<TypeF> > & F,
|
|
|
- std::vector<std::vector<TypeN> > & N)
|
|
|
-{
|
|
|
- using namespace std;
|
|
|
- //stl_file = freopen(NULL,"rb",stl_file);
|
|
|
- if(NULL==stl_file)
|
|
|
- {
|
|
|
- fprintf(stderr,"IOError: stl file could not be reopened as binary (1) ...\n");
|
|
|
+ constexpr size_t HEADER_SIZE = 80;
|
|
|
+ char header[HEADER_SIZE];
|
|
|
+ input.read(header, HEADER_SIZE);
|
|
|
+ if (!starts_with(header, "solid")) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!input.good()) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- V.clear();
|
|
|
- F.clear();
|
|
|
- N.clear();
|
|
|
+ // Check if filesize matches the number of faces claimed.
|
|
|
+ char buf[4];
|
|
|
+ input.read(buf, 4);
|
|
|
+ size_t num_faces = *reinterpret_cast<uint32_t *>(buf);
|
|
|
+ input.seekg(0, input.end);
|
|
|
+ size_t file_size = input.tellg();
|
|
|
|
|
|
+ input.seekg(start_pos);
|
|
|
|
|
|
- // Specifically 80 character header
|
|
|
- char header[80];
|
|
|
- char solid[80] = {0};
|
|
|
- bool is_ascii = true;
|
|
|
- if(fread(header,1,80,stl_file) != 80)
|
|
|
- {
|
|
|
- cerr<<"IOError: too short (1)."<<endl;
|
|
|
- goto close_false;
|
|
|
+ if (file_size == 80 + 4 + (4 * 12 + 2) * num_faces) {
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
}
|
|
|
- sscanf(header,"%79s",solid);
|
|
|
- if(string("solid") != solid)
|
|
|
- {
|
|
|
- // definitely **not** ascii
|
|
|
- is_ascii = false;
|
|
|
- }else
|
|
|
- {
|
|
|
- // might still be binary
|
|
|
- char buf[4];
|
|
|
- if(fread(buf,1,4,stl_file) != 4)
|
|
|
- {
|
|
|
- cerr<<"IOError: too short (3)."<<endl;
|
|
|
- goto close_false;
|
|
|
- }
|
|
|
- size_t num_faces = *reinterpret_cast<unsigned int*>(buf);
|
|
|
- fseek(stl_file,0,SEEK_END);
|
|
|
- int file_size = ftell(stl_file);
|
|
|
- if(file_size == 80 + 4 + (4*12 + 2) * num_faces)
|
|
|
- {
|
|
|
- is_ascii = false;
|
|
|
- }else
|
|
|
- {
|
|
|
- is_ascii = true;
|
|
|
- }
|
|
|
+}
|
|
|
+
|
|
|
+template <typename TypeV, typename TypeF, typename TypeN>
|
|
|
+IGL_INLINE bool read_stl_ascii(std::istream &input,
|
|
|
+ std::vector<std::array<TypeV, 3>> &V,
|
|
|
+ std::vector<std::array<TypeF, 3>> &F,
|
|
|
+ std::vector<std::array<TypeN, 3>> &N) {
|
|
|
+ constexpr size_t LINE_SIZE = 256;
|
|
|
+ char line[LINE_SIZE];
|
|
|
+ bool success = true;
|
|
|
+
|
|
|
+ if (!input) {
|
|
|
+ throw std::runtime_error("Failed to open file");
|
|
|
}
|
|
|
|
|
|
- if(is_ascii)
|
|
|
- {
|
|
|
- // Rewind to end of header
|
|
|
- //stl_file = fopen(filename.c_str(),"r");
|
|
|
- //stl_file = freopen(NULL,"r",stl_file);
|
|
|
- fseek(stl_file, 0, SEEK_SET);
|
|
|
- if(NULL==stl_file)
|
|
|
- {
|
|
|
- fprintf(stderr,"IOError: stl file could not be reopened as ascii ...\n");
|
|
|
+ // skip header line.
|
|
|
+ input.getline(line, LINE_SIZE);
|
|
|
+
|
|
|
+ auto parse_ascii_normal = [&N](const char *line) {
|
|
|
+ double x, y, z;
|
|
|
+ size_t n = sscanf(line, " facet normal %lf %lf %lf", &x, &y, &z);
|
|
|
+ assert(n == 3);
|
|
|
+ if (n != 3) {
|
|
|
return false;
|
|
|
}
|
|
|
- // Read 80 header
|
|
|
- // Eat file name
|
|
|
-#ifndef IGL_LINE_MAX
|
|
|
-# define IGL_LINE_MAX 2048
|
|
|
-#endif
|
|
|
- char name[IGL_LINE_MAX];
|
|
|
- if(NULL==fgets(name,IGL_LINE_MAX,stl_file))
|
|
|
- {
|
|
|
- cerr<<"IOError: ascii too short (2)."<<endl;
|
|
|
- goto close_false;
|
|
|
+
|
|
|
+ N.push_back({{static_cast<TypeN>(x), static_cast<TypeN>(y),
|
|
|
+ static_cast<TypeN>(z)}});
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ auto parse_ascii_vertex = [&V](const char *line) {
|
|
|
+ double x, y, z;
|
|
|
+ size_t n = sscanf(line, " vertex %lf %lf %lf", &x, &y, &z);
|
|
|
+ assert(n == 3);
|
|
|
+ if (n != 3) {
|
|
|
+ return false;
|
|
|
}
|
|
|
- // ascii
|
|
|
- while(true)
|
|
|
- {
|
|
|
- int ret;
|
|
|
- char facet[IGL_LINE_MAX],normal[IGL_LINE_MAX];
|
|
|
- vector<TypeN > n(3);
|
|
|
- double nd[3];
|
|
|
- ret = fscanf(stl_file,"%s %s %lg %lg %lg",facet,normal,nd,nd+1,nd+2);
|
|
|
- if(string("endsolid") == facet)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- if(ret != 5 ||
|
|
|
- !(string("facet") == facet ||
|
|
|
- string("faced") == facet) ||
|
|
|
- string("normal") != normal)
|
|
|
- {
|
|
|
- cout<<"facet: "<<facet<<endl;
|
|
|
- cout<<"normal: "<<normal<<endl;
|
|
|
- cerr<<"IOError: bad format (1)."<<endl;
|
|
|
- goto close_false;
|
|
|
- }
|
|
|
- // copy casts to Type
|
|
|
- n[0] = nd[0]; n[1] = nd[1]; n[2] = nd[2];
|
|
|
- N.push_back(n);
|
|
|
- char outer[IGL_LINE_MAX], loop[IGL_LINE_MAX];
|
|
|
- ret = fscanf(stl_file,"%s %s",outer,loop);
|
|
|
- if(ret != 2 || string("outer") != outer || string("loop") != loop)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (2)."<<endl;
|
|
|
- goto close_false;
|
|
|
+
|
|
|
+ V.push_back({{static_cast<TypeV>(x), static_cast<TypeV>(y),
|
|
|
+ static_cast<TypeV>(z)}});
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ auto parse_ascii_facet = [&parse_ascii_vertex, &parse_ascii_normal](std::istream &fin) {
|
|
|
+ constexpr size_t LINE_SIZE = 256;
|
|
|
+ constexpr size_t WORD_SIZE = 128;
|
|
|
+ char line[LINE_SIZE];
|
|
|
+ char first_word[WORD_SIZE];
|
|
|
+ const char *face_begin = "facet";
|
|
|
+ const char *face_end = "endfacet";
|
|
|
+ const char *loop_begin = "outer";
|
|
|
+ const char *loop_end = "endloop";
|
|
|
+ const char *vertex_flag = "vertex";
|
|
|
+
|
|
|
+ bool reading_facet = false;
|
|
|
+ bool reading_loop = false;
|
|
|
+ bool success = true;
|
|
|
+ size_t num_vts = 0;
|
|
|
+ while (!fin.eof()) {
|
|
|
+ fin.getline(line, LINE_SIZE);
|
|
|
+ size_t n = sscanf(line, " %s", first_word);
|
|
|
+ if (n == 0)
|
|
|
+ continue;
|
|
|
+ if (starts_with(first_word, face_begin)) {
|
|
|
+ success = parse_ascii_normal(line);
|
|
|
+ assert(success);
|
|
|
+ reading_facet = true;
|
|
|
+ } else if (starts_with(first_word, face_end)) {
|
|
|
+ assert(reading_facet);
|
|
|
+ reading_facet = false;
|
|
|
+ } else if (starts_with(first_word, loop_begin)) {
|
|
|
+ reading_loop = true;
|
|
|
+ } else if (starts_with(first_word, loop_end)) {
|
|
|
+ assert(reading_loop);
|
|
|
+ reading_loop = false;
|
|
|
+ } else if (starts_with(first_word, vertex_flag)) {
|
|
|
+ assert(reading_facet);
|
|
|
+ assert(reading_loop);
|
|
|
+ success = parse_ascii_vertex(line);
|
|
|
+ assert(success);
|
|
|
+ num_vts += 1;
|
|
|
}
|
|
|
- vector<TypeF> f;
|
|
|
- while(true)
|
|
|
- {
|
|
|
- char word[IGL_LINE_MAX];
|
|
|
- int ret = fscanf(stl_file,"%s",word);
|
|
|
- if(ret == 1 && string("endloop") == word)
|
|
|
- {
|
|
|
- break;
|
|
|
- }else if(ret == 1 && string("vertex") == word)
|
|
|
- {
|
|
|
- vector<TypeV> v(3);
|
|
|
- double vd[3];
|
|
|
- int ret = fscanf(stl_file,"%lg %lg %lg",vd,vd+1,vd+2);
|
|
|
- if(ret != 3)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (3)."<<endl;
|
|
|
- goto close_false;
|
|
|
- }
|
|
|
- f.push_back(V.size());
|
|
|
- // copy casts to Type
|
|
|
- v[0] = vd[0]; v[1] = vd[1]; v[2] = vd[2];
|
|
|
- V.push_back(v);
|
|
|
- }else
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (4)."<<endl;
|
|
|
- goto close_false;
|
|
|
- }
|
|
|
+ if (!success) {
|
|
|
+ return false;
|
|
|
}
|
|
|
- F.push_back(f);
|
|
|
- char endfacet[IGL_LINE_MAX];
|
|
|
- ret = fscanf(stl_file,"%s",endfacet);
|
|
|
- if(ret != 1 || string("endfacet") != endfacet)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (5)."<<endl;
|
|
|
- goto close_false;
|
|
|
+ if (!reading_facet) {
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
- // read endfacet
|
|
|
- goto close_true;
|
|
|
- }else
|
|
|
- {
|
|
|
- // Binary
|
|
|
- //stl_file = freopen(NULL,"rb",stl_file);
|
|
|
- fseek(stl_file, 0, SEEK_SET);
|
|
|
- // Read 80 header
|
|
|
- char header[80];
|
|
|
- if(fread(header,sizeof(char),80,stl_file)!=80)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (6)."<<endl;
|
|
|
- goto close_false;
|
|
|
+ if (num_vts == 0) {
|
|
|
+ return true;
|
|
|
}
|
|
|
- // Read number of triangles
|
|
|
- unsigned int num_tri;
|
|
|
- if(fread(&num_tri,sizeof(unsigned int),1,stl_file)!=1)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (7)."<<endl;
|
|
|
- goto close_false;
|
|
|
+ assert(num_vts == 3);
|
|
|
+ if (num_vts != 3) {
|
|
|
+ std::cerr << "Warning: mesh contain face made of " << num_vts
|
|
|
+ << " vertices" << std::endl;
|
|
|
+ return false;
|
|
|
}
|
|
|
- V.resize(num_tri*3,vector<TypeV >(3,0));
|
|
|
- N.resize(num_tri,vector<TypeN >(3,0));
|
|
|
- F.resize(num_tri,vector<TypeF >(3,0));
|
|
|
- for(int t = 0;t<(int)num_tri;t++)
|
|
|
- {
|
|
|
- // Read normal
|
|
|
- float n[3];
|
|
|
- if(fread(n,sizeof(float),3,stl_file)!=3)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (8)."<<endl;
|
|
|
- goto close_false;
|
|
|
- }
|
|
|
- // Read each vertex
|
|
|
- for(int c = 0;c<3;c++)
|
|
|
- {
|
|
|
- F[t][c] = 3*t+c;
|
|
|
- N[t][c] = n[c];
|
|
|
- float v[3];
|
|
|
- if(fread(v,sizeof(float),3,stl_file)!=3)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (9)."<<endl;
|
|
|
- goto close_false;
|
|
|
- }
|
|
|
- V[3*t+c][0] = v[0];
|
|
|
- V[3*t+c][1] = v[1];
|
|
|
- V[3*t+c][2] = v[2];
|
|
|
- }
|
|
|
- // Read attribute size
|
|
|
- unsigned short att_count;
|
|
|
- if(fread(&att_count,sizeof(unsigned short),1,stl_file)!=1)
|
|
|
- {
|
|
|
- cerr<<"IOError: bad format (10)."<<endl;
|
|
|
- goto close_false;
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ while (!input.eof()) {
|
|
|
+ success = parse_ascii_facet(input);
|
|
|
+ if (!success) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ F.resize(V.size() / 3);
|
|
|
+ for (size_t f = 0; f < F.size(); ++f) {
|
|
|
+ auto v = static_cast<TypeF>(f * 3);
|
|
|
+ F[f] = {{v, v + 1, v + 2}};
|
|
|
+ }
|
|
|
+ return success;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename TypeV, typename TypeF, typename TypeN>
|
|
|
+IGL_INLINE bool read_stl_binary(std::istream &input,
|
|
|
+ std::vector<std::array<TypeV, 3>> &V,
|
|
|
+ std::vector<std::array<TypeF, 3>> &F,
|
|
|
+ std::vector<std::array<TypeN, 3>> &N) {
|
|
|
+ if (!input) {
|
|
|
+ throw std::runtime_error("Failed to open file");
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr size_t FLOAT_SIZE = sizeof(float);
|
|
|
+ static_assert(FLOAT_SIZE == 4, "float type is not 4 bytes");
|
|
|
+ constexpr size_t LINE_SIZE = 256;
|
|
|
+ char buf[LINE_SIZE];
|
|
|
+
|
|
|
+ // 80 bytes header, no data significance.
|
|
|
+ input.read(buf, 80);
|
|
|
+ if (!input.good()) {
|
|
|
+ throw std::runtime_error("Unable to parse STL header.");
|
|
|
+ }
|
|
|
+
|
|
|
+ input.read(buf, 4);
|
|
|
+ const size_t num_faces = *reinterpret_cast<uint32_t *>(buf);
|
|
|
+ if (!input.good()) {
|
|
|
+ throw std::runtime_error("Unable to parse STL number of faces.");
|
|
|
+ }
|
|
|
+
|
|
|
+ for (size_t i = 0; i < num_faces; i++) {
|
|
|
+ // Parse normal
|
|
|
+ input.read(buf, FLOAT_SIZE * 3);
|
|
|
+ auto nx = static_cast<TypeN>(*reinterpret_cast<float *>(buf));
|
|
|
+ auto ny = static_cast<TypeN>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
|
|
|
+ auto nz =
|
|
|
+ static_cast<TypeN>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
|
|
|
+ assert(input.good());
|
|
|
+
|
|
|
+ // vertex 1
|
|
|
+ input.read(buf, FLOAT_SIZE * 3);
|
|
|
+ auto v1x = static_cast<TypeV>(*reinterpret_cast<float *>(buf));
|
|
|
+ auto v1y = static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
|
|
|
+ auto v1z =
|
|
|
+ static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
|
|
|
+ assert(input.good());
|
|
|
+
|
|
|
+ // vertex 2
|
|
|
+ input.read(buf, FLOAT_SIZE * 3);
|
|
|
+ auto v2x = static_cast<TypeV>(*reinterpret_cast<float *>(buf));
|
|
|
+ auto v2y = static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
|
|
|
+ auto v2z =
|
|
|
+ static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
|
|
|
+ assert(input.good());
|
|
|
+
|
|
|
+ // vertex 3
|
|
|
+ input.read(buf, FLOAT_SIZE * 3);
|
|
|
+ auto v3x = static_cast<TypeV>(*reinterpret_cast<float *>(buf));
|
|
|
+ auto v3y = static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE));
|
|
|
+ auto v3z =
|
|
|
+ static_cast<TypeV>(*reinterpret_cast<float *>(buf + FLOAT_SIZE * 2));
|
|
|
+ assert(input.good());
|
|
|
+
|
|
|
+ // attribute (2 bytes), not sure what purpose they serve.
|
|
|
+ input.read(buf, 2);
|
|
|
+
|
|
|
+ N.push_back({{nx, ny, nz}});
|
|
|
+ V.push_back({{v1x, v1y, v1z}});
|
|
|
+ V.push_back({{v2x, v2y, v2z}});
|
|
|
+ V.push_back({{v3x, v3y, v3z}});
|
|
|
+
|
|
|
+ assert(input.good());
|
|
|
+ if (!input.good()) {
|
|
|
+ std::stringstream err_msg;
|
|
|
+ err_msg << "Failed to parse face " << i << " from STL file";
|
|
|
+ throw std::runtime_error(err_msg.str());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ std::for_each(V.begin(), V.end(), [](const std::array<TypeV, 3> &v) {
|
|
|
+ for (auto x : v) {
|
|
|
+ if (!std::isfinite(x)) {
|
|
|
+ throw std::runtime_error("NaN or Inf detected in input file.");
|
|
|
}
|
|
|
}
|
|
|
- goto close_true;
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!V.empty()) {
|
|
|
+ F.resize(V.size() / 3);
|
|
|
+ for (size_t f = 0; f < F.size(); ++f) {
|
|
|
+ auto v = static_cast<TypeF>(f * 3);
|
|
|
+ F[f] = {{v, v + 1, v + 2}};
|
|
|
+ }
|
|
|
}
|
|
|
-close_false:
|
|
|
- fclose(stl_file);
|
|
|
- return false;
|
|
|
-close_true:
|
|
|
- fclose(stl_file);
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+template <typename TypeV, typename TypeF, typename TypeN>
|
|
|
+IGL_INLINE bool readSTL(std::istream &input,
|
|
|
+ std::vector<std::array<TypeV, 3>> &V,
|
|
|
+ std::vector<std::array<TypeF, 3>> &F,
|
|
|
+ std::vector<std::array<TypeN, 3>> &N) {
|
|
|
+ bool success = false;
|
|
|
+ if (is_stl_binary(input)) {
|
|
|
+ success = read_stl_binary(input, V, F, N);
|
|
|
+ } else {
|
|
|
+ success = read_stl_ascii(input, V, F, N);
|
|
|
+ }
|
|
|
+ return success;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename DerivedV, typename DerivedF, typename DerivedN>
|
|
|
+IGL_INLINE bool readSTL(
|
|
|
+ FILE * fp,
|
|
|
+ Eigen::PlainObjectBase<DerivedV> & V,
|
|
|
+ Eigen::PlainObjectBase<DerivedF> & F,
|
|
|
+ Eigen::PlainObjectBase<DerivedN> & N)
|
|
|
+{
|
|
|
+ std::vector<uint8_t> fileBufferBytes;
|
|
|
+ read_file_binary(fp,fileBufferBytes);
|
|
|
+ file_memory_stream stream((char*)fileBufferBytes.data(), fileBufferBytes.size());
|
|
|
+ return readSTL(stream, V, F, N);
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace igl
|
|
|
+
|
|
|
#ifdef IGL_STATIC_LIBRARY
|
|
|
// Explicit template instantiation
|
|
|
-// generated by autoexplicit.sh
|
|
|
-template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
-// generated by autoexplicit.sh
|
|
|
-template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
-// generated by autoexplicit.sh
|
|
|
-template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
-// generated by autoexplicit.sh
|
|
|
-template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
-template bool igl::readSTL<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
|
|
|
-template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
+template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
|
|
#endif
|