8cb371f81c
- piccoli adattamenti.
375 lines
11 KiB
C++
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) ;
|
|
}
|