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