//---------------------------------------------------------------------------- // EgalTech 2015-2016 //---------------------------------------------------------------------------- // File : VolZmap.cpp Data : 22.01.15 Versione : 1.6a4 // Contenuto : Implementazione della classe Volume Zmap (tre griglie) // // // // Modifiche : 22.01.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "VolZmap.h" #include "GeoObjFactory.h" #include "GdbGeo.h" #include "NgeWriter.h" #include "NgeReader.h" #include "GeoConst.h" #include "/EgtDev/Include/EGkDistPointLine.h" #include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkUiUnits.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include #include #define DEBUG_REMOVE_FINS 0 #if DEBUG_REMOVE_FINS #include "/EgtDev/Include/EGkGeoObjSave.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkGeoVector3d.h" std::vector VT ; std::vector VC ; #endif using namespace std ; #if !defined(_WIN64) int VolZmap::m_nDexelNbr = 0 ; #endif //---------------------------------------------------------------------------- GEOOBJ_REGISTER( VOL_ZMAP, NGE_V_ZMP, VolZmap) ; //---------------------------------------------------------------------------- VolZmap::VolZmap(void) : m_nStatus( TO_VERIFY), m_nTempProp{0,0}, m_dTempParam{0.0,0.0}, m_bShowEdges( false), m_dStep( 10.0), m_nMapNum( 0), m_nShape( GENERIC), m_nVoxNumPerBlock( N_VOXBLOCK), m_nDexVoxRatio( 1), m_nNumBlock( 0), m_nConnectedCompoCount( 0), m_nCurrTool( -1), m_dToolLinTol( LIN_TOL_STD), m_dToolAngTolDeg( ANG_TOL_APPROX_DEG) { for ( int i = 0 ; i < N_MAPS ; ++ i) { m_nNx[i] = 0 ; m_nNy[i] = 0 ; m_nDim[i] = 0 ; m_dMinZ[i] = 0 ; m_dMaxZ[i] = 0 ; m_nFracLin[i] = 0 ; } m_vTool.resize( 1) ; } //---------------------------------------------------------------------------- VolZmap::~VolZmap( void) { // Se versione 32-bit aggiorno il numero di Dexel complessivi rimuovendo il numero dei correnti #if !defined(_WIN64) int nDexelNbr = 0 ; for ( int i = 0 ; i < ssize( m_nDim) ; ++ i) nDexelNbr += m_nDim[i] ; m_nDexelNbr = max( 0, m_nDexelNbr - nDexelNbr) ; #endif } //---------------------------------------------------------------------------- bool VolZmap::Clear( void) { m_nStatus = TO_VERIFY ; m_nTempProp[0] = 0 ; m_nTempProp[1] = 0 ; m_dTempParam[0] = 0.0 ; m_dTempParam[1] = 0.0 ; m_bShowEdges = false ; m_dStep = 10.0 ; m_nMapNum = 0 ; m_nShape = GENERIC ; m_nVoxNumPerBlock = N_VOXBLOCK ; m_nDexVoxRatio = 1 ; m_nNumBlock = 0 ; m_nConnectedCompoCount = 0 ; m_MapFrame.Reset() ; // Se versione 32-bit aggiorno il numero di Dexel complessivi rimuovendo il numero dei correnti #if !defined(_WIN64) int nDexelNbr = 0 ; for ( int i = 0 ; i < ssize( m_nDim) ; ++ i) nDexelNbr += m_nDim[i] ; m_nDexelNbr = max( 0, m_nDexelNbr - nDexelNbr) ; #endif for ( int i = 0 ; i < N_MAPS ; ++ i) { m_nNx[i] = 0 ; m_nNy[i] = 0 ; m_nDim[i] = 0 ; m_dMinZ[i] = 0 ; m_dMaxZ[i] = 0 ; m_Values[i].clear() ; } m_vTool.resize( 1) ; m_nCurrTool = 0 ; m_dToolLinTol = LIN_TOL_STD ; m_dToolAngTolDeg = ANG_TOL_APPROX_DEG ; // imposto ri-creazione della grafica m_OGrMgr.Clear() ; return true ; } //---------------------------------------------------------------------------- VolZmap* VolZmap::Clone( void) const { // alloco oggetto VolZmap* pVzm = new( nothrow) VolZmap ; if ( pVzm != nullptr) { if ( ! pVzm->CopyFrom( *this)) { delete pVzm ; return nullptr ; } } return pVzm ; } //---------------------------------------------------------------------------- bool VolZmap::CopyFrom( const IGeoObj* pGObjSrc) { const VolZmap* pVzm = GetBasicVolZmap( pGObjSrc) ; if ( pVzm == nullptr) return false ; return CopyFrom( *pVzm) ; } //---------------------------------------------------------------------------- bool VolZmap::CopyFrom( const VolZmap& vzmSrc) { if ( &vzmSrc == this) return true ; m_nMapNum = vzmSrc.m_nMapNum ; m_nShape = vzmSrc.m_nShape ; m_nNumBlock = vzmSrc.m_nNumBlock ; m_nVoxNumPerBlock = vzmSrc.m_nVoxNumPerBlock ; m_nFracLin[0] = vzmSrc.m_nFracLin[0] ; m_nFracLin[1] = vzmSrc.m_nFracLin[1] ; m_nFracLin[2] = vzmSrc.m_nFracLin[2] ; m_nDexVoxRatio = vzmSrc.m_nDexVoxRatio ; m_nConnectedCompoCount = vzmSrc.m_nConnectedCompoCount ; m_MapFrame = vzmSrc.m_MapFrame ; for ( int i = 0 ; i < int ( m_nMapNum) ; ++ i) { m_nNx[i] = vzmSrc.m_nNx[i] ; m_nNy[i] = vzmSrc.m_nNy[i] ; m_nDim[i] = vzmSrc.m_nDim[i] ; m_dMinZ[i] = vzmSrc.m_dMinZ[i] ; m_dMaxZ[i] = vzmSrc.m_dMaxZ[i] ; m_Values[i] = vzmSrc.m_Values[i] ; } m_dStep = vzmSrc.m_dStep ; m_nStatus = vzmSrc.m_nStatus ; m_nTempProp[0] = vzmSrc.m_nTempProp[0] ; m_nTempProp[1] = vzmSrc.m_nTempProp[1] ; m_dTempParam[0] = vzmSrc.m_dTempParam[0] ; m_dTempParam[1] = vzmSrc.m_dTempParam[1] ; m_bShowEdges = vzmSrc.m_bShowEdges ; // dimensiono membri legati ai blocchi m_BlockToUpdate = vzmSrc.m_BlockToUpdate ; m_BlockUpdatingCounter = vzmSrc.m_BlockUpdatingCounter ; m_InterBlockVox = vzmSrc.m_InterBlockVox ; m_InterBlockOriginalSharpTria = vzmSrc.m_InterBlockOriginalSharpTria ; m_InterBlockSharpTria = vzmSrc.m_InterBlockSharpTria ; m_BlockSharpTria = vzmSrc.m_BlockSharpTria ; m_BlockSmoothTria = vzmSrc.m_BlockSmoothTria ; m_BlockBigTria = vzmSrc.m_BlockBigTria ; m_SingleMapTria = vzmSrc.m_SingleMapTria ; m_SliceXY = vzmSrc.m_SliceXY ; m_SliceXZ = vzmSrc.m_SliceXZ ; m_SliceYZ = vzmSrc.m_SliceYZ ; // imposto ricalcolo grafica ResetGraphics() ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::ResetGraphics( void) { m_OGrMgr.Clear() ; for ( int nCount = 0 ; nCount < m_nNumBlock ; ++ nCount) m_BlockToUpdate[nCount] = true ; return true ; } //---------------------------------------------------------------------------- GeoObjType VolZmap::GetType( void) const { return static_cast( GEOOBJ_GETTYPE( VolZmap)) ; } //---------------------------------------------------------------------------- const string& VolZmap::GetTitle( void) const { static const string sTitle = "VolZm" ; return sTitle ; } //---------------------------------------------------------------------------- bool VolZmap::Dump( string& sOut, bool bMM, const char* szNewLine) const { // tipo sOut += "Type=" + string( m_nMapNum == 1 ? "dexel" : "tridexel") + szNewLine ; // visualizzazione spigoli sOut += "ShowEdges=" + ToString( GetShowEdges()) + szNewLine ; // dexel per voxel (DexToVoxRatio) sOut += "DexVoxRat=" + ToString( m_nDexVoxRatio) + szNewLine ; // forma switch ( m_nShape) { default : sOut += "Shape=generic" ; break ; case BOX : sOut += "Shape=box" ; break ; case EXTRUSION : sOut += "Shape=extrusion" ; break ; } sOut += szNewLine ; // passo sOut += "Step=" + ToString( GetInUiUnits( m_dStep, bMM), 6) + szNewLine ; // dimensioni if ( m_nMapNum == 1) sOut += "Dim=" + ToString( m_nDim[0]) + "(" + ToString( m_nNx[0]) + "x" + ToString( m_nNy[0]) + ")" + szNewLine ; else { for ( int i = 0 ; i < m_nMapNum ; ++ i) sOut += "Dim" + ToString( i+1) + "=" + ToString( m_nDim[i]) + "(" + ToString( m_nNx[i]) + "x" + ToString( m_nNy[i]) + ")" + szNewLine ; } // numero di blocchi sOut += "Blocks=" + ToString( m_nNumBlock) + " (" + ToString( m_nFracLin[0]) + "x" + ToString( m_nFracLin[1]) + "x" + ToString( m_nFracLin[2]) + ")" + szNewLine ; return true ; } //---------------------------------------------------------------------------- int VolZmap::GetNgeId( void) const { return GEOOBJ_GETNGEID( VolZmap) ; } //---------------------------------------------------------------------------- bool VolZmap::Save( NgeWriter& ngeOut) const { // numero di mappe if ( ! ngeOut.WriteInt( m_nMapNum, ",", false)) return false ; // numero di blocchi if ( ! ngeOut.WriteInt( m_nNumBlock, ",", false)) return false ; // numero di voxel per blocco if ( ! ngeOut.WriteInt( m_nVoxNumPerBlock, ",", false)) return false ; // numero di blocchi per ogni asse for ( int i = 0 ; i < 3 ; ++ i) { if ( ! ngeOut.WriteInt( m_nFracLin[i], ",", false)) return false ; } // DexVoxRatio if ( ! ngeOut.WriteInt( m_nDexVoxRatio, ",", false)) return false ; // numero di componenti connesse if ( ! ngeOut.WriteInt( m_nConnectedCompoCount, ",", false)) return false ; // passo di campionamento (distanza tra spilloni) if ( ! ngeOut.WriteDouble( m_dStep, ";", true)) return false ; // forma if ( ! ngeOut.WriteInt( m_nShape, ";", true)) return false ; // sistema di riferimento if ( ! ngeOut.WriteFrame( m_MapFrame, ";", true)) return false ; // per ogni mappa : numero di passi in X e Y e quote Z estremali for ( int i = 0 ; i < m_nMapNum ; ++ i) { if ( ! ngeOut.WriteInt( m_nNx[i], ",", false)) return false ; if ( ! ngeOut.WriteInt( m_nNy[i], ",", false)) return false ; if ( ! ngeOut.WriteDouble( m_dMinZ[i], ",", false)) return false ; if ( ! ngeOut.WriteDouble( m_dMaxZ[i], ";", true)) return false ; } // ciclo sulle mappe for ( int i = 0 ; i < m_nMapNum ; ++ i) { // ciclo sui dexel for ( int j = 0 ; j < m_nDim[i] ; ++ j) { // numero di estremi int nDim = int( m_Values[i][j].size()) ; if ( ! ngeOut.WriteInt( nDim, ":", false)) return false ; // se dexel nullo if ( nDim == 0) { // scrivo un valore dummy if ( ! ngeOut.WriteDouble( 0, ";", true)) return false ; } // altrimenti else { for ( int k = 0 ; k < nDim ; ++ k) { if ( ! ngeOut.WriteDouble( m_Values[i][j][k].dMin, ",", false)) return false ; if ( ! ngeOut.WriteInt( m_Values[i][j][k].nToolMin, ";", false)) return false ; if ( ! ngeOut.WriteVector( m_Values[i][j][k].vtMinN, ";", false)) return false ; if ( ! ngeOut.WriteDouble( m_Values[i][j][k].dMax, ",", false)) return false ; if ( ! ngeOut.WriteInt( m_Values[i][j][k].nToolMax, ";", false)) return false ; if ( ! ngeOut.WriteVector( m_Values[i][j][k].vtMaxN, ";", false)) return false ; if ( ! ngeOut.WriteInt( m_Values[i][j][k].nCompo, ";", true)) return false ; } } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::PreSave( GdbGeo& Wrapper) const { // salvo il flag di visualizzazione spigoli vivi anche in shading (default false) if ( m_bShowEdges) Wrapper.SetInfo( GDB_SI_SHOWEDGES, true) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::PostSave( GdbGeo& Wrapper) const { // elimino eventuali info aggiunte nella PreSave Wrapper.RemoveInfo( GDB_SI_SHOWEDGES) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::Load( NgeReader& ngeIn) { Clear() ; // numero di mappe if ( ! ngeIn.ReadInt( m_nMapNum, ",", false)) return false ; // numero di blocchi if ( ! ngeIn.ReadInt( m_nNumBlock, ",", false)) return false ; // numero di voxel per blocco if ( ! ngeIn.ReadInt( m_nVoxNumPerBlock, ",", false)) return false ; // numero di blocchi per ogni asse for ( int i = 0 ; i < 3 ; ++ i) { if ( ! ngeIn.ReadInt( m_nFracLin[i], ",", false)) return false ; } // da versione 1018 : aggiunto DexVoxRatio if ( ngeIn.GetFileVersion() >= NGE_VER_1018) { if ( ! ngeIn.ReadInt( m_nDexVoxRatio, ",", false)) return false ; } // numero di componenti connesse if ( ! ngeIn.ReadInt( m_nConnectedCompoCount, ",", false)) return false ; // passo di campionamento (distanza tra spilloni) if ( ! ngeIn.ReadDouble( m_dStep, ";", true)) return false ; // da versione 1014 : aggiunto flag Shape if ( ngeIn.GetFileVersion() >= NGE_VER_1014) { if ( ! ngeIn.ReadInt( m_nShape, ";", true)) return false ; } // sistema di riferimento if ( ! ngeIn.ReadFrame( m_MapFrame, ";", true)) return false ; // per ogni mappa : numero di passi in X e Y e quote Z estremali for ( int i = 0 ; i < m_nMapNum ; ++ i) { if ( ! ngeIn.ReadInt( m_nNx[i], ",", false)) return false ; if ( ! ngeIn.ReadInt( m_nNy[i], ",", false)) return false ; m_nDim[i] = m_nNx[i] * m_nNy[i] ; if ( ! ngeIn.ReadDouble( m_dMinZ[i], ",", false)) return false ; if ( ! ngeIn.ReadDouble( m_dMaxZ[i], ";", true)) return false ; } // ciclo sulle mappe for ( int i = 0 ; i < m_nMapNum ; ++ i) { // dimensiono i vettori m_Values[i].resize( m_nDim[i]) ; // ciclo sui dexel for ( int j = 0 ; j < m_nDim[i] ; ++ j) { // leggo il numero di estremi nel dexel int nDim ; if ( ! ngeIn.ReadInt( nDim, ":", false)) return false ; // se dexel nullo if ( nDim == 0) { // leggo un valore dummy double dDummy ; if ( ! ngeIn.ReadDouble( dDummy, ";", true)) return false ; } // altrimenti else { // dimensiono l'array m_Values[i][j].resize( nDim) ; // leggo i valori for ( int k = 0 ; k < nDim ; ++ k) { if ( ! ngeIn.ReadDouble( m_Values[i][j][k].dMin, ",", false)) return false ; if ( ! ngeIn.ReadInt( m_Values[i][j][k].nToolMin, ";", false)) return false ; if ( ! ngeIn.ReadVector( m_Values[i][j][k].vtMinN, ";", false)) return false ; if ( ! ngeIn.ReadDouble( m_Values[i][j][k].dMax, ",", false)) return false ; if ( ! ngeIn.ReadInt( m_Values[i][j][k].nToolMax, ";", false)) return false ; if ( ! ngeIn.ReadVector( m_Values[i][j][k].vtMaxN, ";", false)) return false ; if ( ! ngeIn.ReadInt( m_Values[i][j][k].nCompo, ";", true)) return false ; } } } } // imposto aggiornamento obbligatorio su tutti i blocchi m_BlockToUpdate.resize( m_nNumBlock, true) ; m_BlockUpdatingCounter.resize( m_nNumBlock + ( m_nMapNum == 1 ? 0 : 1), 0) ; // per triangoli di feature di frontiera tra blocchi m_InterBlockVox.resize( m_nNumBlock) ; m_InterBlockOriginalSharpTria.resize( m_nNumBlock) ; m_InterBlockSharpTria.resize( m_nNumBlock) ; m_BlockSharpTria.resize( m_nNumBlock) ; m_BlockSmoothTria.resize( m_nNumBlock) ; m_BlockBigTria.resize( m_nNumBlock) ; m_SingleMapTria.resize( m_nNumBlock) ; m_SliceXY.resize( m_nNumBlock) ; m_SliceXZ.resize( m_nNumBlock) ; m_SliceYZ.resize( m_nNumBlock) ; m_nStatus = OK ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::PostLoad( GdbGeo& Wrapper) { // recupero eventuale flag di visualizzazione spigoli vivi anche in shading bool bVal ; if ( Wrapper.GetInfo( GDB_SI_SHOWEDGES, bVal)) { m_bShowEdges = bVal ; Wrapper.RemoveInfo( GDB_SI_SHOWEDGES) ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetLocalBBox( BBox3d& b3Loc, int nFlag) const { // verifico lo stato if ( m_nStatus != OK) return false ; // reset box b3Loc.Reset() ; // se richiesto approssimato if ( ( nFlag & BBF_EXACT) == 0) { b3Loc.Add( ORIG) ; b3Loc.Add( Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ; b3Loc.ToGlob( m_MapFrame) ; return true ; } // calcolo preciso // ciclo sui dexel (punti in basso con ciclo aggiunto per punti in alto di ultima riga) double dY = 0 ; for ( int j = 0 ; j <= m_nNy[0] ; ++ j) { int jc = ( ( j != m_nNy[0]) ? j : m_nNy[0] - 1) ; double dX = 0 ; // punto a sinistra di ogni dexel (aggiungo un ciclo per fare punto a destra di ultimo) for ( int i = 0 ; i <= m_nNx[0] ; ++ i) { int ic = ( ( i != m_nNx[0]) ? i : m_nNx[0] - 1) ; int nPos = ic + jc * m_nNx[0] ; if ( ! m_Values[0][nPos].empty()) { Point3d ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersX() + dY * m_MapFrame.VersY() ; b3Loc.Add( ptP + m_Values[0][nPos][0].dMin * m_MapFrame.VersZ()) ; b3Loc.Add( ptP + m_Values[0][nPos][m_Values[0][nPos].size()-1].dMax * m_MapFrame.VersZ()) ; } // passo al punto successivo dX += m_dStep ; if ( m_nMapNum == N_MAPS) dX = min( dX, m_dMaxZ[1]) ; } // passo alla riga successiva dY += m_dStep ; if ( m_nMapNum == N_MAPS) dY = min( dY, m_dMaxZ[2]) ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const { // verifico lo stato if ( m_nStatus != OK) return false ; // reset box b3Ref.Reset() ; // trasformo il riferimento locale tramite quello passato Frame3d frUse = m_MapFrame ; frUse.ToGlob( frRef) ; // se richiesto approssimato if ( ( nFlag & BBF_EXACT) == 0) { b3Ref.Add( ORIG) ; b3Ref.Add( Point3d( m_nNx[0] * m_dStep, m_nNy[0] * m_dStep, m_dMaxZ[0])) ; b3Ref.ToGlob( frUse) ; return true ; } // calcolo preciso // ciclo sui dexel (punti in basso con ciclo aggiunto per punti in alto di ultima riga) double dY = 0 ; for ( int j = 0 ; j <= m_nNy[0] ; ++ j) { int jc = ( ( j != m_nNy[0]) ? j : m_nNy[0] - 1) ; double dX = 0 ; // punto a sinistra di ogni dexel (aggiungo un ciclo per fare punto a destra di ultimo) for ( int i = 0 ; i <= m_nNx[0] ; ++ i) { int ic = ( ( i != m_nNx[0]) ? i : m_nNx[0] - 1) ; int nPos = ic + jc * m_nNx[0] ; if ( nPos >= 0 && ! m_Values[0][nPos].empty()) { Point3d ptP = frUse.Orig() + dX * frUse.VersX() + dY * frUse.VersY() ; b3Ref.Add( ptP + m_Values[0][nPos][0].dMin * frUse.VersZ()) ; b3Ref.Add( ptP + m_Values[0][nPos][m_Values[0][nPos].size()-1].dMax * frUse.VersZ()) ; } // passo al punto successivo dX += m_dStep ; if ( m_nMapNum == N_MAPS) dX = min( dX, m_dMaxZ[1]) ; } // passo alla riga successiva dY += m_dStep ; if ( m_nMapNum == N_MAPS) dY = min( dY, m_dMaxZ[2]) ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetPartLocalBBox( int nPart, BBox3d& b3Loc, int nFlag) const { // Verifico lo stato. if ( m_nStatus != OK) return false ; // Se una sola mappa o il numero di componenti è indefinito, vi è un errore. if ( m_nMapNum == 1 || m_nConnectedCompoCount == - 1) return false ; // Se la componente richiesta non esiste, vi è un errore. if ( nPart < 0 || nPart > m_nConnectedCompoCount - 1) return false ; // Calcolo Bounding-box for ( int nMap = 0 ; nMap < 3 ; ++ nMap) { for ( int nDex = 0 ; nDex < m_nDim[nMap] ; ++ nDex) { for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) { if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) { // Indici del dexel int nI = nDex % m_nNx[nMap] ; int nJ = nDex / m_nNx[nMap] ; // Posizione del dexel double dX = ( nI + 0.5) * m_dStep ; double dY = ( nJ + 0.5) * m_dStep ; // Definisco i punti nel sistema locale Point3d ptP, ptPSt, ptPEn ; if ( nMap == 0) { ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersX() + dY * m_MapFrame.VersY() ; ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * m_MapFrame.VersZ() ; ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * m_MapFrame.VersZ() ; } else if ( nMap == 1) { ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersY() + dY * m_MapFrame.VersZ() ; ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * m_MapFrame.VersX() ; ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * m_MapFrame.VersX() ; } else { ptP = m_MapFrame.Orig() + dX * m_MapFrame.VersZ() + dY * m_MapFrame.VersX() ; ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * m_MapFrame.VersY() ; ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * m_MapFrame.VersY() ; } // Aggiungo i punti al bounding-box b3Loc.Add( ptPSt) ; b3Loc.Add( ptPEn) ; } } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetPartBBox( int nPart, const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const { // Verifico lo stato. if ( m_nStatus != OK) return false ; // Se una sola mappa o il numero di componenti è indefinito, vi è un errore. if ( m_nMapNum == 1 || m_nConnectedCompoCount == - 1) return false ; // Se la componente richiesta non esiste, vi è un errore. if ( nPart < 0 || nPart > m_nConnectedCompoCount - 1) return false ; // Calcolo Bounding-box Point3d ptMapFrameOrig = m_MapFrame.Orig() ; Vector3d vtMapFrameVersX = m_MapFrame.VersX() ; Vector3d vtMapFrameVersY = m_MapFrame.VersY() ; Vector3d vtMapFrameVersZ = m_MapFrame.VersZ() ; ptMapFrameOrig.ToGlob( frRef) ; vtMapFrameVersX.ToGlob( frRef) ; vtMapFrameVersY.ToGlob( frRef) ; vtMapFrameVersZ.ToGlob( frRef) ; for ( int nMap = 0 ; nMap < 3 ; ++ nMap) { for ( int nDex = 0 ; nDex < m_nDim[nMap] ; ++ nDex) { for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) { if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) { // Indici del dexel int nI = nDex % m_nNx[nMap] ; int nJ = nDex / m_nNx[nMap] ; // Posizione del dexel double dX = ( nI + 0.5) * m_dStep ; double dY = ( nJ + 0.5) * m_dStep ; // Definisco i punti nel sistema locale Point3d ptP, ptPSt, ptPEn ; if ( nMap == 0) { ptP = ptMapFrameOrig + dX * vtMapFrameVersX + dY * vtMapFrameVersY ; ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * vtMapFrameVersZ ; ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * vtMapFrameVersZ ; } else if ( nMap == 1) { ptP = ptMapFrameOrig + dX * vtMapFrameVersY + dY * vtMapFrameVersZ ; ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * vtMapFrameVersX ; ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * vtMapFrameVersX ; } else { ptP = ptMapFrameOrig + dX * vtMapFrameVersZ + dY * vtMapFrameVersX ; ptPSt = ptP + m_Values[nMap][nDex][nInt].dMin * vtMapFrameVersY ; ptPEn = ptP + m_Values[nMap][nDex][nInt].dMax * vtMapFrameVersY ; } // Aggiungo i punti al bounding-box b3Ref.Add( ptPSt) ; b3Ref.Add( ptPEn) ; } } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::Translate( const Vector3d& vtMove) { // verifico lo stato if ( m_nStatus != OK) return false ; // imposto ricalcolo della grafica ResetGraphics() ; // traslo il riferimento m_MapFrame.Translate( vtMove) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng) { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validità dell'asse di rotazione if ( vtAx.IsSmall()) return false ; // imposto ricalcolo della grafica ResetGraphics() ; // ruoto il riferimento m_MapFrame.Rotate( ptAx, vtAx, dCosAng, dSinAng) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ) { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico non sia nulla if ( abs( dCoeffX) < EPS_ZERO && abs( dCoeffY) < EPS_ZERO && abs( dCoeffZ) < EPS_ZERO) return false ; return false ; } //---------------------------------------------------------------------------- bool VolZmap::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validità del piano di specchiatura if ( vtNorm.IsSmall()) return false ; return false ; } //---------------------------------------------------------------------------- bool VolZmap::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff) { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validità dei parametri if ( vtNorm.IsSmall() || vtDir.IsSmall()) return false ; return false ; } //---------------------------------------------------------------------------- bool VolZmap::ToGlob( const Frame3d& frRef) { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // se frame identità, non devo fare alcunché if ( IsGlobFrame( frRef)) return true ; // imposto ricalcolo della grafica ResetGraphics() ; // trasformo il riferimento m_MapFrame.ToGlob( frRef) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::ToLoc( const Frame3d& frRef) { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // se frame identità, non devo fare alcunché if ( IsGlobFrame( frRef)) return true ; // imposto ricalcolo della grafica ResetGraphics() ; // trasformo il riferimento m_MapFrame.ToLoc( frRef) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validità dei frame if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR) return false ; // se i due riferimenti coincidono, non devo fare alcunché if ( AreSameFrame( frOri, frDest)) return true ; // imposto ricalcolo della grafica ResetGraphics() ; // trasformo il riferimento m_MapFrame.LocToLoc( frOri, frDest) ; return true ; } //---------------------------------------------------------------------------- int VolZmap::GetPartCount( void) const { // Se mono-dexel la connessione è incalcolabile. if ( m_nMapNum == 1) return - 1 ; // Se il numero delle componenti è indefinito // lo ricalcolo e restituisco il risultato. if ( m_nConnectedCompoCount == - 1) { const_cast(this)->CheckMapConnection() ; return m_nConnectedCompoCount ; } // Altrimenti restituisco direttamente il numero di componenti. else return m_nConnectedCompoCount ; } //---------------------------------------------------------------------------- bool VolZmap::CheckMapConnection( void) { // Imposto il numero di componenti connesse a 0 m_nConnectedCompoCount = 0 ; // Imposto a 0 tutti il valore del numero della componente // connessa di ciascun tratto di ciascun dexel. for ( int tMap = 0 ; tMap < m_nMapNum ; ++ tMap) { for ( int tDex = 0 ; tDex < m_nDim[tMap] ; ++ tDex) { for ( int tInt = 0 ; tInt < int( m_Values[tMap][tDex].size()) ; ++ tInt) { m_Values[tMap][tDex][tInt].nCompo = 0 ; } } } // Numero massimo di thread int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ; // Ciclo sui dexel lungo Z for ( int tI = 0 ; tI < m_nNx[0] ; ++ tI) { for ( int tJ = 0 ; tJ < m_nNy[0] ; ++ tJ) { // Numero del dexel lungo Z int tDexZ = tJ * m_nNx[0] + tI ; // Numero di intervalli nel dexel int tStopIntZ = int( m_Values[0][tDexZ].size()) ; // Ciclo sugli intervalli del dexel for ( int tIntZ = 0 ; tIntZ < tStopIntZ ; ++ tIntZ) { if ( m_Values[0][tDexZ][tIntZ].nCompo == 0) { ++ m_nConnectedCompoCount ; m_Values[0][tDexZ][tIntZ].nCompo = m_nConnectedCompoCount ; // Espando in tutta la componente // Segmento corrente IntervalIndexes NewInt ; NewInt.tMap = 0 ; NewInt.tDex = tJ * m_nNx[0] + tI ; NewInt.tInt = tIntZ ; // Vettore di stack di segmenti IntContainerVec IntervalsToProcessStackVec ; IntervalsToProcessStackVec.resize( nThreadMax) ; // Mi espando dal primo intervallo mettendo gli intervalli che intersecano nei vari thread FirstExpansionFromZ( nThreadMax, NewInt, IntervalsToProcessStackVec) ; // Lancio in parallelo più ricerche int nActiveThread = 0 ; vector> vRes ; vRes.resize( nThreadMax) ; for ( int i = 0 ; i < nThreadMax ; ++ i) { if ( ! IntervalsToProcessStackVec[i].empty()) { ++ nActiveThread ; vRes[i] = async( launch::async, &VolZmap::ProcessIntervals, this, ref( IntervalsToProcessStackVec[i])) ; } } // Attendo che tutti i porcessi terminino int nTerminated = 0 ; while ( nTerminated < nActiveThread) { for ( int i = 0 ; i < nThreadMax ; ++ i) { if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) { vRes[i].get() ; ++ nTerminated ; } } } } // Se l'intervallo non attraversa un nodo o ha già // un indice assegnato salto questa iterazione. else continue ; } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::ExpandFromXInterval( IntContainer& IntCont) { // Copio i dati dell'intervallo corrente IntervalIndexes CurrInterval = IntCont.top() ; IntCont.pop() ; int tDex = CurrInterval.tDex ; int tGrIndex1 = CurrInterval.tDex % m_nNx[1] ; int tGrIndex2 = CurrInterval.tDex / m_nNx[1] ; int tInt = CurrInterval.tInt ; // Quote estreme del segmento lungo X double dMinX = m_Values[1][tDex][tInt].dMin ; double dMaxX = m_Values[1][tDex][tInt].dMax ; double dMinDX = max( floor( ( dMinX - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; double dMaxDX = max( floor( ( dMaxX + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; // Indici estremi dei dei dexel ortogonali // che possono intersecare il segmento di partenza int tStartI = min( int( dMinDX), ( m_nNx[0] - 1)) ; int tStopI = min( int( dMaxDX), ( m_nNx[0] - 1)) ; // Posizione YZ del dexel double dY = ( tGrIndex1 + 0.5) * m_dStep ; double dZ = ( tGrIndex2 + 0.5) * m_dStep ; // Ciclo sugli indici dei dexel che potrebbero // intersecare il segmento di partenza for ( int tI = tStartI ; tI <= tStopI ; ++ tI) { // Analizzo i dexel della griglia 0. int tStopZ = int( m_Values[0][tGrIndex1 * m_nNx[0] + tI].size()) ; for ( int tIntZ = 0 ; tIntZ < tStopZ ; ++ tIntZ) { // Estremi del dexel lunog Z double dZmin = m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].dMin ; double dZmax = m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dZmin - 2 * EPS_SMALL < dZ && dZmax + 2 * EPS_SMALL > dZ && m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].nCompo == 0) { m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].nCompo = m_Values[1][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 0 ; NewInterval.tDex = tGrIndex1 * m_nNx[0] + tI ; NewInterval.tInt = tIntZ ; IntCont.push( NewInterval) ; } } // Analizzo i dexel della griglia 2 int tStopY = int( m_Values[2][tI * m_nNx[2] + tGrIndex2].size()) ; for ( int tIntY = 0 ; tIntY < tStopY ; ++ tIntY) { // Estremi del segmento del dexel lungo Y double dYmin = m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].dMin ; double dYmax = m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dYmin - 2 * EPS_SMALL < dY && dYmax + 2 * EPS_SMALL > dY && m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].nCompo == 0) { m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].nCompo = m_Values[1][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 2 ; NewInterval.tDex = tI * m_nNx[2] + tGrIndex2 ; NewInterval.tInt = tIntY ; IntCont.push( NewInterval) ; } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::ExpandFromYInterval( IntContainer& IntCont) { // Copio i dati dell'intervallo corrente IntervalIndexes CurrInterval = IntCont.top() ; IntCont.pop() ; int tDex = CurrInterval.tDex ; int tGrIndex1 = CurrInterval.tDex % m_nNx[2] ; int tGrIndex2 = CurrInterval.tDex / m_nNx[2] ; int tInt = CurrInterval.tInt ; // Quote estreme del segmento lungo Y double dMinY = m_Values[2][tDex][tInt].dMin ; double dMaxY = m_Values[2][tDex][tInt].dMax ; double dMinDY = max( floor( ( dMinY - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; double dMaxDY = max( floor( ( dMaxY + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; // Indici estremi dei dei dexel ortogonali // che possono intersecare il segmento di partenza int tStartJ = min( int( dMinDY), ( m_nNy[0] - 1)) ; int tStopJ = min( int( dMaxDY), ( m_nNy[0] - 1)) ; // Posizione XZ del dexel double dX = ( tGrIndex2 + 0.5) * m_dStep ; double dZ = ( tGrIndex1 + 0.5) * m_dStep ; // Ciclo sugli indici dei dexel che potrebbero // intersecare il segmento di partenza for ( int tJ = tStartJ ; tJ <= tStopJ ; ++ tJ) { // Analizzo i dexel della griglia 0. int tStopZ = int( m_Values[0][tJ * m_nNx[0] + tGrIndex2].size()) ; for ( int tIntZ = 0 ; tIntZ < tStopZ ; ++ tIntZ) { // Estremi del dexel lunog Z double dZmin = m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].dMin ; double dZmax = m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dZmin - 2 * EPS_SMALL < dZ && dZmax + 2 * EPS_SMALL > dZ && m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].nCompo == 0) { m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].nCompo = m_Values[2][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 0 ; NewInterval.tDex = tJ * m_nNx[0] + tGrIndex2 ; NewInterval.tInt = tIntZ ; IntCont.push( NewInterval) ; } } // Analizzo i dexel della griglia 1 int tStopX = int( m_Values[1][tGrIndex1 * m_nNx[1] + tJ].size()) ; for ( int tIntX = 0 ; tIntX < tStopX ; ++ tIntX) { // Estremi del segmento del dexel lungo X double dXmin = m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].dMin ; double dXmax = m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dXmin - 2 * EPS_SMALL < dX && dXmax + 2 * EPS_SMALL > dX && m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].nCompo == 0) { m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].nCompo = m_Values[2][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 1 ; NewInterval.tDex = tGrIndex1 * m_nNx[1] + tJ ; NewInterval.tInt = tIntX ; IntCont.push( NewInterval) ; } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::ExpandFromZInterval( IntContainer& IntCont) { // Copio i dati dell'intervallo corrente IntervalIndexes CurrInterval = IntCont.top() ; IntCont.pop() ; int tDex = CurrInterval.tDex ; int tGrIndex1 = CurrInterval.tDex % m_nNx[0] ; int tGrIndex2 = CurrInterval.tDex / m_nNx[0] ; int tInt = CurrInterval.tInt ; // Quote estreme del segmento lungo Z double dMinZ = m_Values[0][tDex][tInt].dMin ; double dMaxZ = m_Values[0][tDex][tInt].dMax ; double dMinDZ = max( floor( ( dMinZ - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; double dMaxDZ = max( floor( ( dMaxZ + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; // Indici estremi dei dexel ortogonali // che possono intersecare il segmento di partenza int tStartK = min( int( dMinDZ), ( m_nNy[1] - 1)) ; int tStopK = min( int( dMaxDZ), ( m_nNy[1] - 1)) ; // Posizione XY del dexel double dX = ( tGrIndex1 + 0.5) * m_dStep ; double dY = ( tGrIndex2 + 0.5) * m_dStep ; // Ciclo sugli indici dei dexel che potrebbero // intersecare il segmento di partenza for ( int tK = tStartK ; tK <= tStopK ; ++ tK) { // Analizzo i dexel della griglia 1. int tStopX = int( m_Values[1][tK * m_nNx[1] + tGrIndex2].size()) ; for ( int tIntX = 0 ; tIntX < tStopX ; ++ tIntX) { // Estremi del segmento del dexel lungo X double dXmin = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMin ; double dXmax = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dXmin - 2 * EPS_SMALL < dX && dXmax + 2 * EPS_SMALL > dX && m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo == 0) { m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo = m_Values[0][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 1 ; NewInterval.tDex = tK * m_nNx[1] + tGrIndex2 ; NewInterval.tInt = tIntX ; IntCont.push( NewInterval) ; } } // Analizzo i dexel della griglia 2 int tStopY = int( m_Values[2][tGrIndex1 * m_nNx[2] + tK].size()) ; for ( int tIntY = 0 ; tIntY < tStopY ; ++ tIntY) { // Estremi del segmento del dexel lungo Y double dYmin = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMin ; double dYmax = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dYmin - 2 * EPS_SMALL < dY && dYmax + 2 * EPS_SMALL > dY && m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo == 0) { m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo = m_Values[0][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 2 ; NewInterval.tDex = tGrIndex1 * m_nNx[2] + tK ; NewInterval.tInt = tIntY ; IntCont.push( NewInterval) ; } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::FirstExpansionFromZ( int nNumThread, IntervalIndexes IntSt, IntContainerVec& IntervalsToProcessStackVec) { int tDex = IntSt.tDex ; int tGrIndex1 = IntSt.tDex % m_nNx[0] ; int tGrIndex2 = IntSt.tDex / m_nNx[0] ; int tInt = IntSt.tInt ; // Quote estreme del segmento lungo Z double dMinZ = m_Values[0][tDex][tInt].dMin ; double dMaxZ = m_Values[0][tDex][tInt].dMax ; double dMinDZ = max( floor( ( dMinZ - 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; double dMaxDZ = max( floor( ( dMaxZ + 2 * EPS_SMALL) / m_dStep - 0.5), 0.) ; // Indici estremi dei dexel ortogonali // che possono intersecare il segmento di partenza int tStartK = min( int( dMinDZ), ( m_nNy[1] - 1)) ; int tStopK = min( int( dMaxDZ), ( m_nNy[1] - 1)) ; // Posizione XY del dexel double dX = ( tGrIndex1 + 0.5) * m_dStep ; double dY = ( tGrIndex2 + 0.5) * m_dStep ; // Ciclo sugli indici dei dexel che potrebbero // intersecare il segmento di partenza int nCurStack = 0 ; for ( int tK = tStartK ; tK <= tStopK ; ++ tK) { // Analizzo i dexel della griglia 1. int tStopX = int( m_Values[1][tK * m_nNx[1] + tGrIndex2].size()) ; for ( int tIntX = 0 ; tIntX < tStopX ; ++ tIntX) { // Estremi del segmento del dexel lungo X double dXmin = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMin ; double dXmax = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dXmin - 2 * EPS_SMALL < dX && dXmax + 2 * EPS_SMALL > dX && m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo == 0) { m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].nCompo = m_Values[0][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 1 ; NewInterval.tDex = tK * m_nNx[1] + tGrIndex2 ; NewInterval.tInt = tIntX ; IntervalsToProcessStackVec[nCurStack].push( NewInterval) ; nCurStack = ( ++ nCurStack) % int( IntervalsToProcessStackVec.size()) ; } } // Analizzo i dexel della griglia 2 int tStopY = int( m_Values[2][tGrIndex1 * m_nNx[2] + tK].size()) ; for ( int tIntY = 0 ; tIntY < tStopY ; ++ tIntY) { // Estremi del segmento del dexel lungo Y double dYmin = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMin ; double dYmax = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMax ; // Se i segmenti si incrociano e il nuovo trovato non // ha già un indice assegnato, assegno l'indice e // aggiungo l'intervallo trovato allo stack. if ( dYmin - 2 * EPS_SMALL < dY && dYmax + 2 * EPS_SMALL > dY && m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo == 0) { m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].nCompo = m_Values[0][tDex][tInt].nCompo ; IntervalIndexes NewInterval ; NewInterval.tMap = 2 ; NewInterval.tDex = tGrIndex1 * m_nNx[2] + tK ; NewInterval.tInt = tIntY ; IntervalsToProcessStackVec[nCurStack].push( NewInterval) ; nCurStack = ( ++ nCurStack) % int( IntervalsToProcessStackVec.size()) ; } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::ProcessIntervals( IntContainer& IntervalsToProcess) { // Processo gli intervalli trovati while ( ! IntervalsToProcess.empty()) { switch ( IntervalsToProcess.top().tMap) { case 0: ExpandFromZInterval( IntervalsToProcess) ; break ; case 1: ExpandFromXInterval( IntervalsToProcess) ; break ; case 2: ExpandFromYInterval( IntervalsToProcess) ; break ; } } return true ; } //---------------------------------------------------------------------------- VolZmap* VolZmap::ClonePart( int nPart) const { // verifico lo stato if ( m_nStatus != OK) return nullptr ; // Se è definita una sola griglia non sono definibili le parti, errore if ( m_nMapNum == 1) return nullptr ; // Se è richiesta una componente fuori intervallo, errore if ( nPart < 0 || nPart >= m_nConnectedCompoCount) return nullptr ; // Se il numero di componenti è indefinito, lo ricalcolo. if ( m_nConnectedCompoCount == - 1) const_cast(this)->CheckMapConnection() ; // Se non vi sono componenti, errore if ( m_nConnectedCompoCount == 0) return nullptr ; // Creo nuovo oggetto Zmap PtrOwner pVolume( CreateBasicVolZmap()) ; if ( IsNull( pVolume)) return nullptr ; // Setto per il nuovo Zmap le seguenti variabili pVolume->m_nConnectedCompoCount = 1 ; pVolume->m_dStep = m_dStep ; pVolume->m_nMapNum = m_nMapNum ; // Minimi e massimi indici i,j della componente per le tre griglie int nMinIndI[N_MAPS] ; int nMaxIndI[N_MAPS] ; int nMinIndJ[N_MAPS] ; int nMaxIndJ[N_MAPS] ; // Coordinate dell'origine del sistema di riferimento // del nuovo Zmap double dNewOx, dNewOy, dNewOz ; // Ciclo sulle mappe for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) { nMinIndI[nMap] = m_nNx[nMap] ; nMinIndJ[nMap] = m_nNy[nMap] ; nMaxIndI[nMap] = 0 ; nMaxIndJ[nMap] = 0 ; pVolume->m_dMinZ[nMap] = m_dMaxZ[nMap] ; pVolume->m_dMaxZ[nMap] = m_dMinZ[nMap] ; // Della componente connessa in questione calcolo indici i e j massimi e minimi. // Inoltre cerco la minima e massima Z. for ( int nIndI = 0 ; nIndI < int( m_nNx[nMap]) ; ++ nIndI) { for ( int nIndJ = 0 ; nIndJ < int( m_nNy[nMap]) ; ++ nIndJ) { int nDex = nIndJ * m_nNx[nMap] + nIndI ; for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) { if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) { if ( nIndI < nMinIndI[nMap]) nMinIndI[nMap] = nIndI ; if ( nIndJ < nMinIndJ[nMap]) nMinIndJ[nMap] = nIndJ ; if ( nIndI > nMaxIndI[nMap]) nMaxIndI[nMap] = nIndI ; if ( nIndJ > nMaxIndJ[nMap]) nMaxIndJ[nMap] = nIndJ ; if ( m_Values[nMap][nDex][nInt].dMin < pVolume->m_dMinZ[nMap]) pVolume->m_dMinZ[nMap] = m_Values[nMap][nDex][nInt].dMin ; if ( m_Values[nMap][nDex][nInt].dMax > pVolume->m_dMaxZ[nMap]) pVolume->m_dMaxZ[nMap] = m_Values[nMap][nDex][nInt].dMax ; } } } } } for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) { if ( nMinIndI[nMap] > 0) -- nMinIndI[nMap] ; if ( nMaxIndI[nMap] < int( m_nNx[nMap]) - 1) ++ nMaxIndI[nMap] ; if ( nMinIndJ[nMap] > 0) -- nMinIndJ[nMap] ; if ( nMaxIndJ[nMap] < int( m_nNy[nMap]) - 1) ++ nMaxIndJ[nMap] ; pVolume->m_nNx[nMap] = max( 0, nMaxIndI[nMap] - nMinIndI[nMap] + 1) ; pVolume->m_nNy[nMap] = max( 0, nMaxIndJ[nMap] - nMinIndJ[nMap] + 1) ; pVolume->m_nDim[nMap] = pVolume->m_nNx[nMap] * pVolume->m_nNy[nMap] ; pVolume->m_Values[nMap].resize( pVolume->m_nDim[nMap]) ; } // Se almeno una griglia è nulla, non ha senso Zmap if ( pVolume->m_nDim[0] == 0 || pVolume->m_nDim[1] == 0 || pVolume->m_nDim[2] == 0) return nullptr ; // Copio gli intervalli nelle griglie del nuovo oggetto: // Griglia 0 for ( int nIndJ = 0 ; nIndJ < int( pVolume->m_nNy[0]) ; ++ nIndJ) { for ( int nIndI = 0 ; nIndI < int( pVolume->m_nNx[0]) ; ++ nIndI) { int nNewDex = nIndJ * pVolume->m_nNx[0] + nIndI ; int nOldDex = ( nIndJ + nMinIndJ[0]) * m_nNx[0] + nIndI + nMinIndI[0] ; for ( int nInt = 0 ; nInt < int( m_Values[0][nOldDex].size()) ; ++ nInt) { if ( m_Values[0][nOldDex][nInt].nCompo == nPart + 1) { pVolume->m_Values[0][nNewDex].emplace_back( m_Values[0][nOldDex][nInt]) ; pVolume->m_Values[0][nNewDex].back().nCompo = 1 ; } } } } // Griglia 1 for ( int nIndJ = 0 ; nIndJ < int( pVolume->m_nNy[1]) ; ++ nIndJ) { for ( int nIndI = 0 ; nIndI < int( pVolume->m_nNx[1]) ; ++ nIndI) { int nNewDex = nIndJ * pVolume->m_nNx[1] + nIndI ; int nOldDex = ( nIndJ + nMinIndJ[1]) * m_nNx[1] + nIndI + nMinIndI[1] ; for ( int nInt = 0 ; nInt < int( m_Values[1][nOldDex].size()) ; ++ nInt) { if ( m_Values[1][nOldDex][nInt].nCompo == nPart + 1) { pVolume->m_Values[1][nNewDex].emplace_back( m_Values[1][nOldDex][nInt]) ; pVolume->m_Values[1][nNewDex].back().nCompo = 1 ; } } } } // Griglia 2 for ( int nIndJ = 0 ; nIndJ < int( pVolume->m_nNy[2]) ; ++ nIndJ) { for ( int nIndI = 0 ; nIndI < int( pVolume->m_nNx[2]) ; ++ nIndI) { int nNewDex = nIndJ * pVolume->m_nNx[2] + nIndI ; int nOldDex = ( nIndJ + nMinIndJ[2]) * m_nNx[2] + nIndI + nMinIndI[2] ; for ( int nInt = 0 ; nInt < int( m_Values[2][nOldDex].size()) ; ++ nInt) { if ( m_Values[2][nOldDex][nInt].nCompo == nPart + 1) { pVolume->m_Values[2][nNewDex].emplace_back( m_Values[2][nOldDex][nInt]) ; pVolume->m_Values[2][nNewDex].back().nCompo = 1 ; } } } } // Coordinate x,y dell'origine del sistema di riferimento dNewOx = nMinIndI[0] * m_dStep ; dNewOy = nMinIndJ[0] * m_dStep ; dNewOz = nMinIndJ[1] * m_dStep ; // Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali, // infatti i sistemi di riferimento in gioco differiscono al più per una traslazione. for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) { // Quote estreme Z switch ( nMap) { case 0 : pVolume->m_dMinZ[nMap] -= dNewOz ; pVolume->m_dMaxZ[nMap] -= dNewOz ; break ; case 1 : pVolume->m_dMinZ[nMap] -= dNewOx ; pVolume->m_dMaxZ[nMap] -= dNewOx ; break ; case 2 : pVolume->m_dMinZ[nMap] -= dNewOy ; pVolume->m_dMaxZ[nMap] -= dNewOy ; break ; } // Dexel for ( int nDex = 0 ; nDex < int( pVolume->m_nDim[nMap]) ; ++ nDex) { for ( int nInt = 0 ; nInt < int( pVolume->m_Values[nMap][nDex].size()) ; ++ nInt) { switch ( nMap) { case 0 : pVolume->m_Values[nMap][nDex][nInt].dMin -= dNewOz ; pVolume->m_Values[nMap][nDex][nInt].dMax -= dNewOz ; break ; case 1 : pVolume->m_Values[nMap][nDex][nInt].dMin -= dNewOx ; pVolume->m_Values[nMap][nDex][nInt].dMax -= dNewOx ; break ; case 2 : pVolume->m_Values[nMap][nDex][nInt].dMin -= dNewOy ; pVolume->m_Values[nMap][nDex][nInt].dMax -= dNewOy ; break ; } } } } // Definisco il numero di blocchi lungo x,y e z if ( ! pVolume->CalcBlockNum()) return nullptr ; // Sistema di riferimento intrinseco del nuovo solido Point3d ptNewO = m_MapFrame.Orig() + Vector3d( dNewOx, dNewOy, dNewOz) ; pVolume->m_MapFrame.Set( ptNewO, X_AX, Y_AX, Z_AX) ; // Determino la forma pVolume->m_nShape = ( pVolume->IsBox() ? BOX : GENERIC) ; // Setto lo stato del nuovo Solido pVolume->m_nStatus = m_nStatus ; // Restituisco il nuovo solido return Release( pVolume) ; } //---------------------------------------------------------------------------- bool VolZmap::RemovePart( int nPart) { // verifico lo stato if ( m_nStatus != OK) return false ; // Se è definita una sola griglia non sono definibili le parti, errore if ( m_nMapNum == 1) return false ; // Se il numero di componenti è indefinito, lo ricalcolo if ( m_nConnectedCompoCount == - 1) CheckMapConnection() ; // Se non vi sono componenti, abbiamo finito if ( m_nConnectedCompoCount == 0) return true ; // Elimino i segmenti con indice nPart + 1 e aggiorno quelli con indice superiore // Ciclo sulle mappe. for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) { // Ciclo sui dexel della mappa. for ( int nDex = 0 ; nDex < int( m_Values[nMap].size()) ; ++ nDex) { // Ciclo sugli intervalli del dexel. for ( int nInt = 0 ; nInt < int( m_Values[nMap][nDex].size()) ; ++ nInt) { // Se l'intervallo appartiene alla componente da eliminare, lo cancello. if ( m_Values[nMap][nDex][nInt].nCompo == nPart + 1) { SetToModifyDexelBlocks( nMap, nDex, nInt) ; m_Values[nMap][nDex].erase( m_Values[nMap][nDex].begin() + nInt) ; -- nInt ; } else if ( m_Values[nMap][nDex][nInt].nCompo > nPart + 1) m_Values[nMap][nDex][nInt].nCompo -= 1 ; } } } // Decremento il numero di componenti. m_nConnectedCompoCount -= 1 ; // Imposto ricalcolo grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- int VolZmap::GetPartMinDistFromPoint( const Point3d& ptP) const { // Verifico lo stato e che siano definibili le componenti connesse if ( m_nStatus != OK || m_nMapNum == 1) return - 1 ; // Se il numero di componenti è indefinito, lo ricalcolo if ( m_nConnectedCompoCount == -1) const_cast( this)->CheckMapConnection() ; // Se non vi sono componenti, abbiamo finito if ( m_nConnectedCompoCount == 0) return - 1 ; // Porto il punto nel riferimento intrinseco Point3d ptPL = ptP ; ptPL.ToLoc( m_MapFrame) ; // Trovo la componente connessa di minima distanza dal punto double dMinDist = DBL_MAX ; int nMinDistPart = - 1 ; for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) { for ( int nDex = 0 ; nDex < m_nDim[nMap] ; ++ nDex) { double dX = ( ( nDex % m_nNx[nMap]) + 0.5) * m_dStep ; double dY = ( ( nDex / m_nNx[nMap]) + 0.5) * m_dStep ; int nIntervalNum = int( m_Values[nMap][nDex].size()) ; for ( int nInt = 0 ; nInt < nIntervalNum ; ++ nInt) { Point3d ptSt( dX, dY, m_Values[nMap][nDex][nInt].dMin) ; Point3d ptEn( dX, dY, m_Values[nMap][nDex][nInt].dMax) ; // Riporto le coordinate cicliche delle normali nell'ordine di partenza (da griglia a sistema intrinseco) if ( nMap == 1) { swap( ptSt.x, ptSt.z) ; swap( ptSt.y, ptSt.z) ; swap( ptEn.x, ptEn.z) ; swap( ptEn.y, ptEn.z) ; } else if ( nMap == 2) { swap( ptSt.y, ptSt.z) ; swap( ptSt.x, ptSt.z) ; swap( ptEn.y, ptEn.z) ; swap( ptEn.x, ptEn.z) ; } // Calcolo la distanza del punto dal segmento corrente. Se è minore della minima distanza aggiorno quest'ultima // e la corrispondente componente connessa di minima distanza con la distanza e la componente connessa correnti. double dDist ; DistPointLine DistCalc( ptPL, ptSt, ptEn) ; if ( DistCalc.GetDist( dDist) && dDist < dMinDist) { dMinDist = dDist ; nMinDistPart = m_Values[nMap][nDex][nInt].nCompo ; } } } } return ( nMinDistPart - 1) ; } //---------------------------------------------------------------------------- bool VolZmap::AddSurfTm( const ISurfTriMesh* pStm) { // controllo sulla superficie double dVol ; if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() || ! pStm->GetVolume( dVol) || dVol < 0) return false ; // controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente BBox3d BBox_stm, BBox_curr ; if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr)) return false ; BBox3d BBox_inters ; if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty()) return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone // ciclo sulle griglie bool bCompleted = true ; for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) { // definisco dei sistemi di riferimento ausiliari Frame3d frMapFrame ; if ( nG == 0) frMapFrame = m_MapFrame ; else if ( nG == 1) frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ; else if ( nG == 2) frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ; // oggetto per calcolo massivo intersezioni IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ; // numero massimo di thread int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ; vector> vRes ; vRes.resize( nThreadMax) ; // se dimensione griglia in X maggiore di dimensione Y if ( m_nNx[nG] > m_nNy[nG]) { int nDexNum = m_nNx[nG] / nThreadMax ; int nRemainder = m_nNx[nG] % nThreadMax ; int nInfI = 0 ; int nSupI = 0 ; // aggiungo le parti interessate alla mappa for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfI = nSupI ; nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG, nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()), ref( *pStm), ref( intPLSTM)) ; } } // se dimensione griglia in Y maggiore di dimensione X else { int nDexNum = m_nNy[nG] / nThreadMax ; int nRemainder = m_nNy[nG] % nThreadMax ; int nInfJ = 0 ; int nSupJ = 0 ; // aggiungo le parti interessate alla mappa for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfJ = nSupJ ; nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG, 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()), ref( *pStm), ref( intPLSTM)) ; } } // ciclo per attendere che tutti gli async abbiano terminato. int nTerminated = 0 ; while ( nTerminated < nThreadMax) { for ( int nL = 0 ; nL < nThreadMax ; ++ nL) { // async terminato if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) { ++ nTerminated ; bCompleted = bCompleted && vRes[nL].get() ; } } } if ( ! bCompleted) return false ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::SubtractSurfTm( const ISurfTriMesh* pStm) { // controllo sulla superficie double dVol ; if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() || ! pStm->GetVolume( dVol) || dVol < 0) return false ; // controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente BBox3d BBox_stm, BBox_curr ; if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr)) return false ; BBox3d BBox_inters ; if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty()) return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone // ciclo sulle griglie bool bCompleted = true ; for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) { // definisco dei sistemi di riferimento ausiliari Frame3d frMapFrame ; if ( nG == 0) frMapFrame = m_MapFrame ; else if ( nG == 1) frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ; else if ( nG == 2) frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ; // oggetto per calcolo massivo intersezioni IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ; // numero massimo di thread int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ; vector> vRes ; vRes.resize( nThreadMax) ; // se dimensione griglia in X maggiore di dimensione Y if ( m_nNx[nG] > m_nNy[nG]) { int nDexNum = m_nNx[nG] / nThreadMax ; int nRemainder = m_nNx[nG] % nThreadMax ; int nInfI = 0 ; int nSupI = 0 ; // aggiungo le parti interessate alla mappa for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfI = nSupI ; nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG, nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()), ref( *pStm), ref( intPLSTM)) ; } } // se dimensione griglia in Y maggiore di dimensione X else { int nDexNum = m_nNy[nG] / nThreadMax ; int nRemainder = m_nNy[nG] % nThreadMax ; int nInfJ = 0 ; int nSupJ = 0 ; // aggiungo le parti interessate alla mappa for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfJ = nSupJ ; nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG, 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()), ref( *pStm), ref( intPLSTM)) ; } } // ciclo per attendere che tutti gli async abbiano terminato. int nTerminated = 0 ; while ( nTerminated < nThreadMax) { for ( int nL = 0 ; nL < nThreadMax ; ++ nL) { // async terminato if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) { ++ nTerminated ; bCompleted = bCompleted && vRes[nL].get() ; } } } if ( ! bCompleted) return false ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::MakeUniform( double dToler, bool bIsExtensionFirst, int nToolNum) { // Controllo validità dello Zmap if ( ! IsValid()) return false ; // Creo lo ZMap per i riferimenti degli intervalli sulle griglie PtrOwner pZMapCopy( CloneBasicVolZmap( this)) ; if ( IsNull( pZMapCopy) || ! pZMapCopy->IsValid()) return false ; // Creo uno ZMap per gli intervalli da aggiungere o da rimuovere PtrOwner pZMapExtra( CreateBasicVolZmap()) ; if ( IsNull( pZMapExtra) || ! pZMapExtra->CreateEmpty( m_MapFrame.Orig(), m_dMaxZ[1] - m_dMinZ[1], m_dMaxZ[2] - m_dMinZ[2], m_dMaxZ[0] - m_dMinZ[0], m_dStep, IsTriDexel())) return false ; // Dovendo effettuare estensioni, allargo gli ingobri nelle direzioni principali m_dMinZ[0] -= dToler ; m_dMinZ[1] -= dToler ; m_dMinZ[2] -= dToler ; m_dMaxZ[0] += dToler ; m_dMaxZ[1] += dToler ; m_dMaxZ[2] += dToler ; // NB. Tutti i parametri sono sempre presi dalla Copia dello ZMap corrente // Ciclo sulle griglie for ( int nGrid = 0 ; nGrid < pZMapCopy->m_nMapNum ; ++ nGrid) { // Ciclo sul numero di dexel presenti nella Copia for ( int nDex = 0 ; nDex < ssize( pZMapCopy->m_Values[nGrid]) ; ++ nDex) { // Se il dexel corrente non ha sotto-intervalli passo al successivo if ( pZMapCopy->m_Values[nGrid][nDex].empty()) continue ; // Indici del dexel int nI = nDex % m_nNx[nGrid] ; int nJ = nDex / m_nNx[nGrid] ; // Recupero il numero di intervalli presenti nel Dexel corrente int nIntervals = ssize( pZMapCopy->m_Values[nGrid][nDex]) ; // Scorro gli intervalli presenti for ( int nInfo = 0 ; nInfo < ssize( pZMapCopy->m_Values[nGrid][nDex]) ; ++ nInfo) { // Recupero l'intervallo corrente Data& Interval = pZMapCopy->m_Values[nGrid][nDex][nInfo] ; // --- Se richiesta prima estensione if ( bIsExtensionFirst) { // *** Estremo inferiore -> Intervallo : [ dMin - dToler, dMin + dToler ] // Aggiungo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy) AddIntervals( nGrid, nI, nJ, Interval.dMin - dToler, Interval.dMin + dToler, Interval.vtMinN, Interval.vtMinN, nToolNum, true) ; // Se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due direzioni if ( IsTriDexel() && nIntervals != ssize( m_Values[nGrid][nDex])) { // Aggiorno gli intervalli correnti ( dato che il corrente si è unito al precedente) // ( lascio invariato lo ZMapCopy) nIntervals = ssize( m_Values[nGrid][nDex]) ; pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ, pZMapCopy->m_Values[nGrid][nDex][nInfo-1].dMax, Interval.dMin, dToler, true, nToolNum, V_INVALID, V_INVALID) ; } // *** Estremo superiore -> Intervallo : [ dMax - dToler, dMax + dToler ] // Aggiungo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy) AddIntervals( nGrid, nI, nJ, Interval.dMax - dToler, Interval.dMax + dToler, Interval.vtMaxN, Interval.vtMaxN, nToolNum, true) ; // Se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due direzioni if ( IsTriDexel() && nIntervals != ssize( m_Values[nGrid][nDex])) { // Aggiorno gli intervalli correnti ( dato che il corrente si è unito al successivo) // ( lascio invariato lo ZMapCopy) nIntervals = ssize( m_Values[nGrid][nDex]) ; pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ, Interval.dMax, pZMapCopy->m_Values[nGrid][nDex][nInfo+1].dMin, dToler, true, nToolNum, V_INVALID, V_INVALID) ; } } // --- Se richiesta prima restrizione else { // Se la lunghezza dell'intervallo non è almeno il doppio della tolleranza double dLen = Interval.dMax - Interval.dMin ; if ( dLen < 2. * ( dToler + EPS_SMALL)) { // L'intervallo sparisce completamente SubtractIntervals( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMax + EPS_SMALL, Interval.vtMinN, Interval.vtMaxN, nToolNum, true) ; // Rimuovo le parti di spillone nelle altre dimensioni if ( IsTriDexel()) { -- nIntervals ; pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ, Interval.dMin, Interval.dMax, dToler, true, Tool::UNDEF, V_INVALID, V_INVALID) ; } } // Se sufficientemente lungo, allora else { // *** Estremo inferiore -> Intervallo : [ dMin, dMin + dToler ] // Sottraggo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy) SubtractIntervals( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMin + dToler, Interval.vtMinN, Interval.vtMinN, nToolNum, true) ; // *** Estremo superiore -> Intervallo : [ dMax - dToler, dMax ] // Sottraggo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy) SubtractIntervals( nGrid, nI, nJ, Interval.dMax - dToler, Interval.dMax + EPS_SMALL, Interval.vtMaxN, Interval.vtMaxN, nToolNum, true) ; } } } } } // Ciclo sulle griglie ( uso lo Zmap Corrente, lascio invariato pZMapCopy) for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) { // Ciclo sul numero di dexel presenti for ( int nDex = 0 ; nDex < ssize( m_Values[nGrid]) ; ++ nDex) { // Se l'intervallo è vuoto, non faccio nulla if ( m_Values[nGrid][nDex].empty()) continue ; // Per ogni intervallo ricavato fino ad ora, restringo della tolleranza for ( int nInfo = 0 ; nInfo < ssize( m_Values[nGrid][nDex]) ; ++ nInfo) { // --- Se richiesta prima estensione if ( bIsExtensionFirst) { m_Values[nGrid][nDex][nInfo].dMin += dToler ; m_Values[nGrid][nDex][nInfo].dMax -= dToler ; } // --- Se richiesta prima restrizione else { m_Values[nGrid][nDex][nInfo].dMin -= dToler ; m_Values[nGrid][nDex][nInfo].dMax += dToler ; } // Definisco il colore for ( int nOrigInfo = 0 ; nOrigInfo < ssize( pZMapCopy->m_Values[nGrid][nDex]) ; ++ nOrigInfo) { if ( pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].dMin - m_Values[nGrid][nDex][nInfo].dMin < EPS_SMALL) m_Values[nGrid][nDex][nInfo].nToolMin = pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].nToolMin ; if ( pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].dMax - m_Values[nGrid][nDex][nInfo].dMax < EPS_SMALL) m_Values[nGrid][nDex][nInfo].nToolMax = pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].nToolMax ; } } } } // Gestisco le parti Extra ricavate // Ciclo sulle griglie ( uso lo ZmapExtra, lascio invariato pZMapCopy) for ( int nGrid = 0 ; nGrid < pZMapExtra->m_nMapNum ; ++ nGrid) { // Ciclo sul numero di dexel presenti for ( int nDex = 0 ; nDex < ssize( pZMapExtra->m_Values[nGrid]) ; ++ nDex) { // Se l'intervallo è vuoto, non faccio nulla if ( pZMapExtra->m_Values[nGrid][nDex].empty()) continue ; // Indici del dexel int nI = nDex % m_nNx[nGrid] ; int nJ = nDex / m_nNx[nGrid] ; // Per ogni intervallo ricavato fino ad ora... for ( int nInfo = 0 ; nInfo < ssize( pZMapExtra->m_Values[nGrid][nDex]) ; ++ nInfo) { double dMin = pZMapExtra->m_Values[nGrid][nDex][nInfo].dMin ; double dMax = pZMapExtra->m_Values[nGrid][nDex][nInfo].dMax ; Vector3d vtNMin = pZMapExtra->m_Values[nGrid][nDex][nInfo].vtMinN ; Vector3d vtNMax = pZMapExtra->m_Values[nGrid][nDex][nInfo].vtMaxN ; // --- Se richiesta prima estensione if ( bIsExtensionFirst) { // Aggiungo i contributi AddIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, true) ; } // --- Se richiesta prima restrizione else { // Sottraggo i contributi SubtractIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, true) ; } } } } // Restringo gli ingombri espensi in precedenza m_dMinZ[0] += dToler ; m_dMinZ[1] += dToler ; m_dMinZ[2] += dToler ; m_dMaxZ[0] -= dToler ; m_dMaxZ[1] -= dToler ; m_dMaxZ[2] -= dToler ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::RemoveFins( const Vector3d& vtDir, double dThick) { // Verifico la Validità dello ZMap if ( ! IsValid()) return false ; // Per sicurezza normalizzo la direzione Vector3d vtMyDir = vtDir ; if ( ! vtMyDir.Normalize()) return false ; double dMyThick = max( 10. * EPS_SMALL, dThick) ; // Creo lo ZMap per i riferimenti degli intervalli sulle griglie PtrOwner pZMapCopy( CloneBasicVolZmap( this)) ; if ( IsNull( pZMapCopy) || ! pZMapCopy->IsValid()) return false ; // Creo uno ZMap per gli intervalli da aggiungere e successivamente da rimuovere VolZmap ZMapExtra ; if ( ! ZMapExtra.CreateEmpty( m_MapFrame.Orig(), m_dMaxZ[1] - m_dMinZ[1], m_dMaxZ[2] - m_dMinZ[2], m_dMaxZ[0] - m_dMinZ[0], m_dStep, IsTriDexel())) return false ; const double FIN_ANG_DEG_TOL = 55. ; // Approssimazione per eccesso dell'angolo massimo possibile tra una direzione generica // e un versore della terna globale ( arccos( 1 / sqrt( 3) ~ 54.375) const double COS_FIN_ANG_DEG_TOL = cos( FIN_ANG_DEG_TOL * DEGTORAD) ; const int NUM_TOOL = 1000 ; // Identificativo Utensile per riconoscere le parti rimosse // NB. Tutti i parametri sono sempre presi dalla Copia dello ZMap corrente // Ciclo sulle griglie DBLVECTOR vdThicks ; if ( IsTriDexel()) vdThicks = { dThick, dThick, dThick} ; else vdThicks = { dThick} ; for ( int nGrid = 0 ; nGrid < pZMapCopy->m_nMapNum ; ++ nGrid) { // Verifico se l'angolo tra la direzione degli spilloni della griglia corrente è sotto alla tolleranza rispetto alla direzione double dCosDir = ( nGrid == 0 ? vtMyDir.z : ( nGrid == 1 ? vtMyDir.x : vtMyDir.y)) ; if ( abs( dCosDir) < COS_FIN_ANG_DEG_TOL + EPS_ANG_SMALL) continue ; // Aggiorno l'effettivo valore dello spessore da considerare double dCurrThick = dMyThick / abs( dCosDir) ; // (sicuramente esiste, essendo 55deg il limite) vdThicks[nGrid] = dCurrThick ; // Ciclo sul numero di dexel presenti nella Copia for ( int nDex = 0 ; nDex < ssize( pZMapCopy->m_Values[nGrid]) ; ++ nDex) { // Se il dexel corrente non ha sotto-intervalli passo al successivo if ( pZMapCopy->m_Values[nGrid][nDex].empty()) continue ; // Indici del dexel int nI = nDex % m_nNx[nGrid] ; int nJ = nDex / m_nNx[nGrid] ; // Scorro gli intervalli presenti for ( int nInfo = 0 ; nInfo < ssize( pZMapCopy->m_Values[nGrid][nDex]) ; ++ nInfo) { // Recupero l'intervallo corrente Data& Interval = pZMapCopy->m_Values[nGrid][nDex][nInfo] ; // Se entrambi gli estremi dell'intervallo non sono stati toccati dall'utensile, allora passo al successivo bool bAnalyze = ( ( Interval.nToolMin == 1 && Interval.nToolMax == 1) || ( Interval.dMax > m_dMaxZ[nGrid] - EPS_SMALL || Interval.dMin < m_dMinZ[nGrid] + EPS_SMALL)) ; if ( ! bAnalyze) continue ; // Se la lunghezza dell'intervallo è superiore allo spessore richiesto, non faccio nulla double dLen = Interval.dMax - Interval.dMin ; if ( dLen > dCurrThick + EPS_ZERO) continue ; // Se ZMap composto da una sola griglia, elimino il contributo lungo la direzione corrente if ( ! IsTriDexel()) { SubtractIntervals( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMax + EPS_SMALL, - Interval.vtMinN, - Interval.vtMaxN, NUM_TOOL, true) ; } // Se Tridexel, aggiungo il contributo del cubetto corrente allo ZMap Extra else ZMapExtra.AddStripInterval( nGrid, nI, nJ, Interval.dMin - EPS_SMALL, Interval.dMax + EPS_SMALL, NUM_TOOL) ; } } } // Se non ho aggiunto alcun elemento allo ZMap Extra, non devo fare nulla if ( ! ZMapExtra.IsValid()) return true ; #if DEBUG_REMOVE_FINS SaveGeoObj( ZMapExtra.Clone(), "C:\\Temp\\VolZMapSubt0.nge") ; #endif // Ciclo sulle griglie dello ZMap Extra for ( int nGrid = 0 ; nGrid < ZMapExtra.m_nMapNum ; ++ nGrid) { // Ciclo sul numero di dexel presenti for ( int nDex = 0 ; nDex < ssize( ZMapExtra.m_Values[nGrid]) ; ++ nDex) { // Se l'intervallo è vuoto, non faccio nulla if ( ZMapExtra.m_Values[nGrid][nDex].empty()) continue ; // Indici del dexel int nI = nDex % m_nNx[nGrid] ; int nJ = nDex / m_nNx[nGrid] ; // Scorro i gli Intervalli dello Spillone corrente for ( int nInfo = 0 ; nInfo < ssize( ZMapExtra.m_Values[nGrid][nDex]) ; ++ nInfo) { double dMin = ZMapExtra.m_Values[nGrid][nDex][nInfo].dMin ; double dMax = ZMapExtra.m_Values[nGrid][nDex][nInfo].dMax ; Vector3d vtNMin = ZMapExtra.m_Values[nGrid][nDex][nInfo].vtMinN ; Vector3d vtNMax = ZMapExtra.m_Values[nGrid][nDex][nInfo].vtMaxN ; // sottraggo tali contributi SubtractIntervals( nGrid, nI, nJ, dMin, dMax, - vtNMin, - vtNMax, NUM_TOOL, true) ; } } } if ( ! IsValid()) return true ; #if DEBUG_REMOVE_FINS SaveGeoObj( this->Clone(), "C:\\Temp\\VolZMapSubt1.nge") ; #endif // Sistemo le Normali sullo ZMap ricavato for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) { // Ciclo sul numero di dexel presenti for ( int nDex = 0 ; nDex < ssize( m_Values[nGrid]) ; ++ nDex) { // Se l'Intervallo è vuoto non faccio nulla if ( m_Values[nGrid][nDex].empty()) continue ; // Indici del dexel int nI = nDex % m_nNx[nGrid] ; int nJ = nDex / m_nNx[nGrid] ; // Scorro gli intervalli dello spillone corrente for ( int nInfo = 0 ; nInfo < ssize( m_Values[nGrid][nDex]) ; ++ nInfo) { // Se intervallo con estremo minimo derivante dalla sottrazione con ZMapExtra, medio le normali int nToolMin = m_Values[nGrid][nDex][nInfo].nToolMin ; if ( nToolMin == NUM_TOOL) { // Recupero il valore minimo, se sul bordo dello ZMap corrente non faccio nulla double dMin = m_Values[nGrid][nDex][nInfo].dMin ; if ( dMin > m_dMinZ[nGrid] + EPS_SMALL) { Vector3d vtMinN = V_NULL ; double dZMin = INFINITO ; if ( ! pZMapCopy->ComputePointAndNormalForRemovingFins( nGrid, nI, nJ, dMin, vtMyDir, dThick, true, 1, vtMinN, dZMin)) { vtMinN = - ( nGrid == 0 ? m_MapFrame.VersZ() : nGrid == 1 ? m_MapFrame.VersX() : m_MapFrame.VersY()) ; dZMin = dMin ; } m_Values[nGrid][nDex][nInfo].vtMinN = vtMinN ; m_Values[nGrid][nDex][nInfo].dMin = dZMin ; } } // Se intervallo con estremo massimo derivante dalla sottrazione con ZMapExtra, medio le normali int nToolMax = m_Values[nGrid][nDex][nInfo].nToolMax ; if ( nToolMax == NUM_TOOL) { // Recupero il valore massimo, se sul bordo dello ZMap corrente non faccio nulla double dMax = m_Values[nGrid][nDex][nInfo].dMax ; if ( dMax < m_dMaxZ[nGrid] - EPS_SMALL) { Vector3d vtMaxN = V_NULL ; double dZMax = INFINITO ; if ( ! pZMapCopy->ComputePointAndNormalForRemovingFins( nGrid, nI, nJ, dMax, vtMyDir, dThick, false, 1, vtMaxN, dZMax)) { vtMaxN = ( nGrid == 0 ? m_MapFrame.VersZ() : nGrid == 1 ? m_MapFrame.VersX() : m_MapFrame.VersY()) ; dZMax = dMax ; } m_Values[nGrid][nDex][nInfo].vtMaxN = vtMaxN ; m_Values[nGrid][nDex][nInfo].dMax = dZMax ; } } } } } // Riassegno il Tool dell'utensile alle nuove parti for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) { // Ciclo sul numero di dexel presenti for ( int nDex = 0 ; nDex < ssize( m_Values[nGrid]) ; ++ nDex) { // Se l'Intervallo è vuoto non faccio nulla if ( m_Values[nGrid][nDex].empty()) continue ; // Scorro gli intervalli dello spillone corrente for ( int nInfo = 0 ; nInfo < ssize( m_Values[nGrid][nDex]) ; ++ nInfo) { if ( m_Values[nGrid][nDex][nInfo].nToolMin == NUM_TOOL) m_Values[nGrid][nDex][nInfo].nToolMin = 1 ; if ( m_Values[nGrid][nDex][nInfo].nToolMax == NUM_TOOL) m_Values[nGrid][nDex][nInfo].nToolMax = 1 ; } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::SetToModifyDexelBlocks( int nGrid, int nDex, int nInt) { // Controllo sulla validità della griglia if ( nGrid < 0 || nGrid > 2) return false ; // Controllo sulla validità del dexel if ( nDex <= - 1 || nDex >= int( m_Values[nGrid].size())) return false ; // Controllo sulla validità dell'intervallo if ( nInt <= - 1 || nInt >= int( m_Values[nGrid][nDex].size())) return false ; // Determino quali blocchi sono stati modificati int nLayerBlock = m_nFracLin[0] * m_nFracLin[1] ; // Indici del dexel int nI = nDex % m_nNx[nGrid] ; int nJ = nDex / m_nNx[nGrid] ; // Quote estreme del dexel double dMin = m_Values[nGrid][nDex][nInt].dMin ; double dMax = m_Values[nGrid][nDex][nInt].dMax ; if ( nGrid == 0) { int nXStop = 1 ; int nYStop = 1 ; int nXBlock[2] ; int nYBlock[2] ; // Passo dal dexel al voxel nI /= m_nDexVoxRatio ; nJ /= m_nDexVoxRatio ; nXBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ; nYBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ; if ( nI % N_VOXBLOCK == 0 && nXBlock[0] > 0) { nXBlock[1] = nXBlock[0] - 1 ; ++ nXStop ; } if ( nJ % N_VOXBLOCK == 0 && nYBlock[0] > 0) { nYBlock[1] = nYBlock[0] - 1 ; ++ nYStop ; } // Numero di voxel lungo Z int nVoxNumZ = int( m_nNy[1] / m_nDexVoxRatio + ( m_nNy[1] % m_nDexVoxRatio == 0 ? 1 : 2)) ; int nMinK = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumZ - 2) ; int nMaxK = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumZ - 2) ; int nMinZBlock = ( m_nMapNum == 1 ? 0 : Clamp( nMinK / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[2] - 1))) ; int nMaxZBlock = min( int( m_nFracLin[2] - 1), nMaxK / int( m_nVoxNumPerBlock)) ; for ( int tI = 0 ; tI < nXStop ; ++ tI) { for ( int tJ = 0 ; tJ < nYStop ; ++ tJ) { for ( int k = nMinZBlock ; k <= nMaxZBlock ; ++ k) { int nBlockNum = k * nLayerBlock + nYBlock[tJ] * m_nFracLin[0] + nXBlock[tI] ; m_BlockToUpdate[nBlockNum] = true ; } } } } else if ( nGrid == 1) { int nYStop = 1 ; int nZStop = 1 ; int nYBlock[2] ; int nZBlock[2] ; // Passo dal dexel al voxel nI /= m_nDexVoxRatio ; nJ /= m_nDexVoxRatio ; nYBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ; nZBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ; if ( nI % N_VOXBLOCK == 0 && nYBlock[0] > 0) { nYBlock[1] = nYBlock[0] - 1 ; ++ nYStop ; } if ( nJ % N_VOXBLOCK == 0 && nZBlock[0] > 0) { nZBlock[1] = nZBlock[0] - 1 ; ++ nZStop ; } // Numero di voxel lungo X int nVoxNumX = int( m_nNx[0] / m_nDexVoxRatio + ( m_nNx[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ; int nMinI = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumX - 2) ; int nMaxI = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumX - 2) ; int nMinXBlock = Clamp( nMinI / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[0] - 1)) ; int nMaxXBlock = min( int( m_nFracLin[0] - 1), nMaxI / int( m_nVoxNumPerBlock)) ; for ( int tI = 0 ; tI < nYStop ; ++ tI) { for ( int tJ = 0 ; tJ < nZStop ; ++ tJ) { for ( int k = nMinXBlock ; k <= nMaxXBlock ; ++ k) { int nBlockNum = nZBlock[tJ] * nLayerBlock + nYBlock[tI] * m_nFracLin[0] + k ; m_BlockToUpdate[nBlockNum] = true ; } } } } else if ( nGrid == 2) { int nXStop = 1 ; int nZStop = 1 ; int nXBlock[2] ; int nZBlock[2] ; // Passo dal dexel al voxel nI /= m_nDexVoxRatio ; nJ /= m_nDexVoxRatio ; nXBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ; nZBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ; if ( nJ % N_VOXBLOCK == 0 && nXBlock[0] > 0) { nXBlock[1] = nXBlock[0] - 1 ; ++ nXStop ; } if ( nI % N_VOXBLOCK == 0 && nZBlock[0] > 0) { nZBlock[1] = nZBlock[0] - 1 ; ++ nZStop ; } // Numero di voxel lungo Y int nVoxNumY = int( m_nNy[0] / m_nDexVoxRatio + ( m_nNy[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ; int nMinJ = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumY - 2) ; int nMaxJ = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumY - 2) ; int nMinYBlock = Clamp( nMinJ / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[1] - 1)) ; int nMaxYBlock = min( int( m_nFracLin[1] - 1), nMaxJ / int( m_nVoxNumPerBlock)) ; for ( int tI = 0 ; tI < nZStop ; ++ tI) { for ( int tJ = 0 ; tJ < nXStop ; ++ tJ) { for ( int k = nMinYBlock ; k <= nMaxYBlock ; ++ k) { int nBlockNum = nZBlock[tI] * nLayerBlock + k * m_nFracLin[0] + nXBlock[tJ] ; m_BlockToUpdate[nBlockNum] = true ; } } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::IsMapPartABox( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, double& dMinZ, double& dMaxZ) { dMinZ = m_dMaxZ[nMap] ; dMaxZ = m_dMinZ[nMap] ; for ( int i = nInfI ; i < nSupI ; ++ i) { for ( int j = nInfJ ; j < nSupJ ; ++ j) { int n = j * m_nNx[nMap] + i ; int nSize = int( m_Values[nMap][n].size()) ; if ( nSize > 1) return false ; else if ( nSize > 0) { if ( dMinZ > dMaxZ) { dMinZ = m_Values[nMap][n][0].dMin ; dMaxZ = m_Values[nMap][n][0].dMax ; } else { if ( abs( m_Values[nMap][n][0].dMin - dMinZ) > EPS_SMALL || abs( m_Values[nMap][n][0].dMax - dMaxZ) > EPS_SMALL) return false ; } } } } return ( dMaxZ >= dMinZ) ; } //---------------------------------------------------------------------------- bool VolZmap::IsBox( void) { // Se non tridexel, non posso stabilire con il metodo seguente se è un box // Verifico solo che gli spilloni di una mappa o sono nulli o hanno gli stessi estremi if ( m_nMapNum == 1) return false ; // Numero massimo di thread per il calcolo parallelo. int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ; // Disponibile un solo thread if ( nThreadMax == 1) { for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) { double dMinZ, dMaxZ ; if ( ! IsMapPartABox( nMap, 0, m_nNx[nMap], 0, m_nNy[nMap], dMinZ, dMaxZ)) { m_bIsBox = false ; return false ; } } m_bIsBox = true ; return true ; } // Caso di più thread m_bIsBox = true ; for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) { vector< future> vRes ; vRes.resize( nThreadMax) ; std::vector vMinZ, vMaxZ ; vMinZ.resize( nThreadMax) ; vMaxZ.resize( nThreadMax) ; if ( m_nNx[nMap] > m_nNy[nMap]) { int nDexNum = m_nNx[nMap] / nThreadMax ; int nRemainder = m_nNx[nMap] % nThreadMax ; int nInfI = 0 ; int nSupI = 0 ; for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfI = nSupI ; nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::IsMapPartABox, this, nMap, nInfI, nSupI, 0, m_nNy[nMap], ref( vMinZ[nThread]), ref( vMaxZ[nThread])) ; } } else { int nDexNum = m_nNy[nMap] / nThreadMax ; int nRemainder = m_nNy[nMap] % nThreadMax ; int nInfJ = 0 ; int nSupJ = 0 ; for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfJ = nSupJ ; nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::IsMapPartABox, this, nMap, 0, m_nNx[nMap], nInfJ, nSupJ, ref(vMinZ[nThread]), ref(vMaxZ[nThread])) ; } } // Ciclo per attendere che tutti gli async abbiano terminato. int nTerminated = 0 ; while ( nTerminated < nThreadMax) { for ( int nL = 0 ; nL < nThreadMax ; ++ nL) { // Async terminato if ( vRes[nL].valid() && vRes[nL].wait_for(chrono::microseconds{ 1 }) == future_status::ready) { ++ nTerminated ; if ( ! vRes[nL].get()) { m_bIsBox = false ; } } } } // Se uno dei thread trova che la sua porzione non è un box, non lo può essere il solido intero. if ( ! m_bIsBox) return false ; // Controllo che gli estremi Z siano uguali. for ( int nT = 1 ; nT < nThreadMax ; ++ nT) { if ( abs( vMinZ[nT] - vMinZ[0]) > EPS_SMALL || abs( vMaxZ[nT] - vMaxZ[0]) > EPS_SMALL) { m_bIsBox = false ; return false ; } } } return m_bIsBox ; } //---------------------------------------------------------------------------- bool VolZmap::Cut( const Plane3d& plPlane) { // Porto il piano nel riferimento intrinseco Plane3d plMyPlane = plPlane ; plMyPlane.ToLoc( m_MapFrame) ; // Interseco lo Zmap col piano, ciclando sulle griglie bool bModified = false ; for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) { // Porto il piano nel riferimento di griglia if ( nMap == 1) { Frame3d frGrid ; frGrid.Set( ORIG, Y_AX, Z_AX, X_AX) ; plMyPlane.ToLoc( frGrid) ; } else if (nMap == 2) { Frame3d frGrid ; frGrid.Set( ORIG, Y_AX, Z_AX, X_AX) ; plMyPlane.ToLoc( frGrid) ; } // Ciclo sui dexel della mappa for ( int nD = 0 ; nD < int( m_Values[nMap].size()) ; ++ nD) { // Se spillone già vuoto, passo al successivo if ( m_Values[nMap][nD].empty()) continue ; // Indici di spillone int nI = nD % m_nNx[nMap] ; int nJ = nD / m_nNx[nMap] ; // Recupero estremi spillone double dMin = m_Values[nMap][nD][0].dMin ; double dMax = m_Values[nMap][nD][m_Values[nMap][nD].size() - 1].dMax ; Point3d ptSt( ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep, dMin) ; Point3d ptEn( ( nI + 0.5) * m_dStep, ( nJ + 0.5) * m_dStep, dMax) ; // Distanze degli estremi del segmento dal piano double dStDist = DistPointPlane( ptSt, plMyPlane) ; double dEnDist = DistPointPlane( ptEn, plMyPlane) ; // Se entrambi sotto il piano if ( dStDist < EPS_SMALL && dEnDist < EPS_SMALL) // Non devo fare alcunché ; // se altrimenti entrambi gli estremi sono oltre il piano else if ( dStDist > -EPS_SMALL && dEnDist > -EPS_SMALL) { // Si elimina tutto SubtractIntervals( nMap, nI, nJ, dMin, dMax, V_NULL, V_NULL, 1) ; } // se altrimenti è da tenere il punto iniziale else if ( dStDist < 0) { // Si elimina la parte tra intersezione e punto finale double dInt = dMin + ( dMax - dMin) * abs( dStDist) / ( abs( dStDist) + abs( dEnDist)) ; SubtractIntervals( nMap, nI, nJ, dInt, dMax, plMyPlane.GetVersN(), V_NULL, 1) ; } // se altrimenti è da tenere il punto finale else if (dEnDist < 0) { // Si elimina la parte tra punto iniziale e intersezione double dInt = dMin + ( dMax - dMin) * abs( dStDist) / ( abs( dStDist) + abs( dEnDist)) ; SubtractIntervals( nMap, nI, nJ, dMin, dInt, V_NULL, plMyPlane.GetVersN(), 1) ; } } } if ( bModified == true) { // Imposto forma generica m_nShape = GENERIC ; // Imposto ricalcolo grafica m_OGrMgr.Reset() ; // Imposto numero di componenti connesse da ricalcolare m_nConnectedCompoCount = - 1 ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::Compact( void) { // Determino i nuovi estremi sugli indici e sulle quote Z e copio i dexel i cui indici sono compresi fra gli estremi int nMinI[N_MAPS] ; int nMinJ[N_MAPS] ; int nMaxI[N_MAPS] ; int nMaxJ[N_MAPS] ; int nNx[N_MAPS] ; int nNy[N_MAPS] ; int nDim[N_MAPS] ; double dMinZ[N_MAPS] ; double dMaxZ[N_MAPS] ; vector> Values[N_MAPS] ; bool bNotEmptyGrid = true ; for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) { nMinI[nMap] = m_nNx[nMap] - 1 ; nMinJ[nMap] = m_nNy[nMap] - 1 ; nMaxI[nMap] = 0 ; nMaxJ[nMap] = 0 ; dMinZ[nMap] = m_dMaxZ[nMap] ; dMaxZ[nMap] = m_dMinZ[nMap] ; // Determino estremi degli indici e delle quote Z for ( int nD = 0 ; nD < int( m_Values[nMap].size()) ; ++ nD) { int nDexDim = int( m_Values[nMap][nD].size()) ; if ( nDexDim > 0) { int nI = nD % m_nNx[nMap] ; int nJ = nD / m_nNx[nMap] ; if ( nI < nMinI[nMap]) nMinI[nMap] = nI ; if ( nJ < nMinJ[nMap]) nMinJ[nMap] = nJ ; if ( nI > nMaxI[nMap]) nMaxI[nMap] = nI ; if ( nJ > nMaxJ[nMap]) nMaxJ[nMap] = nJ ; if ( m_Values[nMap][nD][0].dMin < dMinZ[nMap]) dMinZ[nMap] = m_Values[nMap][nD][0].dMin ; if ( m_Values[nMap][nD][nDexDim - 1].dMax > dMaxZ[nMap]) dMaxZ[nMap] = m_Values[nMap][nD][nDexDim - 1].dMax ; } } if ( nMinI[nMap] > nMaxI[nMap] || nMinJ[nMap] > nMaxJ[nMap]) { bNotEmptyGrid = false ; break ; } // Se necessario espando la griglia if ( nMinI[nMap] > 0) -- nMinI[nMap] ; if ( nMinJ[nMap] > 0) -- nMinJ[nMap] ; if ( nMaxI[nMap] < int( m_nNx[nMap]) - 1) ++ nMaxI[nMap] ; if ( nMaxJ[nMap] < int( m_nNy[nMap]) - 1) ++ nMaxJ[nMap] ; nNx[nMap] = nMaxI[nMap] - nMinI[nMap] + 1 ; nNy[nMap] = nMaxJ[nMap] - nMinJ[nMap] + 1 ; nDim[nMap] = nNx[nMap] * nNy[nMap] ; // Copio i dexel i cui indici sono compresi fra gli estremi for ( int nD = 0 ; nD < int( m_Values[nMap].size()) ; ++ nD) { int nI = nD % m_nNx[nMap] ; int nJ = nD / m_nNx[nMap] ; if ( nI >= nMinI[nMap] && nI <= nMaxI[nMap] && nJ >= nMinJ[nMap] && nJ <= nMaxJ[nMap]) { Values[nMap].emplace_back( m_Values[nMap][nD]) ; } } } // Se non vi è materiale if ( ! bNotEmptyGrid) { m_nStatus = TO_VERIFY ; m_nNumBlock = 0 ; m_nConnectedCompoCount = 0 ; m_nShape = GENERIC ; for ( int i = 0 ; i < N_MAPS ; ++ i) { m_nNx[i] = 0 ; m_nNy[i] = 0 ; m_nDim[i] = 0 ; m_dMinZ[i] = 0 ; m_dMaxZ[i] = 0 ; m_nFracLin[i] = 0 ; } return true ; } // Coordinate x,y dell'origine del sistema di riferimento double dNewOx = nMinI[0] * m_dStep ; double dNewOy = nMinJ[0] * m_dStep ; double dNewOz = nMinJ[1] * m_dStep ; // Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali, // infatti i sistemi di riferimento in gioco differiscono al più per una traslazione. for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) { // Quote estreme Z switch ( nMap) { case 0 : dMinZ[nMap] -= dNewOz ; dMaxZ[nMap] -= dNewOz ; break ; case 1 : dMinZ[nMap] -= dNewOx ; dMaxZ[nMap] -= dNewOx ; break ; case 2 : dMinZ[nMap] -= dNewOy ; dMaxZ[nMap] -= dNewOy ; break ; } // Dexel for ( int nD = 0 ; nD < int( nDim[nMap]) ; ++ nD) { for ( int nS = 0 ; nS < int( Values[nMap][nD].size()) ; ++ nS) { switch ( nMap) { case 0 : Values[nMap][nD][nS].dMin -= dNewOz ; Values[nMap][nD][nS].dMax -= dNewOz ; break ; case 1 : Values[nMap][nD][nS].dMin -= dNewOx ; Values[nMap][nD][nS].dMax -= dNewOx ; break ; case 2 : Values[nMap][nD][nS].dMin -= dNewOy ; Values[nMap][nD][nS].dMax -= dNewOy ; break ; } } } } // Ricopio i dexel con gli indici compresi fra gli estremi for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) { m_nNx[nMap] = nNx[nMap] ; m_nNy[nMap] = nNy[nMap] ; m_nDim[nMap] = nDim[nMap] ; m_Values[nMap].resize( 0) ; for ( int nD = 0 ; nD < int( Values[nMap].size()) ; ++ nD) { m_Values[nMap].emplace_back( Values[nMap][nD]) ; } } // Definisco il numero di blocchi lungo x,y e z if ( ! CalcBlockNum()) return false ; // Sistema di riferimento intrinseco del nuovo solido Point3d ptNewO = m_MapFrame.Orig() + Vector3d( dNewOx, dNewOy, dNewOz) ; m_MapFrame.Set( ptNewO, X_AX, Y_AX, Z_AX) ; // Imposto ricalcolo grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::ChangeResolution( int nDexVoxRatio) { if ( nDexVoxRatio < 1 || nDexVoxRatio > 5) return false ; if ( nDexVoxRatio != m_nDexVoxRatio) { int nOldDexVoxRatio = m_nDexVoxRatio ; m_nDexVoxRatio = nDexVoxRatio ; if ( CalcBlockNum()) { ResetGraphics() ; m_OGrMgr.Clear() ; return true ; } m_nDexVoxRatio = nOldDexVoxRatio ; return false ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::CalcBlockNum( void) { // Calcolo il numero di voxel lungo X e Y int nVoxNumX = m_nNx[0] / m_nDexVoxRatio + ( m_nNx[0] % m_nDexVoxRatio == 0 ? 1 : 2) ; int nVoxNumY = m_nNy[0] / m_nDexVoxRatio + ( m_nNy[0] % m_nDexVoxRatio == 0 ? 1 : 2) ; if ( nVoxNumX == 0 || nVoxNumY == 0) return false ; // Definisco il numero di blocchi lungo X e Y m_nFracLin[0] = max( 1, nVoxNumX / m_nVoxNumPerBlock + ( nVoxNumX % m_nVoxNumPerBlock > m_nVoxNumPerBlock / 4 ? 1 : 0)) ; m_nFracLin[1] = max( 1, nVoxNumY / m_nVoxNumPerBlock + ( nVoxNumY % m_nVoxNumPerBlock > m_nVoxNumPerBlock / 4 ? 1 : 0)) ; if ( m_nMapNum == 1) { m_nFracLin[2] = 1 ; m_nNumBlock = m_nFracLin[0] * m_nFracLin[1] * m_nFracLin[2] ; m_BlockToUpdate.clear() ; m_BlockToUpdate.resize( m_nNumBlock, true) ; m_BlockUpdatingCounter.clear() ; m_BlockUpdatingCounter.resize( m_nNumBlock, 0) ; m_SingleMapTria.resize( m_nNumBlock) ; return true ; } // Calcolo il numero di voxel lungo Z int nVoxNumZ = m_nNy[1] / m_nDexVoxRatio + ( m_nNy[1] % m_nDexVoxRatio == 0 ? 1 : 2) ; // Definisco il numero di blocchi lungo Z m_nFracLin[2] = max( 1, nVoxNumZ / m_nVoxNumPerBlock + ( nVoxNumZ % m_nVoxNumPerBlock > m_nVoxNumPerBlock / 4 ? 1 : 0)) ; // Dimensiono e setto il vettore dei blocchi a da ricalcolare e il vettore di contatori di aggiornamenti della grafica m_nNumBlock = m_nFracLin[0] * m_nFracLin[1] * m_nFracLin[2] ; m_BlockToUpdate.clear() ; m_BlockToUpdate.resize( m_nNumBlock, true) ; m_BlockUpdatingCounter.clear() ; m_BlockUpdatingCounter.resize( m_nNumBlock + 1, 0) ; // Dimensiono raccolta di voxel, triangoli di feature tra blocchi e di segnalatori di materiale fra voxel m_InterBlockVox.resize( m_nNumBlock) ; m_InterBlockOriginalSharpTria.resize( m_nNumBlock) ; m_InterBlockSharpTria.resize( m_nNumBlock) ; m_BlockSharpTria.resize( m_nNumBlock) ; m_BlockSmoothTria.resize( m_nNumBlock) ; m_BlockBigTria.resize( m_nNumBlock) ; m_SingleMapTria.resize( m_nNumBlock) ; m_SliceXY.resize( m_nNumBlock) ; m_SliceXZ.resize( m_nNumBlock) ; m_SliceYZ.resize( m_nNumBlock) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::SetToolTolerances( double dLinTol, double dAngTolDeg) { m_dToolLinTol = max( dLinTol, LIN_TOL_MIN) ; m_dToolAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::SetStdTool( const string& sToolName, double dH, double dR, double dCornR, double dCutterH, int nFlag, bool bFirst) { if ( bFirst) { m_vTool.resize( 1) ; m_vTool[0].Clear( true) ; } else m_vTool.emplace_back( true) ; m_nCurrTool = int( m_vTool.size()) - 1 ; if ( m_nCurrTool < 0) return false ; m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ; return m_vTool[m_nCurrTool].SetStdTool( sToolName, dH, dR, dCornR, dCutterH, nFlag) ; } //---------------------------------------------------------------------------- bool VolZmap::SetAdvTool( const string& sToolName, double dH, double dR, double dTipH, double dTipR, double dCornR, double dCutterH, int nFlag, bool bFirst) { if ( bFirst) { m_vTool.resize( 1) ; m_vTool[0].Clear( true) ; } else m_vTool.emplace_back( true) ; m_nCurrTool = int( m_vTool.size()) - 1 ; if ( m_nCurrTool < 0) return false ; m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ; return m_vTool[m_nCurrTool].SetAdvTool( sToolName, dH, dR, dTipH, dTipR, dCornR, dCutterH, nFlag) ; } //---------------------------------------------------------------------------- bool VolZmap::SetSawTool( const string& sToolName, double dH, double dR, double dThick, double dStemR, double dCornR, int nFlag, bool bFirst) { if ( bFirst) { m_vTool.resize( 1) ; m_vTool[0].Clear( true) ; } else m_vTool.emplace_back( true) ; m_nCurrTool = int( m_vTool.size()) - 1 ; if ( m_nCurrTool < 0) return false ; m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ; return m_vTool[m_nCurrTool].SetSawTool( sToolName, dH, dR, dThick, dStemR, dCornR, nFlag) ; } //---------------------------------------------------------------------------- bool VolZmap::SetGenTool( const string& sToolName, const ICurveComposite* pToolOutline, int nFlag, bool bFirst) { if ( bFirst) { m_vTool.resize( 1) ; m_vTool[0].Clear( true) ; } else m_vTool.emplace_back( true) ; m_nCurrTool = int( m_vTool.size()) - 1 ; if ( m_nCurrTool < 0) return false ; m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ; return m_vTool[m_nCurrTool].SetGenTool( sToolName, pToolOutline, nFlag) ; } //---------------------------------------------------------------------------- bool VolZmap::SetMortiserTool( const string& sToolName, double dH, double dW, double dTh, double dRc, int nFlag, bool bFirst) { if ( bFirst) { m_vTool.resize( 1) ; m_vTool[0].Clear( true) ; } else m_vTool.emplace_back( true) ; m_nCurrTool = int( m_vTool.size()) - 1 ; if ( m_nCurrTool < 0) return false ; m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ; return m_vTool[m_nCurrTool].SetMortiserTool( sToolName, dH, dW, dTh, dRc, nFlag) ; } //---------------------------------------------------------------------------- bool VolZmap::SetChiselTool( const string& sToolName, double dH, double dW, double dTh, int nFlag, bool bFirst) { if ( bFirst) { m_vTool.resize( 1) ; m_vTool[0].Clear( true) ; } else m_vTool.emplace_back( true) ; m_nCurrTool = int( m_vTool.size()) - 1 ; if ( m_nCurrTool < 0) return false ; m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ; return m_vTool[m_nCurrTool].SetChiselTool( sToolName, dH, dW, dTh, nFlag) ; } //---------------------------------------------------------------------------- bool VolZmap::SetAdditiveTool( const std::string& sToolName, double dH, double dR, double dRc, int nFlag, bool bFirst) { if ( bFirst) { m_vTool.resize( 1) ; m_vTool[0].Clear( true) ; } else m_vTool.emplace_back( true) ; m_nCurrTool = int( m_vTool.size()) - 1 ; if ( m_nCurrTool < 0) return false ; m_vTool[m_nCurrTool].SetTolerances( m_dToolLinTol, m_dToolAngTolDeg) ; return m_vTool[m_nCurrTool].SetAdditiveTool( sToolName, dH, dR, dRc, nFlag) ; } //---------------------------------------------------------------------------- int VolZmap::GetToolCount( void) const { return m_vTool.size() ; } //---------------------------------------------------------------------------- bool VolZmap::SetCurrTool( int nCurrTool) { if ( nCurrTool < 0 || nCurrTool >= int( m_vTool.size())) return false ; m_nCurrTool = nCurrTool ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::ResetTools( void) { m_vTool.resize( 1) ; m_nCurrTool = 0 ; return m_vTool[0].Clear() ; } //---------------------------------------------------------------------------- const ICurveComposite& VolZmap::GetToolOutline( bool bApprox) const { if ( m_nCurrTool < 0 || m_nCurrTool >= int( m_vTool.size())) { static CurveComposite StatCrvCo ; return StatCrvCo ; } const Tool& CurrTool = m_vTool[m_nCurrTool] ; return ( bApprox ? CurrTool.GetApproxOutline() : CurrTool.GetOutline()) ; }