//---------------------------------------------------------------------------- // 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/EExDllMain.h" #include "/EgtDEv/Include/EGnScanner.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include "/EgtDev/Include/SELkKeyProc.h" #include "/EgtDev/Include/EgtKeyCodes.h" #include "/EgtDev/Include/EgtStringConverter.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include using namespace std ; //---------------------------------------------------------------------------- IImportStl* CreateImportStl( void) { // verifico la chiave e le opzioni if ( ! VerifyKey( KEYOPT_EEX_INPBASE)) return nullptr ; // creo l'oggetto return static_cast ( new(nothrow) ImportStl) ; } //---------------------------------------------------------------------------- bool ImportStl::Import( const string& sFile, IGeomDB* pGDB, int nIdGroup, double dScaleFactor) { // 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 ; // verifico il fattore di scala if ( dScaleFactor < EPS_SMALL) { LOG_ERROR( GetEExLogger(), "ImportStl : Error on ScaleFactor too small (minimum 0.001).") return false ; } m_dScaleFactor = dScaleFactor ; // eseguo l'opportuna importazione switch ( StlType( sFile)) { case STL_ASCII : return ImportASCII( sFile) ; case STL_BINARY : return ImportBinary( sFile) ; 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) { // inizializzo lo scanner Scanner TheScanner ; if ( ! TheScanner.Init( sFile)) { LOG_ERROR( GetEExLogger(), "ImportStl : Error on Init") return false ; } // 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) { // recupero la prima linea string sLine ; if ( ! TheScanner.GetLine( sLine)) { bEnd = true ; return true ; } // la divido in parametri STRVECTOR vsParams ; 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] ; // Costruttore di trimesh da insieme disordinato di triangoli StmFromTriangleSoup StmFts ; if ( ! StmFts.Start()) { LOG_ERROR( GetEExLogger(), "ImportStl : Error initialising StmFromTriangleSoup") return false ; } // ciclo di lettura dei triangoli Triangle3d Tria ; bool bOk = true ; bool bTEnd = false ; do { // leggo i dati del triangolo if ( LoadTriangle( TheScanner, Tria, bTEnd)) { // se letto, aggiungo il triangolo if ( ! bTEnd && ! StmFts.AddTriangle( Tria)) bOk = false ; } else { 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 ( ! StmFts.End()) { LOG_ERROR( GetEExLogger(), "ImportStl : Error adjusting topology in SurfTriMesh") return false ; } // inserisco l'oggetto nel DB geometrico ISurfTriMesh* pSTM = StmFts.GetSurf() ; int nIdNew = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nIdGroup, 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, Triangle3d& Tria, bool& bEnd) { // recupero la prima linea string sLine ; if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri STRVECTOR vsParams ; 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 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 ; // scalo il vertice ptP *= m_dScaleFactor ; // inserisco il vertice nel triangolo Tria.SetP( i, ptP) ; } // 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) { // apertura del file di ingresso ifstream InFile ; InFile.open( stringtoW( sFile), ios::in | ios::binary) ; if ( InFile.fail()) return false ; // 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 ; // Costruttore di trimesh da insieme disordinato di triangoli StmFromTriangleSoup StmFts ; if ( ! StmFts.Start()) { LOG_ERROR( GetEExLogger(), "ImportStl : Error initialising StmFromTriangleSoup") return false ; } // 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 ; // recupero i tre vertici Triangle3d Tria ; 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 ; Tria.SetP( i, Point3d( ufP.f[0] * m_dScaleFactor, ufP.f[1] * m_dScaleFactor, ufP.f[2] * m_dScaleFactor)) ; } // aggiungo il triangolo if ( ! StmFts.AddTriangle( Tria)) 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 ( ! StmFts.End()) { LOG_ERROR( GetEExLogger(), "ImportStl : Error adjusting topology in SurfTriMesh") return false ; } // inserisco l'oggetto nel DB geometrico ISurfTriMesh* pSTM = StmFts.GetSurf() ; int nIdNew = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nIdGroup, pSTM) ; // chiusura del file InFile.close() ; return ( nIdNew != GDB_ID_NULL) ; }