//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : ImportStl.cpp Data : 04.04.14 Versione : 1.5d1 // Contenuto : Implementazione della classe per l'importazione di STL. // // // // Modifiche : 04.04.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "ImportStl.h" #include "DllMain.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDEv/Include/EGnScan.h" #include "/EgtDev/Include/EgnStringUtils.h" #include "/EgtDev/Include/EgnStringConverter.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" using namespace std ; //---------------------------------------------------------------------------- IImportStl* CreateImportStl( void) { return static_cast ( new(nothrow) ImportStl) ; } //---------------------------------------------------------------------------- bool ImportStl::Import( const string& sFile, IGeomDB* pGDB, int nIdGroup) { switch ( StlType( sFile)) { case STL_ASCII : return ImportASCII( sFile, pGDB, nIdGroup) ; case STL_BINARY : return ImportBinary( sFile, pGDB, nIdGroup) ; default : return false ; } } //---------------------------------------------------------------------------- int ImportStl::StlType( const std::string& sFile) { // apertura del file di ingresso ifstream InFile ; InFile.open( stringtoW( sFile), ios::in | ios::binary) ; if ( InFile.fail()) return STL_ERROR ; // lettura dei primi 256 byte char cBuff[256] ; InFile.read( cBuff, 255) ; cBuff[InFile.gcount()] = '\0' ; // chiusura del file InFile.close() ; // verifico se iniziano con "solid" e poi "facet" e "normal" string sBuff = cBuff ; size_t nPosS = sBuff.find( "solid") ; size_t nPosF = sBuff.find( "facet") ; size_t nPosN = sBuff.find( "normal") ; if ( nPosS != string::npos && nPosS < 10 && nPosF != string::npos && nPosN != string::npos) return STL_ASCII ; else return STL_BINARY ; } //---------------------------------------------------------------------------- bool ImportStl::ImportASCII( const string& sFile, IGeomDB* pGDB, int nIdGroup) { // inizializzo lo scanner Scanner TheScanner ; if ( ! TheScanner.Init( sFile)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error on Init") return false ; } // verifico il DB geometrico if ( pGDB == nullptr) { LOG_ERROR( GetEExLogger(), "ImportStl : Error on GeomDB") return false ; } m_pGDB = pGDB ; // verifico l'Id di gruppo if ( ! m_pGDB->ExistsObj( nIdGroup)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error on IdGroup") return false ; } m_nIdGroup = nIdGroup ; // ciclo di lettura degli oggetti bool bOk = true ; bool bEnd = false ; do { if ( ! LoadSolid( TheScanner, bEnd)) { bOk = false ; string sOut = "ImportStl : Error on line " + ToString( TheScanner.GetCurrLineNbr()) ; LOG_ERROR( GetEExLogger(), sOut.c_str()) } } while ( bOk && ! bEnd) ; return bOk ; } //---------------------------------------------------------------------------- bool ImportStl::LoadSolid( Scanner& TheScanner, bool& bEnd) { string sLine ; STRVECTOR vsParams ; // recupero la prima linea if ( ! TheScanner.GetLine( sLine)) { bEnd = true ; return true ; } // la divido in parametri Tokenize( sLine, " ", vsParams) ; // almeno 1 parametro if ( vsParams.size() < 1) return false ; // deve essere la parola chiave "solid" if ( vsParams[0] != "solid") return false ; // se c'è un secondo parametro è il nome string sName ; if ( vsParams.size() >= 2) sName = vsParams[1] ; // preparo l'oggetto TriMesh PtrOwner pSTM( CreateSurfTriMesh()) ; if ( ! IsValid( pSTM)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error allocating SurfTriMesh") return false ; } if ( ! pSTM->Init( 3, 1)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error initialising SurfTriMesh") return false ; } // pulisco Map dei vertici m_MapVert.clear() ; // ciclo di lettura dei triangoli bool bOk = true ; bool bTEnd = false ; do { if ( ! LoadTriangle( TheScanner, Get( pSTM), bTEnd)) { bOk = false ; string sOut = "ImportStl : Error on line " + ToString( TheScanner.GetCurrLineNbr()) ; LOG_ERROR( GetEExLogger(), sOut.c_str()) } } while ( bOk && ! bTEnd) ; // recupero la linea di terminazione dell'oggetto if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri Tokenize( sLine, " ", vsParams) ; // almeno 1 parametro if ( vsParams.size() < 1) return false ; // deve essere la parola chiave "endsolid" oppure "end" "solid" if ( vsParams[0] != "endsolid" && vsParams[0] != "end") return false ; // valido la superficie e calcolo le adiacenze if ( ! pSTM->AdjustTopology()) { LOG_ERROR( GetEExLogger(), "ImportStl : Error adjusting topology in SurfTriMesh") return false ; } // inserisco l'oggetto nel DB geometrico int nIdNew = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nIdGroup, Release( pSTM)) ; // se previsto il nome, lo assegno if ( ! sName.empty()) m_pGDB->SetName( nIdNew, sName) ; bEnd = false ; return ( nIdNew != GDB_ID_NULL) ; } //---------------------------------------------------------------------------- bool ImportStl::LoadTriangle( Scanner& TheScanner, ISurfTriMesh* pSTM, bool& bEnd) { string sLine ; STRVECTOR vsParams ; // recupero la prima linea if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri Tokenize( sLine, " ", vsParams) ; // almeno 1 parametro if ( vsParams.size() < 1) return false ; // deve essere la parola chiave "facet" if ( vsParams[0] != "facet") { TheScanner.UngetLine( sLine) ; bEnd = true ; return true ; } // ignoro il resto // recupero la seconda linea if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri Tokenize( sLine, " ", vsParams) ; // almeno 2 parametri if ( vsParams.size() < 2) return false ; // devono essere le parole chiave "outer" e "loop" if ( vsParams[0] != "outer" || vsParams[1] != "loop") return false ; // ciclo sui tre vertici int nIdV[3] ; PntIntMap::iterator Iter ; for ( int i = 0 ; i < 3 ; ++ i) { // recupero una linea if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri Tokenize( sLine, " ", vsParams) ; // almeno 4 parametri if ( vsParams.size() < 4) return false ; // parola chiave "vertex" if ( vsParams[0] != "vertex") return false ; // tre coordinate del vertice Point3d ptP ; if ( ! FromString( vsParams[1], ptP.x) || ! FromString( vsParams[2], ptP.y) || ! FromString( vsParams[3], ptP.z)) return false ; // verifico se vertice già presente Iter = m_MapVert.find( ptP) ; if ( Iter == m_MapVert.end()) { // aggiungo il vertice if ( ( nIdV[i] = pSTM->AddVertex( ptP)) == -1) return false ; m_MapVert[ptP] = nIdV[i] ; } else nIdV[i] = Iter->second ; } // se i vertici sono tutti diversi tra loro, inserisco il triangolo if ( nIdV[0] != nIdV[1] && nIdV[0] != nIdV[2] && nIdV[1] != nIdV[2]) { if ( pSTM->AddTriangle( nIdV) == -1) return false ; } // nuova linea if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri Tokenize( sLine, " ", vsParams) ; // almeno 1 parametro if ( vsParams.size() < 1) return false ; // parola chiave "endloop" if ( vsParams[0] != "endloop") return false ; // nuova linea if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri Tokenize( sLine, " ", vsParams) ; // almeno 1 parametro if ( vsParams.size() < 1) return false ; // parola chiave "endfacet" if ( vsParams[0] != "endfacet") return false ; bEnd = false ; return true ; } //---------------------------------------------------------------------------- bool ImportStl::ImportBinary( const string& sFile, IGeomDB* pGDB, int nIdGroup) { // apertura del file di ingresso ifstream InFile ; InFile.open( stringtoW( sFile), ios::in | ios::binary) ; if ( InFile.fail()) return false ; // verifico il DB geometrico if ( pGDB == nullptr) { LOG_ERROR( GetEExLogger(), "ImportStl : Error on GeomDB") return false ; } m_pGDB = pGDB ; // verifico l'Id di gruppo if ( ! m_pGDB->ExistsObj( nIdGroup)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error on IdGroup") return false ; } m_nIdGroup = nIdGroup ; // lettura dei primi ottanta byte (commento da scartare) const int LEN_REM = 80 ; char cRem[LEN_REM] ; InFile.read( cRem, LEN_REM) ; if ( InFile.gcount() != LEN_REM) return false ; // lettura del numero di triangoli const int LEN_INT = 4 ; union { int i; char c[LEN_INT]; } uTria ; InFile.read( uTria.c, LEN_INT) ; if ( InFile.gcount() != LEN_INT) return false ; // preparo l'oggetto TriMesh PtrOwner pSTM( CreateSurfTriMesh()) ; if ( ! IsValid( pSTM)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error allocating SurfTriMesh") return false ; } if ( ! pSTM->Init( 3, 1)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error initialising SurfTriMesh") return false ; } // pulisco Map dei vertici m_MapVert.clear() ; // lettura dei triangoli for ( int j = 0 ; j < uTria.i ; ++ j) { // salto i 3 float per la normale const int LEN_NRM = 12 ; char cNorm[LEN_NRM] ; InFile.read( cNorm, LEN_NRM) ; if ( InFile.gcount() != LEN_NRM) return false ; // ciclo sui tre vertici int nIdV[3] ; PntIntMap::iterator Iter ; for ( int i = 0 ; i < 3 ; ++ i) { const int LEN_3F = 12 ; union { float f[3]; char c[LEN_3F]; } ufP ; InFile.read( ufP.c, LEN_3F) ; if ( InFile.gcount() != LEN_3F) return false ; Point3d ptP( ufP.f[0], ufP.f[1], ufP.f[2]) ; // verifico se vertice già presente Iter = m_MapVert.find( ptP) ; if ( Iter == m_MapVert.end()) { // aggiungo il vertice if ( ( nIdV[i] = pSTM->AddVertex( ptP)) == -1) return false ; m_MapVert[ptP] = nIdV[i] ; } else nIdV[i] = Iter->second ; } // se i vertici sono tutti diversi tra loro, inserisco il triangolo if ( nIdV[0] != nIdV[1] && nIdV[0] != nIdV[2] && nIdV[1] != nIdV[2]) { if ( pSTM->AddTriangle( nIdV) == -1) return false ; } // salto 2 byte const int LEN_SKI = 2 ; char cSkip[LEN_SKI] ; InFile.read( cSkip, LEN_SKI) ; if ( InFile.gcount() != LEN_SKI) return false ; } // valido la superficie e calcolo le adiacenze if ( ! pSTM->AdjustTopology()) { LOG_ERROR( GetEExLogger(), "ImportStl : Error adjusting topology in SurfTriMesh") return false ; } // inserisco l'oggetto nel DB geometrico int nIdNew = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nIdGroup, Release( pSTM)) ; // chiusura del file InFile.close() ; return ( nIdNew != GDB_ID_NULL) ; }