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 TNumberContainer1,
class TNumberContainer2,
449 class TIndexContainer1,
class TIndexContainer2>
450 void RemoveDoubles (TNumberContainer1& uniqueCoordsOut,
451 TIndexContainer1& trisInOut,
452 TNumberContainer2& normalsInOut,
453 TIndexContainer2& solidsInOut,
454 std::vector <CoordWithIndex<
455 typename TNumberContainer1::value_type,
456 typename TIndexContainer1::value_type> >
457 &coordsWithIndexInOut)
461 typedef typename TNumberContainer1::value_type number_t;
462 typedef typename TIndexContainer1::value_type index_t;
464 sort (coordsWithIndexInOut.begin(), coordsWithIndexInOut.end());
467 index_t numUnique = 1;
468 for(
size_t i = 1; i < coordsWithIndexInOut.size(); ++i){
469 if(coordsWithIndexInOut[i] != coordsWithIndexInOut[i - 1])
473 uniqueCoordsOut.resize (numUnique * 3);
474 vector<index_t> newIndex (coordsWithIndexInOut.size());
476 TIndexContainer2 newSolids;
481 newIndex[coordsWithIndexInOut[0].index] = 0;
482 for(index_t i = 0; i < 3; ++i)
483 uniqueCoordsOut[i] = coordsWithIndexInOut[0][i];
485 for(
size_t i = 1; i < coordsWithIndexInOut.size(); ++i){
486 const CoordWithIndex <number_t, index_t> c = coordsWithIndexInOut[i];
487 if(c != coordsWithIndexInOut[i - 1]){
489 for(index_t j = 0; j < 3; ++j)
490 uniqueCoordsOut[curInd * 3 + j] = coordsWithIndexInOut[i][j];
493 newIndex[c.index] =
static_cast<index_t
> (curInd);
498 index_t numUniqueTriInds = 0;
499 for(index_t i = 0; i < trisInOut.size(); i+=3){
501 const index_t triInd = i / 3;
502 const index_t newTriInd = numUniqueTriInds / 3;
503 if (newSolids.size () < solidsInOut.size () &&
504 solidsInOut [newSolids.size ()] <= triInd)
506 newSolids.push_back (newTriInd);
510 for(index_t j = 0; j < 3; ++j)
511 ni[j] = newIndex[trisInOut[i+j]];
513 if((ni[0] != ni[1]) && (ni[0] != ni[2]) && (ni[1] != ni[2])){
514 for(index_t j = 0; j < 3; ++j)
516 trisInOut[numUniqueTriInds + j] = ni[j];
517 normalsInOut[numUniqueTriInds + j] = normalsInOut [i + j];
519 numUniqueTriInds += 3;
523 if(numUniqueTriInds < trisInOut.size())
525 trisInOut.resize (numUniqueTriInds);
526 normalsInOut.resize (numUniqueTriInds);
529 if (!newSolids.empty ())
530 newSolids.push_back (numUniqueTriInds / 3);
533 swap (solidsInOut, newSolids);
538template <
class TNumberContainer1,
class TNumberContainer2,
539 class TIndexContainer1,
class TIndexContainer2>
541 TNumberContainer1& coordsOut,
542 TNumberContainer2& normalsOut,
543 TIndexContainer1& trisOut,
544 TIndexContainer2& solidRangesOut)
547 return ReadStlFile_ASCII(filename, coordsOut, normalsOut, trisOut, solidRangesOut);
553template <
class TNumberContainer1,
class TNumberContainer2,
554 class TIndexContainer1,
class TIndexContainer2>
556 TNumberContainer1& coordsOut,
557 TNumberContainer2& normalsOut,
558 TIndexContainer1& trisOut,
559 TIndexContainer2& solidRangesOut)
562 using namespace stl_reader_impl;
564 typedef typename TNumberContainer1::value_type number_t;
565 typedef typename TIndexContainer1::value_type index_t;
570 solidRangesOut.clear();
572 ifstream in(filename);
575 vector<CoordWithIndex <number_t, index_t> > coordsWithIndex;
578 vector<string> tokens;
580 int maxNumTokens = 0;
581 size_t numFaceVrts = 0;
583 while(!(in.eof() || in.fail()))
590 istringstream line(buffer);
592 while(!(line.eof() || line.fail())){
593 if(tokenCount >= maxNumTokens){
594 maxNumTokens = tokenCount + 1;
595 tokens.resize(maxNumTokens);
597 line >> tokens[tokenCount];
603 string& tok = tokens[0];
604 if(tok.compare(
"vertex") == 0){
607 ": vertex not specified correctly in line " << lineCount);
611 CoordWithIndex <number_t, index_t> c;
612 for(
size_t i = 0; i < 3; ++i)
613 c[i] =
static_cast<number_t
> (atof(tokens[i+1].c_str()));
614 c.index =
static_cast<index_t
>(coordsWithIndex.size());
615 coordsWithIndex.push_back(c);
618 else if(tok.compare(
"facet") == 0)
621 "ERROR while reading from " << filename <<
622 ": triangle not specified correctly in line " << lineCount);
625 "ERROR while reading from " << filename <<
626 ": Missing normal specifier in line " << lineCount);
629 for(
size_t i = 0; i < 3; ++i)
630 normalsOut.push_back (
static_cast<number_t
> (atof(tokens[i+2].c_str())));
634 else if(tok.compare(
"outer") == 0){
636 "ERROR while reading from " << filename <<
637 ": expecting outer loop in line " << lineCount);
639 else if(tok.compare(
"endfacet") == 0){
641 "ERROR while reading from " << filename <<
642 ": bad number of vertices specified for face in line " << lineCount);
644 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 3));
645 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 2));
646 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 1));
648 else if(tok.compare(
"solid") == 0){
649 solidRangesOut.push_back(
static_cast<index_t
> (trisOut.size() / 3));
655 solidRangesOut.push_back(
static_cast<index_t
> (trisOut.size() / 3));
657 RemoveDoubles (coordsOut, trisOut, normalsOut, solidRangesOut, coordsWithIndex);
663template <
class TNumberContainer1,
class TNumberContainer2,
664 class TIndexContainer1,
class TIndexContainer2>
666 TNumberContainer1& coordsOut,
667 TNumberContainer2& normalsOut,
668 TIndexContainer1& trisOut,
669 TIndexContainer2& solidRangesOut)
672 using namespace stl_reader_impl;
674 typedef typename TNumberContainer1::value_type number_t;
675 typedef typename TIndexContainer1::value_type index_t;
680 solidRangesOut.clear();
682 ifstream in(filename, ios::binary);
686 in.read(stl_header, 80);
689 unsigned int numTris = 0;
690 in.read((
char*)&numTris, 4);
693 vector<CoordWithIndex <number_t, index_t> > coordsWithIndex;
695 for(
unsigned int tri = 0; tri < numTris; ++tri){
697 in.read((
char*)d, 12 * 4);
700 for(
int i = 0; i < 3; ++i)
701 normalsOut.push_back (d[i]);
703 for(
size_t ivrt = 1; ivrt < 4; ++ivrt){
704 CoordWithIndex <number_t, index_t> c;
705 for(
size_t i = 0; i < 3; ++i)
706 c[i] = d[ivrt * 3 + i];
707 c.index =
static_cast<index_t
>(coordsWithIndex.size());
708 coordsWithIndex.push_back(c);
711 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 3));
712 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 2));
713 trisOut.push_back(
static_cast<index_t
> (coordsWithIndex.size() - 1));
717 STL_READER_COND_THROW(!in,
"Error while parsing additional triangle data in binary stl file " << filename);
720 solidRangesOut.push_back(0);
721 solidRangesOut.push_back(
static_cast<index_t
> (trisOut.size() / 3));
723 RemoveDoubles (coordsOut, trisOut, normalsOut, solidRangesOut, coordsWithIndex);
732 ifstream in(filename);
736 in.read (chars, 256);
737 string buffer (chars, in.gcount());
738 transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
739 return buffer.find (
"solid") != string::npos &&
740 buffer.find (
"\n") != string::npos &&
741 buffer.find (
"facet") != string::npos &&
742 buffer.find (
"normal") != string::npos;
convenience mesh class which makes accessing the stl data more easy
Definition: stl_reader.h:235
const TNumber * vrt_coords(const size_t vi) const
returns an array of 3 floating point values, one for each coordinate of the vertex
Definition: stl_reader.h:297
size_t num_solids() const
returns the number of solids of the mesh
Definition: stl_reader.h:344
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...
Definition: stl_reader.h:327
const TNumber * raw_coords() const
returns a pointer to the coordinate array, containing num_vrts()*3 entries.
Definition: stl_reader.h:366
size_t num_tris() const
returns the number of triangles in the mesh
Definition: stl_reader.h:303
const TNumber * raw_normals() const
returns a pointer to the normal array, containing num_tris()*3 entries.
Definition: stl_reader.h:376
StlMesh(const char *filename)
initializes the mesh from the stl-file specified through filename
Definition: stl_reader.h:245
TIndex solid_tris_begin(const size_t si) const
returns the index of the first triangle in the given solid
Definition: stl_reader.h:352
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
Definition: stl_reader.h:315
const TIndex * raw_tris() const
returns a pointer to the triangle array, containing num_tris()*3 entries.
Definition: stl_reader.h:386
bool read_file(const char *filename)
fills the mesh with the contents of the specified stl-file
Definition: stl_reader.h:258
const TIndex * raw_solids() const
returns a pointer to the solids array, containing num_solids()+1 entries.
Definition: stl_reader.h:396
StlMesh()
initializes an empty mesh
Definition: stl_reader.h:238
TIndex solid_tris_end(const size_t si) const
returns the index of the triangle behind the last triangle in the given solid
Definition: stl_reader.h:358
size_t num_vrts() const
returns the number of vertices in the mesh
Definition: stl_reader.h:291
const TIndex * tri_corner_inds(const size_t ti) const
returns an array of 3 indices, one for each corner vertex of the triangle
Definition: stl_reader.h:309
const TNumber * tri_normal(const size_t ti) const
returns an array of 3 floating point values defining the normal of a tri
Definition: stl_reader.h:333
bool ReadStlFile(const char *filename, TNumberContainer1 &coordsOut, TNumberContainer2 &normalsOut, TIndexContainer1 &trisOut, TIndexContainer2 &solidRangesOut)
Reads an ASCII or binary stl file into several arrays.
Definition: stl_reader.h:540
bool ReadStlFile_ASCII(const char *filename, TNumberContainer1 &coordsOut, TNumberContainer2 &normalsOut, TIndexContainer1 &trisOut, TIndexContainer2 &solidRangesOut)
Reads an ASCII stl file into several arrays.
Definition: stl_reader.h:555
bool StlFileHasASCIIFormat(const char *filename)
Determines whether a stl file has ASCII format.
Definition: stl_reader.h:729
#define STL_READER_COND_THROW(cond, msg)
Throws an std::runtime_error with the given message, if the given condition evaluates to true.
Definition: stl_reader.h:144
#define STL_READER_THROW(msg)
Throws an std::runtime_error with the given message.
Definition: stl_reader.h:141
bool ReadStlFile_BINARY(const char *filename, TNumberContainer1 &coordsOut, TNumberContainer2 &normalsOut, TIndexContainer1 &trisOut, TIndexContainer2 &solidRangesOut)
Reads a binary stl file into several arrays.
Definition: stl_reader.h:665