Files
EgtExchange/Import3MF.cpp
T
DarioS cbd8863fc8 EgtExchange 2.3l2 :
- nell'import 3MF si utilizza direttamente l'indicizzazione dei vertici sui triangoli.
2021-12-23 20:06:56 +01:00

522 lines
18 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 "pugixml.hpp"
#include "/EgtDev/Include/EExDllMain.h"
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
#include "/EgtDev/Extern/libzip/Include/zip.h"
using namespace std ;
using namespace Lib3MF ;
//----------------------------------------------------------------------------
IImport3MF*
CreateImport3MF( void)
{
// verifico la chiave e le opzioni
if ( ! TestKeyForEEx( GetEExKey(), KEYOPT_EEX_INPBASE, GetEExLogger()))
return nullptr ;
// creo l'oggetto
return static_cast<IImport3MF*> ( 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<ISurfTriMesh> 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->AdjustTopology()) {
LOG_ERROR( GetEExLogger(), " Error reading 3MF mesh : ISurfTriMesh AdjustTopology 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<Point3d> 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<sCompositeConstituent> 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 ;
}