//---------------------------------------------------------------------------- // 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/EGkStmFromTriangleSoup.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) { 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 ; 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 PWrapper m_wrapper = CWrapper::loadLibrary() ; if ( ! m_wrapper) { LOG_ERROR( GetEExLogger(), " Import3MF : Error on lib3mf Wrapper") ; return false ; } // creazione del 3MF model m_model = m_wrapper->CreateModel() ; if ( ! m_model) { LOG_ERROR( GetEExLogger(), " Import3MF : Error on lib3mf Model") ; return false ; } // lettura file PReader reader = m_model->QueryReader( "3mf") ; reader->ReadFromFile( sFile) ; for ( Lib3MF_uint32 iWarning = 0 ; iWarning < reader->GetWarningCount() ; iWarning ++) { Lib3MF_uint32 nErrorCode ; string sWarningMsg = reader->GetWarning( iWarning, nErrorCode) ; string sErrorMsg = " Reading 3MF file encountered warning # " + to_string( nErrorCode) + " : " + sWarningMsg ; } switch ( m_model->GetUnit()) { case eModelUnit::MicroMeter : m_nScaleFactor = 0.001 ; break ; case eModelUnit::MilliMeter : m_nScaleFactor = 1.0 ; break ; case eModelUnit::CentiMeter : m_nScaleFactor = 10.0 ; break ; case eModelUnit::Inch : m_nScaleFactor = 25.4 ; break ; case eModelUnit::Foot : m_nScaleFactor = 304.8 ; break ; case eModelUnit::Meter : m_nScaleFactor = 1000.0 ; break ; default: m_nScaleFactor = 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 sMetaDataValue = metaData->GetValue() ; string sMetaDataName = metaData->GetName() ; if ( ! sMetaDataValue.empty() && ! sMetaDataName.empty()) m_pGDB->SetInfo( m_nIdGroup, sMetaDataName, sMetaDataValue) ; } // scorro gli items nel build node PBuildItemIterator pBuildItemsIter = m_model->GetBuildItems() ; while ( pBuildItemsIter->MoveNext()) { if ( ! ReadItem( pBuildItemsIter->GetCurrent())) return false ; } return true ; } //---------------------------------------------------------------------------------------------------- bool Import3MF::ReadItem( const PBuildItem pItem) { if ( ! pItem) return false ; // trasformazione sTransform sTransf = pItem->GetObjectTransform() ; // attributes ATTRVECTOR vAttr ; string sProp = pItem->GetPartNumber() ; if ( ! sProp.empty()) vAttr.push_back( make_pair( "Item partnumber", pItem->GetPartNumber())) ; bool bUUID ; sProp = pItem->GetUUID( bUUID) ; if ( bUUID) vAttr.push_back( make_pair( "Item UUID", sProp)) ; // metadata PMetaDataGroup pMetaDataGrp = pItem->GetMetaDataGroup() ; if ( pMetaDataGrp) ReadMetaDataGroup( pMetaDataGrp, vAttr, Item) ; // lettura oggetto associato return ReadObject( pItem->GetObjectResource(), vAttr, sTransf) ; } //------------------------------------------------------------------------------------------------- bool Import3MF::ReadObject( const PObject pObj, ATTRVECTOR& vAttr, sTransform& sTransf) { if ( ! pObj) return false ; bool bMeshObj = pObj->IsMeshObject() ; // attributes string sProp = pObj->GetName() ; if ( ! sProp.empty()) vAttr.push_back( make_pair( "name", sProp)) ; sProp = pObj->GetPartNumber() ; if ( ! sProp.empty()) vAttr.push_back( make_pair( "partnumber", sProp)) ; bool bUUID = false ; sProp = pObj->GetUUID( bUUID) ; if ( bUUID) { string sPropName = bMeshObj ? "UUID" : "object UUID" ; vAttr.push_back( make_pair( sPropName, sProp)) ; } switch ( pObj->GetType()) { case eObjectType::Model : vAttr.push_back( make_pair( "type", "Model")) ; break ; case eObjectType::Support : vAttr.push_back( make_pair( "type", "Support")) ; break ; case eObjectType::SolidSupport : vAttr.push_back( make_pair( "type", "SolidSupport")) ; break ; default : break ; } // metadata PMetaDataGroup pMetaDataGrp = pObj->GetMetaDataGroup() ; if ( pMetaDataGrp) ReadMetaDataGroup( pMetaDataGrp, vAttr, bMeshObj ? Mesh : Component) ; if ( pObj->IsMeshObject()) return ReadMesh( pObj->GetResourceID(), vAttr, sTransf) ; else if ( pObj->IsComponentsObject()) return ReadComponents( pObj->GetResourceID(), vAttr, sTransf) ; return false ; } //---------------------------------------------------------------------------------------------------------------- bool Import3MF::ReadMesh( const Lib3MF_uint32& nId, ATTRVECTOR& vAttr, sTransform& sTransf) { // Recupero puntatore alla mesh 3MF PMeshObject pMesh = m_model->GetMeshObjectByID( nId) ; if ( pMesh.get() == nullptr) return false ; // Creo e inizializzo trimesh PtrOwner pStm( CreateSurfTriMesh()) ; if ( IsNull( pStm) || ! pStm->Init( 3, 1)) { 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] * sTransf.m_Fields[k][0] ; y += pVertex.m_Coordinates[k] * sTransf.m_Fields[k][1] ; z += pVertex.m_Coordinates[k] * sTransf.m_Fields[k][2] ; } x += sTransf.m_Fields[3][0] ; y += sTransf.m_Fields[3][1] ; z += sTransf.m_Fields[3][2] ; // inserisco il vertice nella trimesh if ( pStm->AddVertex( Point3d( x, y, z)) == 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, m_nIdGroup, 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 for ( size_t i = 0 ; i < vAttr.size() ; i++) { if ( vAttr[i].first == "name") m_pGDB->SetName( nGeoId, vAttr[i].second) ; else m_pGDB->SetInfo( nGeoId, vAttr[i].first, vAttr[i].second) ; } return true ; #if 0 PMeshObject pMesh = m_model->GetMeshObjectByID( nId) ; StmFromTriangleSoup Stm ; if ( ! Stm.Start()) { LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : StmFromTriangleSoup error") ; return false ; } // vertici vector vVertices( pMesh->GetVertexCount()) ; for ( Lib3MF_uint32 i = 0 ; i < pMesh->GetVertexCount() ; i ++) { sPosition pVertex = pMesh->GetVertex( i) ; // applico la trasformazione double x = 0.0, y = 0.0, z = 0.0 ; for ( Lib3MF_uint32 k = 0 ; k < 3 ; k ++) { x += pVertex.m_Coordinates[k] * sTransf.m_Fields[k][0] ; y += pVertex.m_Coordinates[k] * sTransf.m_Fields[k][1] ; z += pVertex.m_Coordinates[k] * sTransf.m_Fields[k][2] ; } x += sTransf.m_Fields[3][0] ; y += sTransf.m_Fields[3][1] ; z += sTransf.m_Fields[3][2] ; Point3d pt( x, y, z) ; vVertices[i] = pt * m_nScaleFactor ; } // triangoli for ( Lib3MF_uint32 i = 0 ; i < pMesh->GetTriangleCount() ; i ++) { sTriangle tTrg = pMesh->GetTriangle( i) ; if ( ! Stm.AddTriangle( vVertices[tTrg.m_Indices[0]], vVertices[tTrg.m_Indices[1]], vVertices[tTrg.m_Indices[2]])) { LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : StmFromTriangleSoup AddTriangle error") ; return false ; } } if ( ! Stm.End()) { LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : StmFromTriangleSoup error") ; return false ; } ISurfTriMesh* pSurf = Stm.GetSurf() ; if ( pSurf == nullptr) { LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : StmFromTriangleSoup GetSurf error") ; return false ; } int nGeoId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nIdGroup, pSurf) ; 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 for ( size_t i = 0 ; i < vAttr.size() ; i++) { if ( vAttr[i].first == "name") m_pGDB->SetName( nGeoId, vAttr[i].second) ; else m_pGDB->SetInfo( nGeoId, vAttr[i].first, vAttr[i].second) ; } return true ; #endif } //----------------------------------------------------------------------------------- bool Import3MF::ReadComponents( const Lib3MF_uint32& nId, ATTRVECTOR& attributes, sTransform& sTransfItem) { PComponentsObject pComponents = m_model->GetComponentsObjectByID( nId) ; // Scorro tutte le componenti for ( Lib3MF_uint32 iC = 0 ; iC < pComponents->GetComponentCount() ; iC ++ ) { PComponent pComponent = pComponents->GetComponent( iC) ; sTransform sTransfComp = pComponent->GetTransform() ; // combino le trasformazioni sTransform sTransfRes ; // inizializzo sTransfRes a zero for ( Lib3MF_uint32 i = 0 ; i < 4 ; i++) fill( sTransfRes.m_Fields[i], sTransfRes.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 ++) sTransfRes.m_Fields[i][j] += sTransfComp.m_Fields[i][k] * sTransfItem.m_Fields[k][j] ; // prodotto fra matrici for ( Lib3MF_uint32 j = 0 ; j < 3 ; j ++) sTransfRes.m_Fields[3][j] += sTransfItem.m_Fields[3][j] ; if ( ! ReadObject( pComponent->GetObjectResource(), attributes, sTransfRes)) return false ; } return true ; } //------------------------------------------------------------------------------------ bool Import3MF::FindColor( const Lib3MF_uint32& pid, const Lib3MF_uint32& pindex, Color& cCol) { 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( size_t i = 0 ; i < 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 ( size_t i = 0 ; i < 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 ( size_t i = 0 ; i < 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 ; } //---------------------------------------------------------------------------------------------------- bool Import3MF::ReadMetaDataGroup( const PMetaDataGroup pMetaDataGrp, ATTRVECTOR& vAttr, const MDGCaller& caller) { for ( Lib3MF_uint32 i = 0 ; i < pMetaDataGrp->GetMetaDataCount() ; i ++) { PMetaData metaData = pMetaDataGrp->GetMetaData( i) ; string sMetaDataValue = metaData->GetValue() ; if ( sMetaDataValue.empty()) continue ; string sMetaDataName ; switch ( caller) { case Item : sMetaDataName = "Item " ; break ; case Component : sMetaDataName = "Object " ; break ; case Mesh : sMetaDataName = "" ; } sMetaDataName += metaData->GetName() ; vAttr.push_back( make_pair( sMetaDataName, sMetaDataValue)) ; } return true ; }