127#ifndef __H__STL_READER
128#define __H__STL_READER
136#ifdef STL_READER_NO_EXCEPTIONS
137 #define STL_READER_THROW(msg) return false;
138 #define STL_READER_COND_THROW(cond, msg) if(cond) return false;
141 #define STL_READER_THROW(msg) {std::stringstream ss; ss << msg; throw(std::runtime_error(ss.str()));}
144 #define STL_READER_COND_THROW(cond, msg) if(cond){std::stringstream ss; ss << msg; throw(std::runtime_error(ss.str()));}
148namespace stl_reader {
191template <
class TNumberContainer1,
class TNumberContainer2,
192 class TIndexContainer1,
class TIndexContainer2>
193bool ReadStlFile(
const char* filename,
194 TNumberContainer1& coordsOut,
195 TNumberContainer2& normalsOut,
196 TIndexContainer1& trisOut,
197 TIndexContainer2& solidRangesOut);
204template <
class TNumberContainer1,
class TNumberContainer2,
205 class TIndexContainer1,
class TIndexContainer2>
206bool ReadStlFile_ASCII(
const char* filename,
207 TNumberContainer1& coordsOut,
208 TNumberContainer2& normalsOut,
209 TIndexContainer1& trisOut,
210 TIndexContainer2& solidRangesOut);
217template <
class TNumberContainer1,
class TNumberContainer2,
218 class TIndexContainer1,
class TIndexContainer2>
219bool ReadStlFile_BINARY(
const char* filename,
220 TNumberContainer1& coordsOut,
221 TNumberContainer2& normalsOut,
222 TIndexContainer1& trisOut,
223 TIndexContainer2& solidRangesOut);
230inline bool StlFileHasASCIIFormat(
const char* filename);
234template <
class TNumber =
float,
class TIndex =
unsigned int>
240 solids.resize (2, 0);
250 StlMesh (
const std::string& filename)
262 #ifndef STL_READER_NO_EXCEPTIONS
266 res =
ReadStlFile (filename, coords, normals, tris, solids);
268 #ifndef STL_READER_NO_EXCEPTIONS
269 }
catch (std::exception& e) {
284 bool read_file (
const std::string& filename)
293 return coords.size() / 3;
299 return &coords[vi * 3];
305 return tris.size() / 3;
311 return &tris [ti * 3];
317 return tris [ti * 3 + ci];
335 return &normals [ti * 3];
348 return solids.size () - 1;
360 return solids [si + 1];
404 std::vector<TNumber> coords;
405 std::vector<TNumber> normals;
406 std::vector<TIndex> tris;
407 std::vector<TIndex> solids;
416namespace stl_reader_impl {
420 template <
typename number_t,
typename index_t>
421 struct CoordWithIndex {
425 bool operator == (
const CoordWithIndex& c)
const
427 return (c[0] == data[0]) && (c[1] == data[1]) && (c[2] == data[2]);
430 bool operator != (
const CoordWithIndex& c)
const
432 return (c[0] != data[0]) || (c[1] != data[1]) || (c[2] != data[2]);
435 bool operator < (
const CoordWithIndex& c)
const
437 return (data[0] < c[0])
438 || (data[0] == c[0] && data[1] < c[1])
439 || (data[0] == c[0] && data[1] == c[1] && data[2] < c[2]);
442 inline number_t& operator [] (
const size_t i) {
return data[i];}
443 inline number_t operator [] (
const size_t i)
const {
return data[i];}
448 template <
class TNumberContainer,
class TIndexContainer>
449 void RemoveDoubles (TNumberContainer& uniqueCoordsOut,
450 TIndexContainer& trisInOut,
451 std::vector <CoordWithIndex<
452 typename TNumberContainer::value_type,
453 typename TIndexContainer::value_type> >
454 &coordsWithIndexInOut)
458 typedef typename TNumberContainer::value_type number_t;
459 typedef typename TIndexContainer::value_type index_t;
461 sort (coordsWithIndexInOut.begin(), coordsWithIndexInOut.end());
464 index_t numUnique = 1;
465 for(
size_t i = 1; i < coordsWithIndexInOut.size(); ++i){
466 if(coordsWithIndexInOut[i] != coordsWithIndexInOut[i - 1])
470 uniqueCoordsOut.resize (numUnique * 3);
471 vector<index_t> newIndex (coordsWithIndexInOut.size());
477 for(index_t i = 0; i < 3; ++i)
478 uniqueCoordsOut[i] = coordsWithIndexInOut[0][i];
480 for(
size_t i = 1; i < coordsWithIndexInOut.size(); ++i){
481 const CoordWithIndex <number_t, index_t> c = coordsWithIndexInOut[i];
482 if(c != coordsWithIndexInOut[i - 1]){
484 for(index_t j = 0; j < 3; ++j)
485 uniqueCoordsOut[curInd * 3 + j] = coordsWithIndexInOut[i][j];
488 newIndex[c.index] =
static_cast<index_t
> (curInd);
493 index_t numUniqueTriInds = 0;
494 for(index_t i = 0; i < trisInOut.size(); i+=3){
496 for(
int j = 0; j < 3; ++j)
497 ni[j] = newIndex[trisInOut[i+j]];
499 if((ni[0] != ni[1]) && (ni[0] != ni[2]) && (ni[1] != ni[2])){
500 for(
int j = 0; j < 3; ++j)
501 trisInOut[numUniqueTriInds + j] = ni[j];
502 numUniqueTriInds += 3;
506 if(numUniqueTriInds < trisInOut.size())
507 trisInOut.resize (numUniqueTriInds);
512template <
class TNumberContainer1,
class TNumberContainer2,
513 class TIndexContainer1,
class TIndexContainer2>
515 TNumberContainer1& coordsOut,
516 TNumberContainer2& normalsOut,
517 TIndexContainer1& trisOut,
518 TIndexContainer2& solidRangesOut)
521 return ReadStlFile_ASCII(filename, coordsOut, normalsOut, trisOut, solidRangesOut);
527template <
class TNumberContainer1,
class TNumberContainer2,
528 class TIndexContainer1,
class TIndexContainer2>
530 TNumberContainer1& coordsOut,
531 TNumberContainer2& normalsOut,
532 TIndexContainer1& trisOut,
533 TIndexContainer2& solidRangesOut)
536 using namespace stl_reader_impl;
538 typedef typename TNumberContainer1::value_type number_t;
539 typedef typename TIndexContainer1::value_type index_t;
544 solidRangesOut.clear();
546 ifstream in(filename);
549 vector<CoordWithIndex <number_t, index_t> > coordsWithIndex;
552 vector<string> tokens;
554 int maxNumTokens = 0;
555 size_t numFaceVrts = 0;
557 while(!(in.eof() || in.fail()))
564 istringstream line(buffer);
566 while(!(line.eof() || line.fail())){
567 if(tokenCount >= maxNumTokens){
568 maxNumTokens = tokenCount + 1;
569 tokens.resize(maxNumTokens);
571 line >> tokens[tokenCount];
577 string& tok = tokens[0];
578 if(tok.compare(
"vertex") == 0){
581 ": vertex not specified correctly in line " << lineCount);
585 CoordWithIndex <number_t, index_t> c;
586 for(
size_t i = 0; i < 3; ++i)
587 c[i] =
static_cast<number_t
> (atof(tokens[i+1].c_str()));
588 c.index =
static_cast<index_t
>(coordsWithIndex.size());
589 coordsWithIndex.push_back(c);
592 else if(tok.compare(
"facet") == 0)
595 "ERROR while reading from " << filename <<
596 ": triangle not specified correctly in line " << lineCount);
599 "ERROR while reading from " << filename <<
600 ": Missing normal specifier in line " << lineCount);
603 for(
size_t i = 0; i < 3; ++i)
604 normalsOut.push_back (
static_cast<number_t
> (atof(tokens[i+2].c_str())));
608 else if(tok.compare(
"outer") == 0){
610 "ERROR while reading from " << filename <<
611 ": expecting outer loop in line " << lineCount);
613 else if(tok.compare(
"endfacet") == 0){
615 "ERROR while reading from " << filename <<
616 ": bad number of vertices specified for face in line " << lineCount);
618 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 3));
619 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 2));
620 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 1));
622 else if(tok.compare(
"solid") == 0){
623 solidRangesOut.push_back(
static_cast<index_t
> (trisOut.size() / 3));
629 solidRangesOut.push_back(
static_cast<index_t
> (trisOut.size() / 3));
631 RemoveDoubles (coordsOut, trisOut, coordsWithIndex);
637template <
class TNumberContainer1,
class TNumberContainer2,
638 class TIndexContainer1,
class TIndexContainer2>
640 TNumberContainer1& coordsOut,
641 TNumberContainer2& normalsOut,
642 TIndexContainer1& trisOut,
643 TIndexContainer2& solidRangesOut)
646 using namespace stl_reader_impl;
648 typedef typename TNumberContainer1::value_type number_t;
649 typedef typename TIndexContainer1::value_type index_t;
654 solidRangesOut.clear();
656 ifstream in(filename, ios::binary);
660 in.read(stl_header, 80);
663 unsigned int numTris = 0;
664 in.read((
char*)&numTris, 4);
667 vector<CoordWithIndex <number_t, index_t> > coordsWithIndex;
669 for(
unsigned int tri = 0; tri < numTris; ++tri){
671 in.read((
char*)d, 12 * 4);
674 for(
int i = 0; i < 3; ++i)
675 normalsOut.push_back (d[i]);
677 for(
size_t ivrt = 1; ivrt < 4; ++ivrt){
678 CoordWithIndex <number_t, index_t> c;
679 for(
size_t i = 0; i < 3; ++i)
680 c[i] = d[ivrt * 3 + i];
681 c.index =
static_cast<index_t
>(coordsWithIndex.size());
682 coordsWithIndex.push_back(c);
685 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 3));
686 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 2));
687 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 1));
691 STL_READER_COND_THROW(!in,
"Error while parsing additional triangle data in binary stl file " << filename);
694 solidRangesOut.push_back(0);
695 solidRangesOut.push_back(
static_cast<index_t
> (trisOut.size() / 3));
697 RemoveDoubles (coordsOut, trisOut, coordsWithIndex);
706 ifstream in(filename);
710 in.read (chars, 256);
711 string buffer (chars, in.gcount());
712 transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
713 return buffer.find (
"solid") != string::npos &&
714 buffer.find (
"\n") != string::npos &&
715 buffer.find (
"facet") != string::npos &&
716 buffer.find (
"normal") != string::npos;
convenience mesh class which makes accessing the stl data more easy
const TNumber * vrt_coords(const size_t vi) const
returns an array of 3 floating point values, one for each coordinate of the vertex
size_t num_solids() const
returns the number of solids of the mesh
const TNumber * tri_corner_coords(const size_t ti, const size_t ci) const
returns an array of 3 floating point values, one for each coordinate of the specified corner of the s...
const TNumber * raw_coords() const
returns a pointer to the coordinate array, containing num_vrts()*3 entries.
size_t num_tris() const
returns the number of triangles in the mesh
const TNumber * raw_normals() const
returns a pointer to the normal array, containing num_tris()*3 entries.
StlMesh(const char *filename)
initializes the mesh from the stl-file specified through filename
TIndex solid_tris_begin(const size_t si) const
returns the index of the first triangle in the given solid
const TIndex tri_corner_ind(const size_t ti, const size_t ci) const
returns the index of the corner with index 0<=ci<3 of triangle ti
const TIndex * raw_tris() const
returns a pointer to the triangle array, containing num_tris()*3 entries.
bool read_file(const char *filename)
fills the mesh with the contents of the specified stl-file
const TIndex * raw_solids() const
returns a pointer to the solids array, containing num_solids()+1 entries.
StlMesh()
initializes an empty mesh
TIndex solid_tris_end(const size_t si) const
returns the index of the triangle behind the last triangle in the given solid
size_t num_vrts() const
returns the number of vertices in the mesh
const TIndex * tri_corner_inds(const size_t ti) const
returns an array of 3 indices, one for each corner vertex of the triangle
const TNumber * tri_normal(const size_t ti) const
returns an array of 3 floating point values defining the normal of a tri
bool ReadStlFile(const char *filename, TNumberContainer1 &coordsOut, TNumberContainer2 &normalsOut, TIndexContainer1 &trisOut, TIndexContainer2 &solidRangesOut)
Reads an ASCII or binary stl file into several arrays.
bool ReadStlFile_ASCII(const char *filename, TNumberContainer1 &coordsOut, TNumberContainer2 &normalsOut, TIndexContainer1 &trisOut, TIndexContainer2 &solidRangesOut)
Reads an ASCII stl file into several arrays.
bool StlFileHasASCIIFormat(const char *filename)
Determines whether a stl file has ASCII format.
#define STL_READER_COND_THROW(cond, msg)
Throws an std::runtime_error with the given message, if the given condition evaluates to true.
#define STL_READER_THROW(msg)
Throws an std::runtime_error with the given message.
bool ReadStlFile_BINARY(const char *filename, TNumberContainer1 &coordsOut, TNumberContainer2 &normalsOut, TIndexContainer1 &trisOut, TIndexContainer2 &solidRangesOut)
Reads a binary stl file into several arrays.