aa80fb63af
- in import ed export 3MF gestione della gerarchia dei gruppi - migliorie e correzioni varie.
413 lines
15 KiB
C++
413 lines
15 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2014-2014
|
|
//----------------------------------------------------------------------------
|
|
// File : Import3MF.h Data : 29.01.21 Versione : 2.3b1
|
|
// Contenuto : Dichiarazione della classe Import3MF.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 21.01.21 SP Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "Import3MF.h"
|
|
#include "DllMain.h"
|
|
#include "/EgtDev/Include/EExDllMain.h"
|
|
#include "/EgtDev/Include/EGkSurfTriMesh.h"
|
|
|
|
using namespace std ;
|
|
using namespace Lib3MF ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
IImport3MF*
|
|
CreateImport3MF( void)
|
|
{
|
|
// verifico la chiave e le opzioni
|
|
if ( ! VerifyKey( KEYOPT_EEX_INPBASE))
|
|
return nullptr ;
|
|
// creo l'oggetto
|
|
return static_cast<IImport3MF*> ( new( nothrow) Import3MF) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Import3MF::Import( const string& sFile, IGeomDB* pGDB, int nIdGroup, int nFlag)
|
|
{
|
|
LOG_INFO( GetEExLogger(), ( "Import3MF : " + sFile).c_str()) ;
|
|
|
|
// verifico il DB geometrico
|
|
if ( pGDB == nullptr) {
|
|
LOG_ERROR( GetEExLogger(), " Import3MF : Error on GeomDB") ;
|
|
return false ;
|
|
}
|
|
m_pGDB = pGDB ;
|
|
|
|
// verifico l'Id di gruppo
|
|
if ( ! m_pGDB->ExistsObj( nIdGroup)) {
|
|
LOG_ERROR( GetEExLogger(), " Import3MF : Error on IdGroup") ;
|
|
return false ;
|
|
}
|
|
m_nIdGroup = nIdGroup ;
|
|
|
|
// imposto le opzioni di importazione
|
|
m_nFlag = nFlag ;
|
|
|
|
try {
|
|
if ( ! DoImport( sFile))
|
|
return false ;
|
|
}
|
|
catch ( ELib3MFException &exception) {
|
|
LOG_ERROR( GetEExLogger(), exception.what()) ;
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Import3MF::DoImport( const string& sFile)
|
|
{
|
|
// libreria 3MF
|
|
m_wrapper = CWrapper::loadLibrary() ;
|
|
if ( m_wrapper == nullptr) {
|
|
LOG_ERROR( GetEExLogger(), " Import3MF : Error on lib3mf Wrapper") ;
|
|
return false ;
|
|
}
|
|
|
|
// creazione del 3MF model
|
|
m_model = m_wrapper->CreateModel() ;
|
|
if ( m_model == nullptr) {
|
|
LOG_ERROR( GetEExLogger(), " Import3MF : Error on lib3mf Model") ;
|
|
return false ;
|
|
}
|
|
|
|
// lettura file
|
|
PReader reader = m_model->QueryReader( "3mf") ;
|
|
reader->ReadFromFile( sFile) ;
|
|
for ( Lib3MF_uint32 nWarning = 0 ; nWarning < reader->GetWarningCount() ; nWarning ++) {
|
|
Lib3MF_uint32 nErrorCode ;
|
|
string sWarningMsg = reader->GetWarning( nWarning, nErrorCode) ;
|
|
string sErrorMsg = " Reading 3MF file encountered warning # " + to_string( nErrorCode) + " : " + sWarningMsg ;
|
|
LOG_ERROR( GetEExLogger(), sErrorMsg.c_str()) ;
|
|
}
|
|
|
|
switch ( m_model->GetUnit()) {
|
|
case eModelUnit::MicroMeter :
|
|
m_dScaleFactor = 0.001 ;
|
|
break ;
|
|
case eModelUnit::MilliMeter :
|
|
m_dScaleFactor = 1.0 ;
|
|
break ;
|
|
case eModelUnit::CentiMeter :
|
|
m_dScaleFactor = 10.0 ;
|
|
break ;
|
|
case eModelUnit::Inch :
|
|
m_dScaleFactor = 25.4 ;
|
|
break ;
|
|
case eModelUnit::Foot :
|
|
m_dScaleFactor = 304.8 ;
|
|
break ;
|
|
case eModelUnit::Meter :
|
|
m_dScaleFactor = 1000.0 ;
|
|
break ;
|
|
default:
|
|
m_dScaleFactor = 1.0 ;
|
|
}
|
|
|
|
// analisi metadata
|
|
PMetaDataGroup metaDataGrp = m_model->GetMetaDataGroup() ;
|
|
Lib3MF_uint32 nMetaDataCount = metaDataGrp->GetMetaDataCount() ;
|
|
for ( Lib3MF_uint32 i = 0 ; i < nMetaDataCount ; i ++) {
|
|
PMetaData metaData = metaDataGrp->GetMetaData( i) ;
|
|
string sName = metaData->GetName() ;
|
|
string sValue = metaData->GetValue() ;
|
|
if ( ! sName.empty() && ! sValue.empty())
|
|
m_pGDB->SetInfo( m_nIdGroup, sName, sValue) ;
|
|
}
|
|
|
|
// scorro gli items nel build node
|
|
PBuildItemIterator pBuildItemsIter = m_model->GetBuildItems() ;
|
|
while ( pBuildItemsIter->MoveNext()) {
|
|
PBuildItem pItem = pBuildItemsIter->GetCurrent() ;
|
|
// ignoro i suoi attributes e i suoi metadata
|
|
// recupero la sua trasformazione
|
|
sTransform sTransf = pItem->GetObjectTransform() ;
|
|
// lettura oggetto associato
|
|
if ( ! ReadObject( pItem->GetObjectResource(), sTransf, m_nIdGroup))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
bool
|
|
Import3MF::ReadObject( const PObject pObj, const sTransform& Transform, int nParentId)
|
|
{
|
|
if ( pObj == nullptr)
|
|
return false ;
|
|
|
|
// attributes
|
|
INFOVECTOR vInfo ;
|
|
string sName = pObj->GetName() ;
|
|
string sProp = pObj->GetPartNumber() ;
|
|
if ( ! sProp.empty())
|
|
vInfo.emplace_back( "PartNumber", sProp) ;
|
|
bool bUUID = false ;
|
|
sProp = pObj->GetUUID( bUUID) ;
|
|
if ( bUUID)
|
|
vInfo.emplace_back( "UUID", sProp) ;
|
|
|
|
switch ( pObj->GetType()) {
|
|
case eObjectType::Model :
|
|
vInfo.emplace_back( "Type", "Model") ;
|
|
break ;
|
|
case eObjectType::Support :
|
|
vInfo.emplace_back( "Type", "Support") ;
|
|
break ;
|
|
case eObjectType::SolidSupport :
|
|
vInfo.emplace_back( "Type", "SolidSupport") ;
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
|
|
// metadata
|
|
PMetaDataGroup pMetaDataGrp = pObj->GetMetaDataGroup() ;
|
|
for ( Lib3MF_uint32 i = 0 ; i < pMetaDataGrp->GetMetaDataCount() ; i ++) {
|
|
PMetaData metaData = pMetaDataGrp->GetMetaData( i) ;
|
|
string sMetaDataName = metaData->GetName() ;
|
|
string sMetaDataValue = metaData->GetValue() ;
|
|
if ( ! sMetaDataName.empty() && ! sMetaDataValue.empty())
|
|
vInfo.emplace_back( sMetaDataName, sMetaDataValue) ;
|
|
}
|
|
|
|
if ( pObj->IsMeshObject())
|
|
return ReadMesh( pObj->GetResourceID(), sName, vInfo, Transform, nParentId) ;
|
|
else if ( pObj->IsComponentsObject())
|
|
return ReadComponent( pObj->GetResourceID(), sName, vInfo, Transform, nParentId) ;
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------
|
|
bool
|
|
Import3MF::ReadMesh( Lib3MF_uint32 nId, const string& sName, const INFOVECTOR& vInfo, const sTransform& Transform, int nParentId)
|
|
{
|
|
// Recupero puntatore alla mesh 3MF
|
|
PMeshObject pMesh = m_model->GetMeshObjectByID( nId) ;
|
|
if ( pMesh == nullptr)
|
|
return false ;
|
|
|
|
// Creo e inizializzo trimesh
|
|
PtrOwner<ISurfTriMesh> pStm( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pStm) || ! pStm->Init( pMesh->GetVertexCount(), pMesh->GetTriangleCount())) {
|
|
LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : ISurfTriMesh Create error") ;
|
|
return false ;
|
|
}
|
|
pStm->SetLinearTolerance( 10 * EPS_SMALL) ;
|
|
|
|
// Ciclo sui vertici della mesh 3MF
|
|
for ( Lib3MF_uint32 i = 0 ; i < pMesh->GetVertexCount() ; i ++) {
|
|
// recupero le coordinate del vertice
|
|
sPosition pVertex = pMesh->GetVertex( i) ;
|
|
// applico la trasformazione
|
|
double x = 0.0, y = 0.0, z = 0.0 ;
|
|
for ( int k = 0 ; k < 3 ; k ++) {
|
|
x += pVertex.m_Coordinates[k] * Transform.m_Fields[k][0] ;
|
|
y += pVertex.m_Coordinates[k] * Transform.m_Fields[k][1] ;
|
|
z += pVertex.m_Coordinates[k] * Transform.m_Fields[k][2] ;
|
|
}
|
|
x += Transform.m_Fields[3][0] ;
|
|
y += Transform.m_Fields[3][1] ;
|
|
z += Transform.m_Fields[3][2] ;
|
|
// inserisco il vertice nella trimesh
|
|
if ( pStm->AddVertex( Point3d( x, y, z) * m_dScaleFactor) == SVT_NULL) {
|
|
LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : ISurfTriMesh AddVertex error") ;
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
// Ciclo sui triangoli della mesh 3MF
|
|
for ( Lib3MF_uint32 i = 0 ; i < pMesh->GetTriangleCount() ; i ++) {
|
|
// recupero gli indici dei vertici del triangolo
|
|
sTriangle tTrg = pMesh->GetTriangle( i) ;
|
|
int nIdV[3] = { int( tTrg.m_Indices[0]), int( tTrg.m_Indices[1]), int( tTrg.m_Indices[2])} ;
|
|
// 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) == SVT_NULL) {
|
|
LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : ISurfTriMesh AddTriangle error") ;
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Aggiustamenti finali
|
|
if ( ! pStm->DoCompacting()) {
|
|
LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : ISurfTriMesh DoCompacting error") ;
|
|
return false ;
|
|
}
|
|
|
|
// Inserimento nel DB geometrico
|
|
int nGeoId = m_pGDB->AddGeoObj( GDB_ID_NULL, nParentId, Release( pStm)) ;
|
|
if ( nGeoId == GDB_ID_NULL) {
|
|
LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : error adding GeoObject") ;
|
|
return false ;
|
|
}
|
|
|
|
// colore
|
|
Lib3MF_uint32 pid, pindex ;
|
|
if ( pMesh->GetObjectLevelProperty( pid, pindex)) {
|
|
Color cCol ;
|
|
if ( FindColor( pid, pindex, cCol))
|
|
m_pGDB->SetMaterial( nGeoId, cCol) ;
|
|
}
|
|
|
|
// attributes
|
|
if ( ! sName.empty())
|
|
m_pGDB->SetName( nGeoId, sName) ;
|
|
for ( int i = 0 ; i < int( vInfo.size()) ; i++)
|
|
m_pGDB->SetInfo( nGeoId, vInfo[i].first, vInfo[i].second) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
bool
|
|
Import3MF::ReadComponent( Lib3MF_uint32 nId, const string& sName, const INFOVECTOR& vInfo, const sTransform& Transform, int nParentId)
|
|
{
|
|
// se va conservata la gerarchia ogni componente corrisponde ad un layer, altrimenti gli elementi della componente vengono
|
|
// inseriti direttamente in m_nIdGroup e i suoi attributes vengono ignorati
|
|
|
|
PComponentsObject pComponents = m_model->GetComponentsObjectByID( nId) ;
|
|
if ( pComponents == nullptr)
|
|
return false ;
|
|
|
|
int nLayerId = nParentId ;
|
|
// se importo gerarchia creo il layer corrispondente alla componente
|
|
if ( ( m_nFlag & EI3FLAG_KEEP_GROUPS) != 0) {
|
|
nLayerId = m_pGDB->AddGroup( GDB_ID_NULL, nParentId, GLOB_FRM) ;
|
|
// assegno nome e info
|
|
if ( ! sName.empty())
|
|
m_pGDB->SetName( nLayerId, sName) ;
|
|
for ( int i = 0 ; i < int( vInfo.size()) ; i++)
|
|
m_pGDB->SetInfo( nLayerId, vInfo[i].first, vInfo[i].second) ;
|
|
}
|
|
|
|
// scorro tutti i suoi oggetti
|
|
for ( Lib3MF_uint32 nC = 0 ; nC < pComponents->GetComponentCount() ; nC++) {
|
|
|
|
PComponent pComponent = pComponents->GetComponent( nC) ;
|
|
|
|
// combino le trasformazioni
|
|
sTransform TransfComp = pComponent->GetTransform() ;
|
|
sTransform TransfRes ;
|
|
// inizializzo TransfRes a zero
|
|
for ( Lib3MF_uint32 i = 0 ; i < 4 ; i++)
|
|
fill( TransfRes.m_Fields[i], TransfRes.m_Fields[i] + 3, ( Lib3MF_single) 0.0) ;
|
|
|
|
for ( Lib3MF_uint32 i = 0 ; i < 4 ; i ++)
|
|
for ( Lib3MF_uint32 j = 0 ; j < 3 ; j++)
|
|
for ( Lib3MF_uint32 k = 0 ; k < 3 ; k ++)
|
|
TransfRes.m_Fields[i][j] += TransfComp.m_Fields[i][k] * Transform.m_Fields[k][j] ; // prodotto fra matrici
|
|
|
|
for ( Lib3MF_uint32 j = 0 ; j < 3 ; j ++)
|
|
TransfRes.m_Fields[3][j] += Transform.m_Fields[3][j] ;
|
|
|
|
if ( ! ReadObject( pComponent->GetObjectResource(), TransfRes, nLayerId))
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------
|
|
bool
|
|
Import3MF::FindColor( Lib3MF_uint32 pid, Lib3MF_uint32 pindex, Color& cCol) const
|
|
{
|
|
sColor sCol ;
|
|
|
|
switch ( m_model->GetPropertyTypeByID( pid)) {
|
|
case ePropertyType::BaseMaterial :
|
|
{
|
|
PBaseMaterialGroup pBaseMatGrp = m_model->GetBaseMaterialGroupByID( pid) ;
|
|
sCol = pBaseMatGrp->GetDisplayColor( pindex) ;
|
|
break ;
|
|
}
|
|
case ePropertyType::Colors :
|
|
{
|
|
PColorGroup pColorGrp = m_model->GetColorGroupByID( pid) ;
|
|
sCol = pColorGrp->GetColor( pindex) ;
|
|
break ;
|
|
}
|
|
case ePropertyType::Multi :
|
|
{
|
|
PMultiPropertyGroup pMultiPropGrp = m_model->GetMultiPropertyGroupByID( pid) ;
|
|
// multiproperty corrispondente a pindex
|
|
UINTVECTOR pindices ;
|
|
pMultiPropGrp->GetMultiProperty( pindex, pindices) ;
|
|
// analizzo i layers alla ricerca di una proprietà che definisca un colore
|
|
Lib3MF_uint32 nLayers = pMultiPropGrp->GetLayerCount() ;
|
|
for ( Lib3MF_uint32 i = 0 ; i < nLayers ; i ++) {
|
|
sMultiPropertyLayer layer = pMultiPropGrp->GetLayer( i) ;
|
|
Lib3MF_uint32 pidLayer = layer.m_ResourceID ;
|
|
// appena trovo una propietà che definisce un colore mi fermo
|
|
if ( m_model->GetPropertyTypeByID( pidLayer) == ePropertyType::BaseMaterial ||
|
|
m_model->GetPropertyTypeByID( pidLayer) == ePropertyType::Colors)
|
|
return FindColor( pidLayer, pindices[i], cCol) ;
|
|
}
|
|
return false ;
|
|
}
|
|
case ePropertyType::Composite :
|
|
{
|
|
PCompositeMaterials pCompoMat = m_model->GetCompositeMaterialsByID( pid) ;
|
|
// BaseMaterialGroup corrispondente
|
|
PBaseMaterialGroup pBaseMatGrp = pCompoMat->GetBaseMaterialGroup() ;
|
|
vector<sCompositeConstituent> vComposite ;
|
|
pCompoMat->GetComposite( pindex, vComposite) ;
|
|
|
|
// check sui valori in vComposite
|
|
double dMixSum = 0.0 ;
|
|
for( int i = 0 ; i < int( vComposite.size()) ; i ++)
|
|
dMixSum += vComposite[i].m_MixingRatio ;
|
|
// se fossero tutti zero, considero proporzioni uguali per ogni colore
|
|
if ( abs( dMixSum) < EPS_SMALL) {
|
|
dMixSum = vComposite.size() ;
|
|
for ( int i = 0 ; i < int( vComposite.size()) ; i++)
|
|
vComposite[i].m_MixingRatio = 1 ;
|
|
}
|
|
|
|
double dRed = 0.0, dGreen = 0.0, dBlue = 0.0, dAlpha = 0.0 ; // colore finale
|
|
Lib3MF_uint8 nRedTmp, nGreenTmp, nBlueTmp, nAlphaTmp ; // colore del BaseMaterial
|
|
// per ogni elemento di composite aggiungo il suo colore con l'opportuno coefficiente
|
|
for ( int i = 0 ; i < int( vComposite.size()) ; i++) {
|
|
sCol = pBaseMatGrp->GetDisplayColor( vComposite[i].m_PropertyID) ;
|
|
m_wrapper->ColorToRGBA( sCol, nRedTmp, nGreenTmp, nBlueTmp, nAlphaTmp) ;
|
|
double dMixingRatio = vComposite[i].m_MixingRatio / dMixSum ;
|
|
dRed += nRedTmp * dMixingRatio ;
|
|
dGreen += nGreenTmp * dMixingRatio ;
|
|
dBlue += nBlueTmp * dMixingRatio ;
|
|
dAlpha += nAlphaTmp * dMixingRatio ;
|
|
}
|
|
dAlpha = dAlpha * 100.0 / 255.0 ;
|
|
cCol.Set( int( dRed + 0.5), int( dGreen + 0.5), int( dBlue + 0.5), int( dAlpha + 0.5)) ;
|
|
return true ;
|
|
}
|
|
default :
|
|
return false ;
|
|
}
|
|
|
|
// converto il colore
|
|
Lib3MF_uint8 nRed, nGreen, nBlue, nAlpha ;
|
|
m_wrapper->ColorToRGBA( sCol, nRed, nGreen, nBlue, nAlpha) ;
|
|
nAlpha = Lib3MF_uint8( nAlpha * 100.0 / 255.0 + 0.5) ;
|
|
cCol.Set( nRed, nGreen, nBlue, nAlpha) ;
|
|
|
|
return true ;
|
|
}
|