Files
EgtExchange/Export3MF.cpp
T
SaraP 2a4d3b7947 EgtExchange :
- in export 3MF aggiunta esportazione texture
- in export 3MF migliorie varie.
2021-11-03 15:10:49 +01:00

426 lines
14 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2014-2014
//----------------------------------------------------------------------------
// File : Export3MF.cpp Data : 01.09.21 Versione : 2.3i1
// Contenuto : Implementazione della classe per l'esportazione in formato 3MF.
//
//
//
// Modifiche : 07.08.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "Export3MF.h"
#include "DllMain.h"
#include "/EgtDev/Include/EExDllMain.h"
#include "/EgtDev/Include/EGkGeomDB.h"
#include "/EgtDev/Include/EGkSurfFlatRegion.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkGdbIterator.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/SELkKeyProc.h"
#include "/EgtDev/Include/EgtKeyCodes.h"
#include "/EgtDev/Include/EgtStringConverter.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EXeExecutor.h"
#include "/EgtDev/Include/EGnFileUtils.h"
using namespace std ;
using namespace Lib3MF ;
//----------------------------------------------------------------------------
IExport3MF*
CreateExport3MF( void)
{
// verifico la chiave e le opzioni
if ( ! TestKeyForEEx( GetEExKey(), KEYOPT_EEX_EXPBASE, GetEExLogger()))
return nullptr ;
// creo l'oggetto
return static_cast<IExport3MF*> ( new(nothrow) Export3MF) ;
}
//----------------------------------------------------------------------------
bool
Export3MF::SetOptions( int nFilter)
{
m_nFilter = nFilter ;
return true ;
}
//----------------------------------------------------------------------------
bool
Export3MF::Export( IGeomDB* pGDB, int nId, const string& sFile)
{
// verifico il DB geometrico
if ( pGDB == nullptr) {
LOG_ERROR( GetEExLogger(), "Export3MF : Error on GeomDB")
return false ;
}
m_pGDB = pGDB ;
// verifico l'Id dell'oggetto da esportare
if ( ! pGDB->ExistsObj( nId)) {
LOG_ERROR( GetEExLogger(), "Export3MF : Error on Id")
return false ;
}
try {
if ( ! DoExport( nId, sFile))
return false ;
}
catch ( ELib3MFException &exception) {
LOG_ERROR( GetEExLogger(), exception.what()) ;
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Export3MF::DoExport( const int& nId, const string& sFile)
{
// libreria 3MF
m_wrapper = CWrapper::loadLibrary() ;
if ( ! m_wrapper) {
LOG_ERROR( GetEExLogger(), "Export3MF : Error on lib3mf Wrapper")
return false ;
}
// creo model per 3MF
m_model = m_wrapper->CreateModel() ;
if ( ! m_model) {
LOG_ERROR( GetEExLogger(), "Export3MF : Error on lib3mf Model")
return false ;
}
if ( ! m_model->AddColorGroup()) {
LOG_ERROR( GetEExLogger(), "Export3MF : Error on lib3mf Color Group")
return false ;
}
// creo un iteratore
PtrOwner<IGdbIterator> pIter( CreateGdbIterator( m_pGDB)) ;
if ( IsNull( pIter))
return false ;
pIter->GoTo( nId) ;
// esporto l'oggetto e i suoi eventuali figli
if ( ! ExportObject( *pIter))
return false ;
// scrivo il file
PWriter writer = m_model->QueryWriter( "3mf") ;
writer->WriteToFile( sFile) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Export3MF::ExportObject( const IGdbIterator& iIter)
{
switch ( iIter.GetGdbType()) {
case GDB_TY_GEO :
{
// recupero l'oggetto geometrico
const IGeoObj* pGeoObj = iIter.GetGeoObj() ;
if ( pGeoObj == nullptr)
return true ;
// se non è una superficie esco
if ( pGeoObj->GetType() != SRF_TRIMESH && pGeoObj->GetType() != SRF_FLATRGN)
return true ;
// recupero il livello dell'oggetto
int nLev = GDB_LV_USER ;
iIter.GetCalcLevel( nLev) ;
// recupero il modo dell'oggetto
int nMode = GDB_MD_STD ;
iIter.GetCalcMode( nMode) ;
// recupero lo stato dell'oggetto
int nStat = GDB_ST_ON ;
iIter.GetCalcStatus( nStat) ;
// se il filtro lo abilita
if ( TestFilter( nLev, nMode, nStat)) {
// emetto l'oggetto
switch ( pGeoObj->GetType()) {
case SRF_TRIMESH :
if ( ! ExportSTM( iIter.GetId(), GetSurfTriMesh( pGeoObj)))
return false ;
break ;
case SRF_FLATRGN :
if ( ! ExportSFR( iIter.GetId(), GetSurfFlatRegion( pGeoObj)))
return false ;
break ;
default :
break ;
}
}
}
return true ;
case GDB_TY_GROUP :
// esploro il gruppo
return ScanGroup( iIter) ;
default :
return false ;
}
}
//----------------------------------------------------------------------------
bool
Export3MF::TestFilter( int nLev, int nMode, int nStat)
{
if ( ( nLev == GDB_LV_USER && ( m_nFilter & EEXFLT_LEVUSER) == 0) ||
( nLev == GDB_LV_SYSTEM && ( m_nFilter & EEXFLT_LEVSYSTEM) == 0) ||
( nLev == GDB_LV_TEMP && ( m_nFilter & EEXFLT_LEVTEMP) == 0))
return false ;
if ( ( nMode == GDB_MD_STD && ( m_nFilter & EEXFLT_MODESTD) == 0) ||
( nMode == GDB_MD_LOCKED && ( m_nFilter & EEXFLT_MODELOCKED) == 0) ||
( nMode == GDB_MD_HIDDEN && ( m_nFilter & EEXFLT_MODEHIDDEN) == 0))
return false ;
if ( ( nStat == GDB_ST_OFF && ( m_nFilter & EEXFLT_STAOFF) == 0) ||
( nStat == GDB_ST_ON && ( m_nFilter & EEXFLT_STAON) == 0) ||
( nStat == GDB_ST_SEL && ( m_nFilter & EEXFLT_STASEL) == 0))
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
Export3MF::ExportSFR( const int& nId, const ISurfFlatRegion* pSFR)
{
// verifico oggetto
if ( pSFR == nullptr || nId == GDB_ID_NULL)
return false ;
// ricavo la trimesh equivalente
const ISurfTriMesh* pStm = pSFR->GetAuxSurf() ;
return ExportSTM( nId, pStm) ;
}
//----------------------------------------------------------------------------
bool
Export3MF::ExportSTM( const int& nId, const ISurfTriMesh* pSTM)
{
// verifico oggetto
if ( pSTM == nullptr || nId == GDB_ID_NULL)
return false ;
// recupero il riferimento globale dell'oggetto
Frame3d frFrame ;
if ( ! m_pGDB->GetGlobFrame( nId, frFrame))
return false ;
// recupero eventuale nome
string sName ;
if ( ! m_pGDB->GetName( nId, sName))
sName = ToString( nId) ;
// ciclo sui vertici della trimesh
vector<sLib3MFPosition> vVertices( pSTM->GetVertexSize()) ;
for ( int i = 0 ; i < pSTM->GetVertexSize() ; i++) {
Point3d pt ;
pSTM->GetVertex( i, pt) ;
pt.ToGlob( frFrame) ;
vVertices[i].m_Coordinates[0] = Lib3MF_single( pt.x) ;
vVertices[i].m_Coordinates[1] = Lib3MF_single( pt.y) ;
vVertices[i].m_Coordinates[2] = Lib3MF_single( pt.z) ;
}
// ciclo sui triangoli della trimesh
vector<sLib3MFTriangle> vTriangles( pSTM->GetTriangleCount()) ;
int k = 0 ;
for ( int i = 0 ; i < pSTM->GetTriangleSize() ; i++) {
int nIdVert[3] ;
if ( ! pSTM->GetTriangle( i, nIdVert))
continue ; // se il triangolo non è valido passo al successivo
vTriangles[k].m_Indices[0] = nIdVert[0] ;
vTriangles[k].m_Indices[1] = nIdVert[1] ;
vTriangles[k].m_Indices[2] = nIdVert[2] ;
k ++ ;
}
if ( vVertices.size() == 0 || vTriangles.size() == 0) {
LOG_ERROR( GetEExLogger(), ("Export3MF : surface \"" + sName + "\" is empty. Ignored.").c_str()) ;
return true ;
}
// creo mesh 3MF
PMeshObject meshObject = m_model->AddMeshObject() ;
if ( ! meshObject) {
LOG_ERROR( GetEExLogger(), "Export3MF : Error on lib3mf Mesh Object")
return false ;
}
meshObject->SetName( sName) ;
meshObject->SetGeometry( vVertices, vTriangles) ;
// texture
if ( ! ExportTexture( nId, pSTM, meshObject))
return false ;
// assegno il colore
Color cCol ;
if ( GetColor( nId, cCol)) {
Lib3MF_uint32 nColId = ColorHandler3MF( cCol) ;
meshObject->SetObjectLevelProperty( 1, nColId) ;
}
m_model->AddBuildItem( meshObject.get(), m_wrapper->GetIdentityTransform()) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Export3MF::ScanGroup( const IGdbIterator& iIter)
{
// creo un iteratore
PtrOwner<IGdbIterator> pIter( CreateGdbIterator( iIter.GetGDB())) ;
if ( IsNull( pIter))
return false ;
// scandisco il gruppo
bool bOk = true ;
for ( bool bNext = pIter->GoToFirstInGroup( iIter) ;
bNext ;
bNext = pIter->GoToNext()) {
if ( ! ExportObject( *pIter))
bOk = false ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
Export3MF::GetColor( const int& nId, Color& cCol)
{
if ( nId == GDB_ID_NULL)
return false ;
if ( ! m_pGDB->GetMaterial( nId, cCol))
// se fallisce cerco il colore del parent
return GetColor( m_pGDB->GetParentId( nId), cCol) ;
return true ;
}
//----------------------------------------------------------------------------
Lib3MF_uint32
Export3MF::ColorHandler3MF( const Color& cCol)
{
PColorGroup pColorGrp = m_model->GetColorGroupByID( 1) ;
// converto il colore nel formato usato da 3MF
Lib3MF_uint8 nAlpha = ( int)( cCol.GetIntAlpha() * 2.55 + 0.5) ;
sColor cCol3mf = m_wrapper->RGBAToColor( cCol.GetIntRed(), cCol.GetIntGreen(), cCol.GetIntBlue(), nAlpha) ;
// verifico se il colore è già presente nel colorgroup
UINTVECTOR vColorIdx ;
pColorGrp->GetAllPropertyIDs( vColorIdx) ;
for ( Lib3MF_uint32 i : vColorIdx) {
sColor cColTmp = pColorGrp->GetColor( i) ;
if ( cColTmp.m_Red == cCol3mf.m_Red && cColTmp.m_Green == cCol3mf.m_Green && cColTmp.m_Blue == cCol3mf.m_Blue
&& cColTmp.m_Alpha == cCol3mf.m_Alpha)
return i ;
}
// se non fosse presente, lo aggiungo
return pColorGrp->AddColor( cCol3mf) ;
}
//----------------------------------------------------------------------------
bool
Export3MF::ExportTexture( const int& nObjId, const ISurfTriMesh* pSTM, PMeshObject& meshObject)
{
// verifico esistenza texture
string sTxrName ;
if ( ! m_pGDB->GetTextureName( nObjId, sTxrName))
return true ;
// cerco id della texture nel GeomDB
int nGrpId = m_pGDB->GetFirstNameInGroup( GDB_ID_ROOT, "Photos") ;
if ( nGrpId == GDB_ID_NULL)
return false ;
int nTxrId = m_pGDB->GetFirstNameInGroup( nGrpId, sTxrName) ;
if ( nTxrId == GDB_ID_NULL)
return false ;
double dDimX, dDimY ;
if ( ! ExeGetPhotoDimensions( nTxrId, dDimX, dDimY))
return false ;
// frame per gestire la texture
Frame3d frSrf ;
if ( ! m_pGDB->GetTextureFrame( nObjId, frSrf))
return false ;
Lib3MF_uint32 nTxrGrpId = TextureGroupHandler( nTxrId) ;
PTexture2DGroup textureGroup = m_model->GetTexture2DGroupByID( nTxrGrpId) ;
// creo coordinate ( u, v) della texture per ogni vertice di pSTM
for ( int i = 0 ; i < pSTM->GetVertexSize() ; i ++) {
Point3d pt( 0, 0, 0) ;
pSTM->GetVertex( i, pt) ;
pt.ToLoc( frSrf) ;
textureGroup->AddTex2Coord( sLib3MFTex2Coord({ pt.x / dDimX, pt.y / dDimY})) ;
}
// indice in textureGroup corrispondente al primo vertice di questa superficie
int nOffs = textureGroup->GetCount() - pSTM->GetVertexSize() + 1 ;
// assegno ai triangoli
int k = 0 ;
for ( int i = 0 ; i < pSTM->GetTriangleSize() ; i++) {
sLib3MFTriangleProperties property ;
property.m_ResourceID = nTxrGrpId ;
int nIdVert[3] ;
if ( ! pSTM->GetTriangle( i, nIdVert))
continue ;
property.m_PropertyIDs[0] = nIdVert[0] + nOffs ;
property.m_PropertyIDs[1] = nIdVert[1] + nOffs ;
property.m_PropertyIDs[2] = nIdVert[2] + nOffs ;
meshObject->SetTriangleProperties( k, property) ;
k ++ ;
}
return true ;
}
//----------------------------------------------------------------------------
Lib3MF_uint32
Export3MF::TextureGroupHandler( const int& nTxrId)
{
auto it = m_TexturesMap.find( nTxrId) ;
// se la texture è già presente nel modello 3MF restituisco il suo id
if ( it != m_TexturesMap.end())
return it->second ;
// se non è presente l'aggiungo
string sTxrPath ;
string sInfo ;
m_pGDB->GetInfo( nTxrId, "Path", sInfo) ;
ExeGetPhotoPath( nTxrId, sTxrPath) ;
string sTxrExtension = GetFileExtension( sTxrPath) ;
string sTxrRelationshipType = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture" ;
string sOPCPath = "/3D/Texture/texture_" + to_string( m_TexturesMap.size()) + "." + sTxrExtension ;
PAttachment attachment = m_model->AddAttachment( sOPCPath, sTxrRelationshipType) ;
attachment->ReadFromFile( sTxrPath) ;
PTexture2D texture2D = m_model->AddTexture2DFromAttachment( attachment.get()) ;
if ( sTxrExtension == "jpg" || sTxrExtension == "jpeg")
texture2D->SetContentType( eTextureType::JPEG) ;
else if ( sTxrExtension == "png")
texture2D->SetContentType( eTextureType::PNG) ;
texture2D->SetTileStyleUV( eTextureTileStyle::NoTileStyle, eTextureTileStyle::NoTileStyle) ;
PTexture2DGroup textureGroup = m_model->AddTexture2DGroup( texture2D.get()) ;
Lib3MF_uint32 nTxrGrpId = textureGroup->GetResourceID() ;
m_TexturesMap.emplace( nTxrId, nTxrGrpId) ;
return nTxrGrpId ;
}