Files
EgtExchange/ImportStl.cpp
T
Dario Sassi 8cb371f81c EgtExchange :
- piccoli adattamenti.
2015-06-06 17:51:26 +00:00

375 lines
11 KiB
C++

//----------------------------------------------------------------------------
// 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 <fstream>
using namespace std ;
//----------------------------------------------------------------------------
IImportStl*
CreateImportStl( void)
{
// verifico la chiave e le opzioni
if ( ! TestKeyForEEx( GetEExKey(), KEYOPT_EEX_INPBASE, GetEExLogger()))
return false ;
// creo l'oggetto
return static_cast<IImportStl*> ( 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)
{
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] ;
// 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)
{
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
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) ;
}