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;
140 #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()));}
148 namespace stl_reader {
191 template <
class TNumberContainer1,
class TNumberContainer2,
192 class TIndexContainer1,
class TIndexContainer2>
193 bool ReadStlFile(
const char* filename,
194 TNumberContainer1& coordsOut,
195 TNumberContainer2& normalsOut,
196 TIndexContainer1& trisOut,
197 TIndexContainer2& solidRangesOut);
204 template <
class TNumberContainer1,
class TNumberContainer2,
205 class TIndexContainer1,
class TIndexContainer2>
206 bool ReadStlFile_ASCII(
const char* filename,
207 TNumberContainer1& coordsOut,
208 TNumberContainer2& normalsOut,
209 TIndexContainer1& trisOut,
210 TIndexContainer2& solidRangesOut);
217 template <
class TNumberContainer1,
class TNumberContainer2,
218 class TIndexContainer1,
class TIndexContainer2>
219 bool ReadStlFile_BINARY(
const char* filename,
220 TNumberContainer1& coordsOut,
221 TNumberContainer2& normalsOut,
222 TIndexContainer1& trisOut,
223 TIndexContainer2& solidRangesOut);
230 inline bool StlFileHasASCIIFormat(
const char* filename);
234 template <
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;
416 namespace 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);
512 template <
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);
527 template <
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);
637 template <
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;
721 #endif //__H__STL_READER