/*===========================================================================*\ * * * OpenMesh * * Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen * * www.openmesh.org * * * *---------------------------------------------------------------------------* * * * License * * * * This library is free software; you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as published * * by the Free Software Foundation, version 2.1. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * \*===========================================================================*/ //== INCLUDES ================================================================= // STL #include #include // OpenMesh #include #include #include #include #include #include //=== NAMESPACES ============================================================== namespace OpenMesh { namespace IO { //=== INSTANCIATE ============================================================= // register the STLReader singleton with MeshReader _STLReader_ __STLReaderInstance; _STLReader_& STLReader() { return __STLReaderInstance; } //=== IMPLEMENTATION ========================================================== _STLReader_:: _STLReader_() : eps_(FLT_MIN) { IOManager().register_module(this); } //----------------------------------------------------------------------------- bool _STLReader_:: read(const std::string& _filename, BaseImporter& _bi, Options& _opt) { bool result = false; STL_Type file_type = NONE; if ( check_extension( _filename, "stla" ) ) { file_type = STLA; } else if ( check_extension( _filename, "stlb" ) ) { file_type = STLB; } else if ( check_extension( _filename, "stl" ) ) { file_type = check_stl_type(_filename); } switch (file_type) { case STLA: { result = read_stla(_filename, _bi); _opt -= Options::Binary; break; } case STLB: { result = read_stlb(_filename, _bi); _opt += Options::Binary; break; } default: { result = false; break; } } return result; } //----------------------------------------------------------------------------- #ifndef DOXY_IGNORE_THIS class CmpVec { public: CmpVec(float _eps=FLT_MIN) : eps_(_eps) {} bool operator()( const Vec3f& _v0, const Vec3f& _v1 ) const { if (fabs(_v0[0] - _v1[0]) <= eps_) { if (fabs(_v0[1] - _v1[1]) <= eps_) { return (_v0[2] < _v1[2] - eps_); } else return (_v0[1] < _v1[1] - eps_); } else return (_v0[0] < _v1[0] - eps_); } private: float eps_; }; #endif //----------------------------------------------------------------------------- bool _STLReader_:: read_stla(const std::string& _filename, BaseImporter& _bi) const { omlog() << "[STLReader] : read ascii file\n"; FILE* in = fopen(_filename.c_str(), "r"); if (!in) { omerr() << "[STLReader] : cannot not open file " << _filename << std::endl; return false; } char line[100], *p; unsigned int i; OpenMesh::Vec3f v; unsigned int cur_idx(0); BaseImporter::VHandles vhandles; CmpVec comp(eps_); std::map vMap(comp); std::map::iterator vMapIt; while (in && !feof(in) && fgets(line, 100, in)) { for (p=line; isspace(*p) && *p!='\0'; ++p) {}; // skip white-space if ((strncmp(p, "outer", 5) == 0) || (strncmp(p, "OUTER", 5) == 0)) { vhandles.clear(); for (i=0; i<3; ++i) { fgets(line, 100, in); for (p=line; isspace(*p) && *p!='\0'; ++p) {}; // skip white-space sscanf(p+6, "%f %f %f", &v[0], &v[1], &v[2]); // has vector been referenced before? if ((vMapIt=vMap.find(v)) == vMap.end()) { // No : add vertex and remember idx/vector mapping _bi.add_vertex(v); vhandles.push_back(VertexHandle(cur_idx)); vMap[v] = VertexHandle(cur_idx++); } else // Yes : get index from map vhandles.push_back(vMapIt->second); } // Add face only if it is not degenerated if ((vhandles[0] != vhandles[1]) && (vhandles[0] != vhandles[2]) && (vhandles[1] != vhandles[2])) _bi.add_face(vhandles); } } fclose(in); // In general a file has data, there the number of vertices cannot be 0. return _bi.n_vertices() != 0; } //----------------------------------------------------------------------------- bool _STLReader_:: read_stlb(const std::string& _filename, BaseImporter& _bi) const { omlog() << "[STLReader] : read binary file\n"; FILE* in = fopen(_filename.c_str(), "rb"); if (!in) { omerr() << "[STLReader] : cannot not open file " << _filename << std::endl; return false; } char dummy[100]; bool swapFlag; unsigned int i, nT; OpenMesh::Vec3f v; unsigned int cur_idx(0); BaseImporter::VHandles vhandles; std::map vMap; std::map::iterator vMapIt; // check size of types if ((sizeof(float) != 4) || (sizeof(int) != 4)) { omerr() << "[STLReader] : wrong type size\n"; return false; } // determine endian mode union { unsigned int i; unsigned char c[4]; } endian_test; endian_test.i = 1; swapFlag = (endian_test.c[3] == 1); // read number of triangles fread(dummy, 1, 80, in); nT = read_int(in, swapFlag); // read triangles while (nT) { vhandles.clear(); // skip triangle normal fread(dummy, 1, 12, in); // triangle's vertices for (i=0; i<3; ++i) { v[0] = read_float(in, swapFlag); v[1] = read_float(in, swapFlag); v[2] = read_float(in, swapFlag); // has vector been referenced before? if ((vMapIt=vMap.find(v)) == vMap.end()) { // No : add vertex and remember idx/vector mapping _bi.add_vertex(v); vhandles.push_back(VertexHandle(cur_idx)); vMap[v] = VertexHandle(cur_idx++); } else // Yes : get index from map vhandles.push_back(vMapIt->second); } // Add face only if it is not degenerated if ((vhandles[0] != vhandles[1]) && (vhandles[0] != vhandles[2]) && (vhandles[1] != vhandles[2])) _bi.add_face(vhandles); fread(dummy, 1, 2, in); --nT; } return true; } //----------------------------------------------------------------------------- _STLReader_::STL_Type _STLReader_:: check_stl_type(const std::string& _filename) const { // assume it's binary stl, then file size is known from #triangles // if size matches, it's really binary // open file FILE* in = fopen(_filename.c_str(), "rb"); if (!in) return NONE; // determine endian mode union { unsigned int i; unsigned char c[4]; } endian_test; endian_test.i = 1; bool swapFlag = (endian_test.c[3] == 1); // read number of triangles char dummy[100]; fread(dummy, 1, 80, in); unsigned int nT = read_int(in, swapFlag); // compute file size from nT unsigned int binary_size = 84 + nT*50; // get actual file size unsigned int file_size(0); rewind(in); while (!feof(in)) file_size += fread(dummy, 1, 100, in); fclose(in); // if sizes match -> it's STLB return (binary_size == file_size ? STLB : STLA); } //============================================================================= } // namespace IO } // namespace OpenMesh //=============================================================================