//---------------------------------------------------------------------------- // 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 ( 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 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 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 ; }