//---------------------------------------------------------------------------- // EgalTech 2015-2018 //---------------------------------------------------------------------------- // File : VolZmap.cpp Data : 27.01.18 Versione : 1.8a3 // Contenuto : Implementazione della classe Volume Zmap (tre griglie) // // // // Modifiche : 22.01.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveLine.h" #include "VolZmap.h" #include "GeoConst.h" #include "IntersLineSurfTm.h" #include "MC_Tables.h" #include "PolygonPlane.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Extern/Eigen\Core" #include "/EgtDev/Extern/Eigen\SVD" using namespace std ; // ------------------------- UNORDERED MAP PER LA GESTIONE DEI TRIANGOLI GRANDI --------------------------------------------------- // ------------------------- TABELLA BLOCCHI ADIACENTI ---------------------------------------------------------------------------- static int NeighbourTable[8][4] = { {0, -1, -1, -1}, {1, 1, -1, -1}, {1, 1, 2, -1}, {2, 1, 2, -1}, {1, 3, -1, -1}, {2, 1, 3, -1}, {2, 2, 3, -1}, {3, 1, 2, 3} } ; // ------------------------- FUNZIONE TEST SULLE NORMALI -------------------------------------------------------------------------- enum FatureType { NO_FEATURE = 0, CORNER = 1, EDGE = 2} ; enum CanonicDir { X_PLUS = 1, X_MINUS = -1, Y_PLUS = 2, Y_MINUS = -2, Z_PLUS = 3, Z_MINUS = -3} ; //---------------------------------------------------------------------------- int TestOnNormal( const VectorField CompoVert[], int nCompoElem) { // Cerco la massima deviazione tra le normali nei punti della parte connessa int nI, nJ ; double dMinCosTheta = 2 ; for ( int i = 0 ; i < nCompoElem ; ++ i) { for ( int j = i + 1 ; j < nCompoElem ; ++ j) { double dCurrCos = CompoVert[i].vtNorm * CompoVert[j].vtNorm ; if ( dCurrCos < dMinCosTheta) { dMinCosTheta = dCurrCos ; nI = i ; nJ = j ; } } } // Se la massima deviazione non supera il limite non è feature const double SHARP_COS = 0.9 ; if ( dMinCosTheta >= SHARP_COS) return NO_FEATURE ; // Verifico se Edge o Corner // direzione perpendicolare alle normali con massima differenza (potenziale edge) Vector3d vtK = CompoVert[nI].vtNorm ^ CompoVert[nJ].vtNorm ; vtK.Normalize() ; // cerco normale con massima vicinanza al potenziale edge double dMaxAbsCos = 0 ; for ( int i = 0 ; i < nCompoElem ; ++ i) { double dAbsCurrentCos = abs( CompoVert[i].vtNorm * vtK) ; if ( dAbsCurrentCos > dMaxAbsCos) dMaxAbsCos = dAbsCurrentCos ; } // se esiste normale diretta quasi come potenziale edge, allora corner const double CORNER_COS = 0.7 ; if ( dMaxAbsCos > CORNER_COS) return CORNER ; else return EDGE ; } //---------------------------------------------------------------------------- bool CanonicPlaneTest( const VectorField CompoVert[], int nDir, double& dPos, int& nTool) { // Verifico posizione dei punti int nI ; switch ( nDir) { case X_PLUS : case X_MINUS : nI = 0 ; break ; case Y_PLUS : case Y_MINUS : nI = 1 ; break ; case Z_PLUS : case Z_MINUS : nI = 2 ; break ; } double dPos0 = CompoVert[0].ptInt.v[nI] ; double dPos1 = CompoVert[1].ptInt.v[nI] ; double dPos2 = CompoVert[2].ptInt.v[nI] ; double dPos3 = CompoVert[3].ptInt.v[nI] ; dPos = ( dPos0 + dPos1 + dPos2 + dPos3) / 4 ; if ( abs( dPos0 - dPos) > EPS_SMALL || abs( dPos1 - dPos) > EPS_SMALL || abs( dPos2 - dPos) > EPS_SMALL || abs( dPos3 - dPos) > EPS_SMALL) return false ; // Verifico direzione normali Vector3d vtN ; switch ( nDir) { case X_PLUS : vtN = X_AX ; break ; case X_MINUS : vtN = -X_AX ; break ; case Y_PLUS : vtN = Y_AX ; break ; case Y_MINUS : vtN = - Y_AX ; break ; case Z_PLUS : vtN = Z_AX ; break ; case Z_MINUS : vtN = - Z_AX ; break ; } int nDifferent = 0 ; for ( int i = 0 ; i < 4 ; ++ i) { if ( CompoVert[i].vtNorm * vtN < 0.999) return false ; for ( int j = i + 1 ; j < 4 ; ++ j) { if ( CompoVert[i].nToolFlag != CompoVert[j].nToolFlag) ++ nDifferent ; else nTool = CompoVert[i].nToolFlag ; } } if ( nDifferent > 3) return false ; // Superati tutti i test return true ; } //---------------------------------------------------------------------------- bool DotTest( const VectorField CompoVert[], int nCompoElem, Vector3d& vtAvg, double dThreshold = 0) { // Cerco la massima deviazione tra le normali nei punti della parte connessa double dMinCosTheta = 2 ; for ( int i = 0 ; i < nCompoElem ; ++ i) { for ( int j = i + 1 ; j < nCompoElem ; ++ j) { double dCurrCos = CompoVert[i].vtNorm * CompoVert[j].vtNorm ; if ( dCurrCos < dMinCosTheta) { dMinCosTheta = dCurrCos ; } } } // se normali sparpagliate oltre limite if ( dMinCosTheta < dThreshold) return false ; // determino media delle normali vtAvg = V_NULL ; for ( int i = 0 ; i < nCompoElem ; ++ i) vtAvg += CompoVert[i].vtNorm ; vtAvg /= nCompoElem ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::GridControl( VectorField VecField[], VectorField CompoVert[][12], int nIndArrey[][4], int nVertComp[], int nCompCount, bool& bGridControl) const { // Ordino i 4 indici in senso crescente for ( int nSrtInd1 = 0 ; nSrtInd1 < nVertComp[nCompCount - 1] - 1 ; ++ nSrtInd1) { for ( int nSrtInd2 = nSrtInd1 + 1 ; nSrtInd2 < nVertComp[nCompCount - 1] ; ++ nSrtInd2) { if ( nIndArrey[nCompCount - 1][nSrtInd1] > nIndArrey[nCompCount - 1][nSrtInd2]) swap( nIndArrey[nCompCount - 1][nSrtInd1], nIndArrey[nCompCount - 1][nSrtInd2]) ; } } if ( ( nIndArrey[nCompCount - 1][0] == 0 && nIndArrey[nCompCount - 1][1] == 2 && nIndArrey[nCompCount - 1][2] == 9 && nIndArrey[nCompCount - 1][3] == 10) || ( nIndArrey[nCompCount - 1][0] == 4 && nIndArrey[nCompCount - 1][1] == 6 && nIndArrey[nCompCount - 1][2] == 9 && nIndArrey[nCompCount - 1][3] == 10) || ( nIndArrey[nCompCount - 1][0] == 4 && nIndArrey[nCompCount - 1][1] == 6 && nIndArrey[nCompCount - 1][2] == 8 && nIndArrey[nCompCount - 1][3] == 11) || ( nIndArrey[nCompCount - 1][0] == 0 && nIndArrey[nCompCount - 1][1] == 2 && nIndArrey[nCompCount - 1][2] == 8 && nIndArrey[nCompCount - 1][3] == 11) || ( nIndArrey[nCompCount - 1][0] == 1 && nIndArrey[nCompCount - 1][1] == 3 && nIndArrey[nCompCount - 1][2] == 8 && nIndArrey[nCompCount - 1][3] == 9 ) || ( nIndArrey[nCompCount - 1][0] == 1 && nIndArrey[nCompCount - 1][1] == 3 && nIndArrey[nCompCount - 1][2] == 10 && nIndArrey[nCompCount - 1][3] == 11) || ( nIndArrey[nCompCount - 1][0] == 5 && nIndArrey[nCompCount - 1][1] == 7 && nIndArrey[nCompCount - 1][2] == 10 && nIndArrey[nCompCount - 1][3] == 11) || ( nIndArrey[nCompCount - 1][0] == 5 && nIndArrey[nCompCount - 1][1] == 7 && nIndArrey[nCompCount - 1][2] == 8 && nIndArrey[nCompCount - 1][3] == 9 )) { if ( AreSameVectorApprox( VecField[nIndArrey[nCompCount - 1][0]].vtNorm, VecField[nIndArrey[nCompCount - 1][1]].vtNorm) && abs( VecField[nIndArrey[nCompCount - 1][0]].vtNorm * VecField[nIndArrey[nCompCount - 1][2]].vtNorm) < EPS_SMALL && abs( VecField[nIndArrey[nCompCount - 1][0]].vtNorm * VecField[nIndArrey[nCompCount - 1][3]].vtNorm) < EPS_SMALL) { Point3d ptBarycenter = ( CompoVert[nCompCount - 1][0].ptInt + CompoVert[nCompCount - 1][1].ptInt + CompoVert[nCompCount - 1][2].ptInt + CompoVert[nCompCount - 1][3].ptInt) / 4 ; Vector3d vtVecField = VecField[nIndArrey[nCompCount - 1][0]].vtNorm ; if ( vtVecField.x * vtVecField.x > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.x - ptBarycenter.x) < EPS_SMALL) { double dXBar = ptBarycenter.x / m_dStep - 0.5 ; int nBarLimSup = int( m_nNx[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dXInd = double( nBarInd) ; if ( abs( dXInd - dXBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.y * vtVecField.y > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.y - ptBarycenter.y) < EPS_SMALL) { double dYBar = ptBarycenter.y / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dYInd = double( nBarInd) ; if ( abs( dYInd - dYBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.z * vtVecField.z > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.z - ptBarycenter.z) < EPS_SMALL) { double dZBar = ptBarycenter.z / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[1]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dZInd = double( nBarInd) ; if ( abs( dZInd - dZBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } } else if ( AreSameVectorApprox( VecField[nIndArrey[nCompCount - 1][2]].vtNorm, VecField[nIndArrey[nCompCount - 1][3]].vtNorm) && abs( VecField[nIndArrey[nCompCount - 1][2]].vtNorm * VecField[nIndArrey[nCompCount - 1][0]].vtNorm) < EPS_SMALL && abs( VecField[nIndArrey[nCompCount - 1][2]].vtNorm * VecField[nIndArrey[nCompCount - 1][1]].vtNorm) < EPS_SMALL) { Point3d ptBarycenter = ( CompoVert[nCompCount - 1][0].ptInt + CompoVert[nCompCount - 1][1].ptInt + CompoVert[nCompCount - 1][2].ptInt + CompoVert[nCompCount - 1][3].ptInt) / 4 ; Vector3d vtVecField = VecField[nIndArrey[nCompCount - 1][2]].vtNorm ; if ( vtVecField.x * vtVecField.x > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.x - ptBarycenter.x) < EPS_SMALL) { double dXBar = ptBarycenter.x / m_dStep - 0.5 ; int nBarLimSup = int( m_nNx[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dXInd = double( nBarInd) ; if ( abs( dXInd - dXBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.y * vtVecField.y > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.y - ptBarycenter.y) < EPS_SMALL) { double dYBar = ptBarycenter.y / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dYInd = double( nBarInd) ; if ( abs( dYInd - dYBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.z * vtVecField.z > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.z - ptBarycenter.z) < EPS_SMALL) { double dZBar = ptBarycenter.z / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[1]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dZInd = double( nBarInd) ; if ( abs( dZInd - dZBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } } } else if ( ( nIndArrey[nCompCount - 1][0] == 0 && nIndArrey[nCompCount - 1][1] == 1 && nIndArrey[nCompCount - 1][2] == 4 && nIndArrey[nCompCount - 1][3] == 5) || ( nIndArrey[nCompCount - 1][0] == 1 && nIndArrey[nCompCount - 1][1] == 2 && nIndArrey[nCompCount - 1][2] == 5 && nIndArrey[nCompCount - 1][3] == 6) || ( nIndArrey[nCompCount - 1][0] == 2 && nIndArrey[nCompCount - 1][1] == 3 && nIndArrey[nCompCount - 1][2] == 6 && nIndArrey[nCompCount - 1][3] == 7) || ( nIndArrey[nCompCount - 1][0] == 0 && nIndArrey[nCompCount - 1][1] == 3 && nIndArrey[nCompCount - 1][2] == 4 && nIndArrey[nCompCount - 1][3] == 7)) { if ( AreSameVectorApprox( VecField[nIndArrey[nCompCount - 1][0]].vtNorm, VecField[nIndArrey[nCompCount - 1][2]].vtNorm) && abs( VecField[nIndArrey[nCompCount - 1][0]].vtNorm * VecField[nIndArrey[nCompCount - 1][1]].vtNorm) < EPS_SMALL && abs( VecField[nIndArrey[nCompCount - 1][0]].vtNorm * VecField[nIndArrey[nCompCount - 1][3]].vtNorm) < EPS_SMALL) { Point3d ptBarycenter = ( CompoVert[nCompCount - 1][0].ptInt + CompoVert[nCompCount - 1][1].ptInt + CompoVert[nCompCount - 1][2].ptInt + CompoVert[nCompCount - 1][3].ptInt) / 4 ; Vector3d vtVecField = VecField[nIndArrey[nCompCount - 1][0]].vtNorm ; if ( vtVecField.x * vtVecField.x > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.x - ptBarycenter.x) < EPS_SMALL) { double dXBar = ptBarycenter.x / m_dStep - 0.5 ; int nBarLimSup = int( m_nNx[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dXInd = double( nBarInd) ; if ( abs( dXInd - dXBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.y * vtVecField.y > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.y - ptBarycenter.y) < EPS_SMALL) { double dYBar = ptBarycenter.y / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dYInd = double( nBarInd) ; if ( abs( dYInd - dYBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.z * vtVecField.z > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.z - ptBarycenter.z) < EPS_SMALL) { double dZBar = ptBarycenter.z / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[1]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dZInd = double( nBarInd) ; if ( abs( dZInd - dZBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } } else if ( AreSameVectorApprox( VecField[nIndArrey[nCompCount - 1][1]].vtNorm, VecField[nIndArrey[nCompCount - 1][3]].vtNorm) && abs( VecField[nIndArrey[nCompCount - 1][1]].vtNorm * VecField[nIndArrey[nCompCount - 1][0]].vtNorm) < EPS_SMALL && abs( VecField[nIndArrey[nCompCount - 1][1]].vtNorm * VecField[nIndArrey[nCompCount - 1][2]].vtNorm) < EPS_SMALL) { Point3d ptBarycenter = ( CompoVert[nCompCount - 1][0].ptInt + CompoVert[nCompCount - 1][1].ptInt + CompoVert[nCompCount - 1][2].ptInt + CompoVert[nCompCount - 1][3].ptInt) / 4 ; Vector3d vtVecField = VecField[nIndArrey[nCompCount - 1][0]].vtNorm ; if ( vtVecField.x * vtVecField.x > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.x - ptBarycenter.x) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.x - ptBarycenter.x) < EPS_SMALL) { double dXBar = ptBarycenter.x / m_dStep - 0.5 ; int nBarLimSup = int( m_nNx[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dXInd = double( nBarInd) ; if ( abs( dXInd - dXBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.y * vtVecField.y > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.y - ptBarycenter.y) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.y - ptBarycenter.y) < EPS_SMALL) { double dYBar = ptBarycenter.y / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[0]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dYInd = double( nBarInd) ; if ( abs( dYInd - dYBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } else if ( vtVecField.z * vtVecField.z > 1 - EPS_SMALL * EPS_SMALL) { if ( abs( CompoVert[nCompCount - 1][0].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][1].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][2].ptInt.z - ptBarycenter.z) < EPS_SMALL && abs( CompoVert[nCompCount - 1][3].ptInt.z - ptBarycenter.z) < EPS_SMALL) { double dZBar = ptBarycenter.z / m_dStep - 0.5 ; int nBarLimSup = int( m_nNy[1]) ; int nBarInd = 0 ; while ( nBarInd < nBarLimSup) { double dZInd = double( nBarInd) ; if ( abs( dZInd - dZBar) < EPS_SMALL) { bGridControl = false ; break ; } ++ nBarInd ; } } } } } return true ; } // ------------------------- VISUALIZZAZIONE -------------------------------------------------------------------------------------- //---------------------------------------------------------------------------- bool VolZmap::GetDexelLines( int nDir, int nPos1, int nPos2, POLYLINELIST& lstPL) const { // Se richiesti spilloni ( 0 <= nDir < 3) if ( nDir < 3) { // Controllo l'ammissibilità della griglia if ( nDir < 0 || nDir > 2) return false ; // Verifiche sugli indici if ( nPos1 < 0 || nPos1 >= int( m_nNx[nDir]) || nPos2 < 0 || nPos2 >= int( m_nNy[nDir])) return false ; int nPos = nPos1 + nPos2 * m_nNx[nDir] ; if ( nPos < 0 || nPos >= int( m_Values[nDir].size())) return false ; // Definisco un sistema di riferimento opportuno Frame3d frMapFrame ; if ( nDir == 0) frMapFrame = m_MapFrame ; else if ( nDir == 1) frMapFrame.Set( m_MapFrame.Orig(), m_MapFrame.VersY(), m_MapFrame.VersZ(), m_MapFrame.VersX()) ; else if ( nDir == 2) frMapFrame.Set( m_MapFrame.Orig(), m_MapFrame.VersZ(), m_MapFrame.VersX(), m_MapFrame.VersY()) ; // Calcolo coordinate punto double dX = m_dStep * ( 0.5 + nPos1) ; double dY = m_dStep * ( 0.5 + nPos2) ; // Determino il punto di partenza sulla griglia Point3d ptP = frMapFrame.Orig() + dX * frMapFrame.VersX() + dY * frMapFrame.VersY() ; // Creo le polilinee for ( int j = 0 ; j < int( m_Values[nDir][nPos].size()) ; j += 1) { // aggiungo polilinea a lista lstPL.emplace_back() ; // inserisco punti estremi lstPL.back().AddUPoint( 0, ptP + m_Values[nDir][nPos][j].dMin * frMapFrame.VersZ()) ; lstPL.back().AddUPoint( 1, ptP + m_Values[nDir][nPos][j].dMax * frMapFrame.VersZ()) ; } return true ; } // altrimenti richieste normali ( 3 <= nDir < 6) else { // riporto a indice griglia nDir -= 3 ; // Controllo l'ammissibilità della griglia if ( nDir < 0 || nDir > 2) return false ; // Verifiche sugli indici if ( nPos1 < 0 || nPos1 >= int( m_nNx[nDir]) || nPos2 < 0 || nPos2 >= int( m_nNy[nDir])) return false ; int nPos = nPos1 + nPos2 * m_nNx[nDir] ; if ( nPos < 0 || nPos >= int( m_Values[nDir].size())) return false ; // Definisco un sistema di riferimento opportuno Frame3d frMapFrame ; if ( nDir == 0) frMapFrame = m_MapFrame ; else if ( nDir == 1) frMapFrame.Set( m_MapFrame.Orig(), m_MapFrame.VersY(), m_MapFrame.VersZ(), m_MapFrame.VersX()) ; else if ( nDir == 2) frMapFrame.Set( m_MapFrame.Orig(), m_MapFrame.VersZ(), m_MapFrame.VersX(), m_MapFrame.VersY()) ; // Calcolo coordinate punto double dX = m_dStep * ( 0.5 + nPos1) ; double dY = m_dStep * ( 0.5 + nPos2) ; // Determino il punto di partenza sulla griglia Point3d ptP = frMapFrame.Orig() + dX * frMapFrame.VersX() + dY * frMapFrame.VersY() ; // Creo le polilinee for ( int j = 0 ; j < int( m_Values[nDir][nPos].size()) ; j += 1) { // aggiungo polilinea a lista lstPL.emplace_back() ; // calcolo e inserisco punto inizio spillone Point3d ptQ = ptP + m_Values[nDir][nPos][j].dMin * frMapFrame.VersZ() ; lstPL.back().AddUPoint( 0, ptQ) ; // calcolo e inserisco punto su termine sua normale Vector3d vtV = m_Values[nDir][nPos][j].vtMinN ; vtV.ToGlob( m_MapFrame) ; lstPL.back().AddUPoint( 1, ptQ + vtV * m_dStep / 4) ; // aggiungo polilinea a lista lstPL.emplace_back() ; // calcolo e inserisco punto fine spillone Point3d ptR = ptP + m_Values[nDir][nPos][j].dMax * frMapFrame.VersZ() ; lstPL.back().AddUPoint( 0, ptR) ; // calcolo e inserisco punto su termine sua normale Vector3d vtW = m_Values[nDir][nPos][j].vtMaxN ; vtW.ToGlob( m_MapFrame) ; lstPL.back().AddUPoint( 1, ptR + vtW * m_dStep / 4) ; } return true ; } } //---------------------------------------------------------------------------- bool VolZmap::GetAllTriangles( TRIA3DEXLIST& lstTria) const { INTVECTOR nModifiedBlocks ; TRIA3DEXLISTVECTOR vLstTria ; if ( ! GetTriangles( true, nModifiedBlocks, vLstTria)) return false ; lstTria.clear() ; for ( size_t i = 0 ; i < vLstTria.size() ; ++ i) { lstTria.splice( lstTria.end(), vLstTria[i]) ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetTriangles( bool bAllBlocks, INTVECTOR& nModifiedBlocks, TRIA3DEXLISTVECTOR& vLstTria) const { // Se nessun blocco modificato, è richiesta esterna e li considero tutti modificati bool bSomeModif = false ; for ( size_t i = 0 ; i < m_nNumBlock ; ++ i) { if ( m_BlockToUpdate[i]) { bSomeModif = true ; break ; } } if ( ! bSomeModif) bAllBlocks = true ; // Caso di singola mappa if ( m_nMapNum == 1) { const int MAX_DIM_CHUNK = 128 ; nModifiedBlocks.resize( m_nNumBlock) ; vLstTria.reserve( m_nNumBlock) ; // Ciclo sui blocchi for ( size_t t = 0 ; t < m_nNumBlock ; ++ t) { // Se il blocco deve essere aggiornato, eseguo if ( bAllBlocks || m_BlockToUpdate[t]) { // preparo lista vLstTria.emplace_back() ; nModifiedBlocks[t] = int( vLstTria.size()) - 1 ; // Calcolo posizione del blocco nella griglia int nIBlock = int( t) % int( m_nFracLin[0]) ; int nJBlock = int( t) / int( m_nFracLin[0]) ; // Calcolo limiti per l'indice i int nStartI = nIBlock * int( m_nVoxNumPerBlock) * N_DEXVOXRATIO ; int nEndI = ( nIBlock + 1 == int( m_nFracLin[0]) ? int( m_nNx[0]) : ( nIBlock + 1) * int( m_nVoxNumPerBlock)) * N_DEXVOXRATIO ; // Calcolo limiti per l'indice j int nStartJ = nJBlock * int( m_nVoxNumPerBlock) * N_DEXVOXRATIO ; int nEndJ = ( nJBlock + 1 == int( m_nFracLin[1]) ? int( m_nNy[0]) : ( nJBlock + 1) * int( m_nVoxNumPerBlock)) * N_DEXVOXRATIO ; // Ciclo su i e j for ( int i = nStartI ; i < nEndI ; i += MAX_DIM_CHUNK) { int nDimChunkX = min( MAX_DIM_CHUNK, nEndI - i) ; for ( int j = nStartJ ; j < nEndJ ; j += MAX_DIM_CHUNK) { int nDimChunkY = min( MAX_DIM_CHUNK, nEndJ - j) ; GetChunkPrisms( i, j, nDimChunkX, nDimChunkY, MAX_DIM_CHUNK, vLstTria.back()) ; } } m_BlockToUpdate[t] = false ; } else nModifiedBlocks[t] = -1 ; } } // Caso con tre mappe else { nModifiedBlocks.resize( m_nNumBlock + 1) ; vLstTria.reserve( m_nNumBlock + 1) ; TriaMatrix VecTriHold ; VecTriHold.resize( m_nNumBlock) ; bool bCalcInterBlock = false ; // Calcolo i triangoli sui blocchi for ( size_t t = 0 ; t < m_nNumBlock ; ++ t) { // Se il blocco deve essere processato if ( bAllBlocks || m_BlockToUpdate[t]) { // processo ... vLstTria.emplace_back() ; nModifiedBlocks[t] = int( vLstTria.size()) - 1 ; m_InterBlockTria[t].clear() ; ExtMarchingCubes( int( t), vLstTria.back(), VecTriHold[t]) ; // Flipping fra voxel interni FlipEdgesII( VecTriHold[t]) ; bCalcInterBlock = true ; m_BlockToUpdate[t] = false ; } else nModifiedBlocks[t] = -1 ; } // Calcolo i triangoli di frontiera tra feature di blocchi diversi // copio i triangoli di frontiera in una matrice gemella // di m_InterBlockTria per avere sempre a disposizione // i triangoli non flippati. TriaMatrix InterBlockTria ; if ( bCalcInterBlock) { InterBlockTria = m_InterBlockTria ; FlipEdgesBB( InterBlockTria) ; } // Inserisco in lista i triangoli di feature derivanti dai blocchi for ( size_t t = 0 ; t < m_nNumBlock ; ++ t) { if ( nModifiedBlocks[t] >= 0) { // ciclo sui voxel del blocco for ( size_t t1 = 0 ; t1 < VecTriHold[t].size() ; ++ t1) { // ciclo sulle componenti connesse del voxel for ( size_t t2 = 0 ; t2 < VecTriHold[t][t1].vCompoTria.size() ; ++ t2) { // ciclo sui triangoli delle componenti connesse for ( size_t t3 = 0 ; t3 < VecTriHold[t][t1].vCompoTria[t2].size() ; ++ t3) { // Controllo normali Vector3d vtN = VecTriHold[t][t1].vCompoTria[t2][t3].GetN() ; bool bNormN = vtN.IsNormalized() ; for ( int nV = 0 ; nV < 3 ; ++ nV) { Vector3d vtNV = VecTriHold[t][t1].vCompoTria[t2][t3].GetVertexNorm( nV) ; bool bNormV = vtNV.IsNormalized() ; if ( bNormN && bNormV && vtN * vtNV < 0.7) VecTriHold[t][t1].vCompoTria[t2][t3].SetVertexNorm( nV, vtN) ; } // aggiungo triangolo alla lista vLstTria[nModifiedBlocks[t]].emplace_back( VecTriHold[t][t1].vCompoTria[t2][t3]) ; } } } } } // Inserisco in lista i triangoli di frontiera tra feature di blocchi diversi if ( bCalcInterBlock) { vLstTria.resize( vLstTria.size() + 1) ; size_t nPos = size_t( vLstTria.size() - 1) ; for ( size_t t = 0 ; t < InterBlockTria.size() ; ++ t) { for ( size_t t1 = 0 ; t1 < InterBlockTria[t].size() ; ++ t1) { for ( size_t t2 = 0 ; t2 < InterBlockTria[t][t1].vCompoTria.size() ; ++ t2) { for ( size_t t3 = 0 ; t3 < InterBlockTria[t][t1].vCompoTria[t2].size() ; ++ t3) { if ( InterBlockTria[t][t1].vCompoTria[t2][t3].GetArea() > SQ_EPS_SMALL) { // Controllo normali Vector3d vtN = InterBlockTria[t][t1].vCompoTria[t2][t3].GetN() ; bool bNormN = vtN.IsNormalized() ; for ( int nV = 0 ; nV < 3 ; ++ nV) { Vector3d vtNV = InterBlockTria[t][t1].vCompoTria[t2][t3].GetVertexNorm( nV) ; bool bNormV = vtNV.IsNormalized() ; if ( bNormN && bNormV && vtN * vtNV < 0.7) InterBlockTria[t][t1].vCompoTria[t2][t3].SetVertexNorm( nV, vtN) ; } // aggiungo triangolo alla lista vLstTria[nPos].emplace_back( InterBlockTria[t][t1].vCompoTria[t2][t3]) ; } } } } } nModifiedBlocks.back() = int( nPos) ; } else nModifiedBlocks.back() = - 1 ; } return true ; } //---------------------------------------------------------------------------- int VolZmap::GetBlockCount( void) const { return m_nNumBlock + ( m_nMapNum == 1 ? 0 : 1) ; } //---------------------------------------------------------------------------- bool VolZmap::GetChunkPrisms( int nPos1, int nPos2, int nDim1, int nDim2, int nDimChk, TRIA3DEXLIST& lstTria) const { // determino se è un semplice parallelepipedo bool bIsSimple = true ; double dBotZ ; double dTopZ ; for ( int i = 0 ; i < nDim1 && bIsSimple ; ++ i) { for ( int j = 0 ; j < nDim2 && bIsSimple ; ++ j) { int nPos = ( nPos1 + i) + ( nPos2 + j) * m_nNx[0] ; if ( nPos > int( m_nDim[0]) || int( m_Values[0][nPos].size()) != 1) bIsSimple = false ; else if ( i == 0 && j == 0) { dBotZ = m_Values[0][nPos][0].dMin ; dTopZ = m_Values[0][nPos][0].dMax ; } else if ( abs( m_Values[0][nPos][0].dMin - dBotZ) > EPS_SMALL || abs( m_Values[0][nPos][0].dMax - dTopZ) > EPS_SMALL) bIsSimple = false ; } } // se semplice parallelepipedo if ( bIsSimple) { CalcChunkPrisms( nPos1, nPos2, nDim1, nDim2, lstTria) ; } // se chunk di dimensioni accettabili else if ( nDimChk >= 4) { int nNewDimChk = nDimChk / 2 ; for ( int i = nPos1 ; i < int( nPos1 + nDim1) ; i += nNewDimChk) { int nDimChunkX = min( nNewDimChk, int( nPos1 + nDim1) - i) ; for ( int j = nPos2 ; j < int( nPos2 + nDim2) ; j += nNewDimChk) { int nDimChunkY = min( nNewDimChk, int( nPos2 + nDim2) - j) ; GetChunkPrisms( i, j, nDimChunkX, nDimChunkY, nNewDimChk, lstTria) ; } } } // altrimenti else { // elaboro ogni singolo dexel for ( int i = 0 ; i < nDim1 ; ++ i) { for ( int j = 0 ; j < nDim2 ; ++ j) { CalcDexelPrisms( nPos1 + i, nPos2 + j, lstTria) ; } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::CalcChunkPrisms( int nPos1, int nPos2, int nDim1, int nDim2, TRIA3DEXLIST& lstTria) const { // verifiche sugli indici if ( nPos1 < 0 || nPos1 + nDim1 > int( m_nNx[0]) || nPos2 < 0 || nPos2 + nDim2 > int( m_nNy[0])) return false ; int nPos = nPos1 + nPos2 * m_nNx[0] ; if ( nPos < 0 || nPos >= int( m_nDim[0])) return false ; // calcolo coordinate punti double dX = m_dStep * nPos1 ; double dY = m_dStep * nPos2 ; Point3d ptP1 = m_MapFrame.Orig() + dX * m_MapFrame.VersX() + dY * m_MapFrame.VersY() ; Point3d ptP2 = ptP1 + nDim1 * m_dStep * m_MapFrame.VersX() ; Point3d ptP3 = ptP2 + nDim2 * m_dStep * m_MapFrame.VersY() ; Point3d ptP4 = ptP1 + nDim2 * m_dStep * m_MapFrame.VersY() ; // creo le facce sopra e sotto Vector3d vtDZt = m_Values[0][nPos][0].dMax * m_MapFrame.VersZ() ; Vector3d vtDZb = m_Values[0][nPos][0].dMin * m_MapFrame.VersZ() ; // faccia superiore P1t->P2t->P3t->P4t : sempre visibile lstTria.emplace_back() ; lstTria.back().Set( ptP1 + vtDZt, ptP2 + vtDZt, ptP3 + vtDZt, m_MapFrame.VersZ()) ; lstTria.emplace_back() ; lstTria.back().Set( ptP3 + vtDZt, ptP4 + vtDZt, ptP1 + vtDZt, m_MapFrame.VersZ()) ; // faccia inferiore P1b->P4b->P3b->P2b : sempre visibile lstTria.emplace_back() ; lstTria.back().Set( ptP1 + vtDZb, ptP4 + vtDZb, ptP3 + vtDZb, - m_MapFrame.VersZ()) ; lstTria.emplace_back() ; lstTria.back().Set( ptP3 + vtDZb, ptP2 + vtDZb, ptP1 + vtDZb, - m_MapFrame.VersZ()) ; // creo le facce laterali for ( int j = 0 ; j < nDim2 ; ++ j) { int nPosD = nPos + nDim1 - 1 + j * m_nNx[0] ; int nPosEst = ( nPos1 + nDim1 - 1 < int( m_nNx[0] - 1) ? nPosD + 1 : - 1) ; Point3d ptP2D = ptP2 + j * m_dStep * m_MapFrame.VersY() ; Point3d ptP3D = ptP2D + m_dStep * m_MapFrame.VersY() ; AddDexelSideFace( nPosD, nPosEst, ptP2D, ptP3D, m_MapFrame.VersZ(), m_MapFrame.VersX(), lstTria) ; } for ( int i = 0 ; i < nDim1 ; ++ i) { int nPosD = nPos + ( nDim2 - 1) * m_nNx[0] + i ; int nPosNord = ( nPos2 + nDim2 - 1 < int( m_nNy[0] - 1) ? nPosD + m_nNx[0] : - 1) ; Point3d ptP4D = ptP4 + i * m_dStep * m_MapFrame.VersX() ; Point3d ptP3D = ptP4D + m_dStep * m_MapFrame.VersX() ; AddDexelSideFace( nPosD, nPosNord, ptP3D, ptP4D, m_MapFrame.VersZ(), m_MapFrame.VersY(), lstTria) ; } for ( int j = 0 ; j < nDim2 ; ++ j) { int nPosD = nPos + j * m_nNx[0] ; int nPosWest = ( nPos1 > 0 ? nPosD - 1 : - 1) ; Point3d ptP1D = ptP1 + j * m_dStep * m_MapFrame.VersY() ; Point3d ptP4D = ptP1D + m_dStep * m_MapFrame.VersY() ; AddDexelSideFace( nPosD, nPosWest, ptP4D, ptP1D, m_MapFrame.VersZ(), - m_MapFrame.VersX(), lstTria) ; } for ( int i = 0 ; i < nDim1 ; ++ i) { int nPosD = nPos + i ; int nPosSud = ( nPos2 > 0 ? nPosD - m_nNx[0] : - 1) ; Point3d ptP1D = ptP1 + i * m_dStep * m_MapFrame.VersX() ; Point3d ptP2D = ptP1D + m_dStep * m_MapFrame.VersX() ; AddDexelSideFace( nPosD, nPosSud, ptP1D, ptP2D, m_MapFrame.VersZ(), - m_MapFrame.VersY(), lstTria) ; } // return true ; } //---------------------------------------------------------------------------- bool VolZmap::CalcDexelPrisms( int nPos1, int nPos2, TRIA3DEXLIST& lstTria) const { // verifiche sugli indici if ( nPos1 < 0 || nPos1 >= int( m_nNx[0]) || nPos2 < 0 || nPos2 >= int( m_nNy[0])) return false ; int nPos = nPos1 + nPos2 * m_nNx[0] ; if ( nPos < 0 || nPos >= int( m_nDim[0])) return false ; // calcolo coordinate punto double dX = m_dStep * nPos1 ; double dY = m_dStep * nPos2 ; Point3d ptP1 = m_MapFrame.Orig() + dX * m_MapFrame.VersX() + dY * m_MapFrame.VersY() ; Point3d ptP2 = ptP1 + m_dStep * m_MapFrame.VersX() ; Point3d ptP3 = ptP2 + m_dStep * m_MapFrame.VersY() ; Point3d ptP4 = ptP1 + m_dStep * m_MapFrame.VersY() ; // creo le facce sopra e sotto di ogni intervallo (sempre visibili) for ( int i = 0 ; i < int( m_Values[0][nPos].size()) ; i += 1) { Vector3d vtDZt = m_Values[0][nPos][i].dMax * m_MapFrame.VersZ() ; Vector3d vtDZb = m_Values[0][nPos][i].dMin * m_MapFrame.VersZ() ; // faccia superiore P1t->P2t->P3t->P4t : sempre visibile lstTria.emplace_back() ; lstTria.back().Set( ptP1 + vtDZt, ptP2 + vtDZt, ptP3 + vtDZt, m_MapFrame.VersZ()) ; lstTria.emplace_back() ; lstTria.back().Set( ptP3 + vtDZt, ptP4 + vtDZt, ptP1 + vtDZt, m_MapFrame.VersZ()) ; // faccia inferiore P1b->P4b->P3b->P2b : sempre visibile lstTria.emplace_back() ; lstTria.back().Set( ptP1 + vtDZb, ptP4 + vtDZb, ptP3 + vtDZb, - m_MapFrame.VersZ()) ; lstTria.emplace_back() ; lstTria.back().Set( ptP3 + vtDZb, ptP2 + vtDZb, ptP1 + vtDZb, - m_MapFrame.VersZ()) ; } // creo le facce laterali int nPosEst = ( nPos1 < int( m_nNx[0] - 1) ? nPos + 1 : - 1) ; AddDexelSideFace( nPos, nPosEst, ptP2, ptP3, m_MapFrame.VersZ(), m_MapFrame.VersX(), lstTria) ; int nPosNord = ( nPos2 < int( m_nNy[0] - 1) ? nPos + m_nNx[0] : - 1) ; AddDexelSideFace( nPos, nPosNord, ptP3, ptP4, m_MapFrame.VersZ(), m_MapFrame.VersY(), lstTria) ; int nPosWest = ( nPos1 > 0 ? nPos - 1 : - 1) ; AddDexelSideFace( nPos, nPosWest, ptP4, ptP1, m_MapFrame.VersZ(), - m_MapFrame.VersX(), lstTria) ; int nPosSud = ( nPos2 > 0 ? nPos - m_nNx[0] : - 1) ; AddDexelSideFace( nPos, nPosSud, ptP1, ptP2, m_MapFrame.VersZ(), - m_MapFrame.VersY(), lstTria) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::AddDexelSideFace( int nPos, int nPosAdj, const Point3d& ptP, const Point3d& ptQ, const Vector3d& vtZ, const Vector3d& vtNorm, TRIA3DEXLIST& lstTria) const { Intervals intFace ; for ( int i = 0 ; i < int( m_Values[0][nPos].size()) ; i += 1) intFace.Add( m_Values[0][nPos][i].dMin, m_Values[0][nPos][i].dMax) ; if ( nPosAdj > 0) { for ( int i = 0 ; i < int( m_Values[0][nPosAdj].size()) ; i += 1) intFace.Subtract( m_Values[0][nPosAdj][i].dMin, m_Values[0][nPosAdj][i].dMax) ; } double dMin, dMax ; bool bFound = intFace.GetFirst( dMin, dMax) ; while ( bFound) { Vector3d vtDZt = dMax * vtZ ; Vector3d vtDZb = dMin * vtZ ; lstTria.emplace_back() ; lstTria.back().Set( ptP + vtDZb, ptQ + vtDZb, ptQ + vtDZt, vtNorm) ; lstTria.emplace_back() ; lstTria.back().Set( ptQ + vtDZt, ptP + vtDZt, ptP + vtDZb, vtNorm) ; bFound = intFace.GetNext( dMin, dMax) ; } return true ; } //---------------------------------------------------------------------------- // Calcola i triangoli del voxel con indici nVoxI, nVoxJ, nVoxK; se si vuole // il riconoscimento delle sharp-feature bEnh deve valere true. // I triangoli formanti sharp-feature vengono messi nel TriHolder, gli altri nella lista. bool VolZmap::ProcessCube( int nVoxI, int nVoxJ, int nVoxK, TRIA3DEXLIST& lstTria, TriHolder& triHold, bool bEnh) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Se il voxel non esiste, vi è un errore. if ( nVoxI + 1 < 0 || nVoxI + 2 > nVoxNumX || nVoxJ + 1 < 0 || nVoxJ + 2 > nVoxNumY || nVoxK + 1 < 0 || nVoxK + 2 > nVoxNumZ) return false ; // Classificazione dei vertici: interni o esterni al materiale int nIndex = CalcIndex( nVoxI, nVoxJ , nVoxK) ; // Se vi è qualche intersezione fra segmenti e superficie // continuo altrimenti passo al prossimo voxel. if ( EdgeTable[nIndex] != 0) { // Indici i,j,k dei vertici int IndexCorner[8][3] = { { nVoxI, nVoxJ, nVoxK}, { nVoxI + 1, nVoxJ, nVoxK}, { nVoxI + 1, nVoxJ + 1, nVoxK}, { nVoxI, nVoxJ + 1, nVoxK}, { nVoxI, nVoxJ, nVoxK + 1}, { nVoxI + 1, nVoxJ, nVoxK + 1}, { nVoxI + 1, nVoxJ + 1, nVoxK + 1}, { nVoxI, nVoxJ + 1, nVoxK + 1} } ; static int intersections[12][2] = { { 0, 1 }, { 1, 2 }, { 3, 2 }, { 0, 3 }, { 4, 5 }, { 5, 6 }, { 7, 6 }, { 4, 7 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } } ; // Array di strutture punto di intersezione e normale alla superficie in esso. VectorField VecField[12] ; // Flag di regolarità dei campi scalare e vettoriale bool bReg = true ; // Ciclo sui segmenti for ( int EdgeIndex = 0 ; EdgeIndex < 12 ; ++ EdgeIndex) { // Se il segmento non attraversa la superficie passo al successivo if ( ( EdgeTable[nIndex] & ( 1 << EdgeIndex)) == 0) continue ; // Indici per linee di griglia sui vertici int n1 = intersections[EdgeIndex][0] ; int n2 = intersections[EdgeIndex][1] ; // Flag posizione corner bool bN1 = ( ( nIndex & ( 1 << n1)) != 0) ; // Determino con precisione il punto di intersezione sullo spigolo, // se i campi scalare e vettoriale non sono regolari bReg diviene falso. if ( ! IntersPos( IndexCorner[n1], IndexCorner[n2], bN1, VecField[EdgeIndex])) bReg = false ; } // Determino il numero di componenti connesse nel voxel in caso di configurazione standard int nComponents = TriangleTableEn[nIndex][1][0] ; // Matrici di campi vettoriali: // CompoVert[i] ha i vertici della base del triangle fan della (i+1)-esima componente connessa; // CompoTriVert[i] ha i vertici di tutti i triangoli, nel caso di assenza di sharp feature, // della (i+1)-esima componente connessa. VectorField CompoVert[6][12] ; VectorField CompoTriVert[6][17] ; // Arrey numero di vertici della base del fan per componente // connessa: nVertComp[i] contiene il numero di vertici // della base del fan della (i+1)-esima componente connessa. int nVertComp[6] ; // Matrice di indici dei punti: serve per la gestione del caso int nIndArrey[6][4] ; int nExtTabOff = nComponents ; int nStdTabOff = 0 ; // Carico le matrici CompoVert e CompoTriVert for ( int nCompCount = 1 ; nCompCount <= nComponents ; ++ nCompCount) { // Numero vertici per componenti nVertComp[nCompCount - 1] = TriangleTableEn[nIndex][1][nCompCount] ; // Riempio il nCompCount-esimo vettore di vertici della base del fan for ( int nVertCount = 0 ; nVertCount < nVertComp[nCompCount - 1] ; ++ nVertCount) CompoVert[nCompCount - 1][nVertCount] = VecField[TriangleTableEn[nIndex][1][nVertCount + nExtTabOff + 1]] ; // Serve per la gestione del caso ... if ( nVertComp[nCompCount - 1] == 4) { for ( int nVertCount = 0 ; nVertCount < nVertComp[nCompCount - 1] ; ++ nVertCount) nIndArrey[nCompCount - 1][nVertCount] = TriangleTableEn[nIndex][1][nVertCount + nExtTabOff + 1] ; } // Riempio il nCompCount-esimo vettore di vertici dei triangoli in assenza di // sharp feature: in una mesh di triangoli con n vertici vi sono n - 2 triangoli. for ( int nVertCount = 0 ; nVertCount < 3 * ( nVertComp[nCompCount - 1] - 2) ; nVertCount += 3) { CompoTriVert[nCompCount - 1][nVertCount] = VecField[TriangleTableEn[nIndex][0][nStdTabOff + nVertCount+2]] ; CompoTriVert[nCompCount - 1][nVertCount+1] = VecField[TriangleTableEn[nIndex][0][nStdTabOff + nVertCount+1]] ; CompoTriVert[nCompCount - 1][nVertCount+2] = VecField[TriangleTableEn[nIndex][0][nStdTabOff + nVertCount]] ; } // Aggiorno gli offsets per raggiungere i // vertici della componente successiva. nExtTabOff += nVertComp[nCompCount - 1] ; nStdTabOff += 3 * ( nVertComp[nCompCount - 1] - 2) ; } // Test sulla topologia: dal momento che il nostro test // si fonda sugli angoli compresi fra le normali, esso ha // senso solo se il campo è regolare. // Il flag bSecondConfig6 serve perché nel caso di configurazione 6 // con una sola componente connessa non si deve eseguire l'Extended MC. bool bSecondConfig6 = false ; if ( bReg) { if ( nAllConfig[nIndex] == 3) { Vector3d vtCmpAvg0, vtCmpAvg1 ; // Verifico se i versori delle componenti sono tutti // più o meno concordi (per esserlo non devono esserci // due vettori di una medesima componente con prodotto // scalare inferiore a 0.7). bool bTest0 = DotTest( CompoVert[0], 3, vtCmpAvg0, 0.7) ; bool bTest1 = DotTest( CompoVert[1], 3, vtCmpAvg1, 0.7) ; // Se i versori di entrambe le componenti sono concordi // ha senso parlare di vettori medi, altrimenti non ha // senso. Se non ha senso parlare di vettori medi non // ha senso parlare di prodotti scalari fra loro, // quindi pongo il loro prodotto a un valore assurdo -2 // (il prodotto scalare fra versori ha modulo non superiore // a uno). double dScProd = - 2 ; if ( bTest0 && bTest1) dScProd = vtCmpAvg0 * vtCmpAvg1 ; double dThreshold = 0.7 ; if ( ! ( bTest0 && bTest1) || ( bTest0 && bTest1 && dScProd > dThreshold)) { int nt = 0 ; while ( nIndexVsIndex3[nt][0] != nIndex) ++ nt ; int nRotCase = nIndexVsIndex3[nt][1] ; nComponents = Cases3Plus[nRotCase][1][0] ; // Riaggiorno gli offsets nExtTabOff = nComponents ; nStdTabOff = 0 ; // Modifico le matrici for ( int nC = 1 ; nC <= nComponents ; ++ nC) { // Numero vertici per componenti nVertComp[nC - 1] = Cases3Plus[nRotCase][1][nC] ; // Matrice dei vertici della base del fan for ( int nFanVert = 0 ; nFanVert < nVertComp[nC - 1] ; ++ nFanVert) CompoVert[nC - 1][nFanVert] = VecField[Cases3Plus[nRotCase][1][nFanVert + nExtTabOff + 1]] ; // Matrici dei vertici dei triangoli in assenza di sharp feature for ( int nTriVert = 0 ; nTriVert < 3 * ( nVertComp[nC - 1] - 2) ; nTriVert += 3) { CompoTriVert[nC - 1][nTriVert] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert+2]] ; CompoTriVert[nC - 1][nTriVert+1] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert+1]] ; CompoTriVert[nC - 1][nTriVert+2] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert]] ; } // Aggiorno gli offsets per raggiungere i // vertici della componente successiva. nExtTabOff += nVertComp[nC - 1] ; nStdTabOff += 3 * ( nVertComp[nC - 1] - 2) ; } } } else if ( nAllConfig[nIndex] == 6) { // Procedura analoga a quella della configurazione 3 Vector3d vtCmpAvg0, vtCmpAvg1 ; bool bTest0 = DotTest( CompoVert[0], 4, vtCmpAvg0, 0.7) ; bool bTest1 = DotTest( CompoVert[1], 3, vtCmpAvg1, 0.7) ; double dScProd = - 2 ; if ( bTest0 && bTest1) dScProd = vtCmpAvg0 * vtCmpAvg1 ; double dThreshold = 0.7 ; if ( ! ( bTest0 && bTest1) || ( bTest0 && bTest1 && dScProd > dThreshold)) { int nt = 0 ; while ( nIndexVsIndex6[nt][0] != nIndex) ++ nt ; int nRotCase = nIndexVsIndex6[nt][1] ; nComponents = 1 ; // Riaggiorno gli offsets nExtTabOff = nComponents ; nStdTabOff = 0 ; // Modifico le matrici for ( int nC = 1 ; nC <= nComponents ; ++ nC) { // Numero vertici per componenti nVertComp[nC - 1] = 7 ; // Matrici dei vertici dei triangoli in assenza di sharp feature for ( int nTriVert = 0 ; nTriVert < 3 * ( nVertComp[nC - 1] - 2) ; nTriVert += 3) { CompoTriVert[nC - 1][nTriVert] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert+2]] ; CompoTriVert[nC - 1][nTriVert+1] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert+1]] ; CompoTriVert[nC - 1][nTriVert+2] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert]] ; } // Aggiorno gli offsets per raggiungere i // vertici della componente successiva. nExtTabOff += nVertComp[nC - 1] ; nStdTabOff += 3 * ( nVertComp[nC - 1] - 2) ; } bSecondConfig6 = true ; } } else if ( nAllConfig[nIndex] == 10) { Vector3d vtCmpAvg0, vtCmpAvg1 ; // Verifico se i versori delle componenti sono tutti // più o meno concordi (per esserlo non devono esserci // due vettori di una medesima componente con prodotto // scalare inferiore a 0). decidere se 0.0 o 0.7 bool bTest0 = DotTest( CompoVert[0], 4, vtCmpAvg0) ; bool bTest1 = DotTest( CompoVert[1], 4, vtCmpAvg1) ; if ( ! ( bTest0 && bTest1)) { int nt = 0 ; while ( nIndexVsIndex10[nt][0] != nIndex) ++ nt ; int nRotCase = nIndexVsIndex10[nt][1] ; // Riaggiorno gli offsets nExtTabOff = 2 ; nStdTabOff = 0 ; // Modifico le matrici for ( int nC = 1 ; nC <= 2 ; ++ nC) { // Numero vertici per componenti nVertComp[nC - 1] = Cases10Plus[nRotCase][1][nC] ; // Matrice dei vertici della base del fan for ( int nFanVert = 0 ; nFanVert < 4 ; ++ nFanVert) CompoVert[nC - 1][nFanVert] = VecField[Cases10Plus[nRotCase][1][nFanVert + nExtTabOff + 1]] ; // Matrici dei vertici dei triangoli in assenza di sharp feature for ( int nTriVert = 0 ; nTriVert < 6 ; nTriVert += 3) { CompoTriVert[nC - 1][nTriVert] = VecField[Cases10Plus[nRotCase][0][nStdTabOff + nTriVert+2]] ; CompoTriVert[nC - 1][nTriVert+1] = VecField[Cases10Plus[nRotCase][0][nStdTabOff + nTriVert+1]] ; CompoTriVert[nC - 1][nTriVert+2] = VecField[Cases10Plus[nRotCase][0][nStdTabOff + nTriVert]] ; } // Aggiorno gli offsets per raggiungere i vertici della componente successiva. nExtTabOff += nVertComp[nC - 1] ; nStdTabOff += 3 * ( nVertComp[nC - 1] - 2) ; } } } } // Numero di feature nel voxel: al più vi è una feature per componente connessa. int nInnerFeatureInVoxel = 0 ; int nBorderFeatureInVoxel = 0 ; // Ciclo sulle componenti for ( int nCompCount = 1 ; nCompCount <= nComponents ; ++ nCompCount) { int nFeatureType = NO_FEATURE ; // Se i componenti sono regolari valuto le normali per stabilire se eseguire ExtMC o MC if ( bReg) nFeatureType = TestOnNormal( CompoVert[nCompCount - 1], nVertComp[nCompCount - 1]) ; // Controllo per il caso piano su una griglia // con versori normali a due a due paralleli. bool bGridControl = true ; if ( nFeatureType != NO_FEATURE) { if ( nVertComp[nCompCount - 1] == 4) GridControl( VecField, CompoVert, nIndArrey, nVertComp, nCompCount, bGridControl) ; } // Flag ExtMC bool bExtMC = ( nFeatureType != NO_FEATURE && bGridControl) && ( ! bSecondConfig6) && bEnh ; // Extended MC if ( bExtMC) { // Passo al sistema di riferimento del baricentro Point3d ptGravityCenter( 0, 0, 0) ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) ptGravityCenter = ptGravityCenter + CompoVert[nCompCount - 1][ni].ptInt ; ptGravityCenter = ptGravityCenter / nVertComp[nCompCount - 1] ; Vector3d vtTrasf[12] ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) vtTrasf[ni] = CompoVert[nCompCount - 1][ni].ptInt - ptGravityCenter ; // Preparo le matrici per il sistema typedef Eigen::Matrix dSystemMatrix ; typedef Eigen::Matrix dSystemVector ; typedef Eigen::JacobiSVD DecomposerSVD ; dSystemMatrix dMatrixN( nVertComp[nCompCount - 1], 3) ; dSystemVector dKnownVector( nVertComp[nCompCount - 1], 1) ; // Caso generale for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { dMatrixN( ni, 0) = CompoVert[nCompCount - 1][ni].vtNorm.x ; dMatrixN( ni, 1) = CompoVert[nCompCount - 1][ni].vtNorm.y ; dMatrixN( ni, 2) = CompoVert[nCompCount - 1][ni].vtNorm.z ; dKnownVector( ni) = CompoVert[nCompCount - 1][ni].vtNorm * vtTrasf[ni] ; } // calcolo SVD DecomposerSVD svd( dMatrixN, Eigen::ComputeThinU | Eigen::ComputeThinV) ; dSystemMatrix dMatrixV = svd.matrixV() ; dSystemVector dSingularValue = svd.singularValues() ; // Se la feature è un edge annullo il valore singolare minore. if ( nFeatureType == EDGE) { double dThres = 0.5 * ( dSingularValue( 1) + dSingularValue( 2)) / dSingularValue( 0) ; svd.setThreshold( dThres) ; } // risolvo il sistema con SVD, quindi ai minimi quadrati dSystemVector dUnknownVector( 3, 1) ; dUnknownVector = svd.solve( dKnownVector) ; // Vettore Baricentro-Feature Vector3d vtFeature( dUnknownVector( 0), dUnknownVector( 1), dUnknownVector( 2)) ; // Esprimo la soluzione nel sistema di riferimento z-map Point3d ptSol = ptGravityCenter + vtFeature ; // Limito la feature entro i secondi voxel vicini, // nel caso essa esca dal reticolo la limito entro una // distanza dal baricentro pari alla diagonale del voxel. bool bOutside = false ; int nFtVxI, nFtVxJ, nFtVxK ; if ( GetPointVoxel( ptSol, nFtVxI, nFtVxJ, nFtVxK)) { if ( abs( nFtVxI - nVoxI) > 2 || abs( nFtVxJ - nVoxJ) > 2 || abs( nFtVxK - nVoxK) > 2) bOutside = true ; } else { double dDistFeature = vtFeature.Len() ; const double MAX_DIST = sqrt( 3) * N_DEXVOXRATIO * m_dStep ; bOutside = ( dDistFeature > MAX_DIST) ; } TRIA3DVECTOR triContainer ; // Costruisco triangoli di prova for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; // Il triangolo è pronto Triangle3d CurrentTriangle ; CurrentTriangle.Set( ptSol, CompoVert[nCompCount - 1][nj].ptInt, CompoVert[nCompCount - 1][ni].ptInt) ; CurrentTriangle.Validate( true) ; // Aggiungo triangolo al vettore temporaneo triContainer.emplace_back( CurrentTriangle) ; } // Controllo delle inversioni dei triangoli bool bDangerInversion = false ; // Caso ventaglio con tre vertici di base if ( nVertComp[nCompCount - 1] == 3) { // Controllo se esiste almeno un triangolo con normale avente prodotto scalare // negativo con la normale di almeno uno dei vertici di base del ventaglio. bool bInversione = false ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; double dDI = triContainer[ni].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; double dDJ = triContainer[ni].GetN() * CompoVert[nCompCount - 1][nj].vtNorm ; if ( dDI < - EPS_SMALL || dDJ < - EPS_SMALL) { bInversione = true ; break ; } } // Se tale triangolo esiste procedo if ( bInversione) { // Conto le coppie di normali con angolo compreso maggiore di 90° int nNegDot = 0 ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] - 1 ; ++ ni) { for ( int nj = ni + 1 ; nj < nVertComp[nCompCount - 1] ; ++ nj) { if ( CompoVert[nCompCount - 1][ni].vtNorm * CompoVert[nCompCount - 1][nj].vtNorm < - EPS_SMALL) nNegDot ++ ; } } if ( nNegDot == nVertComp[nCompCount - 1] - 1) { // Cerco se esiste un punto in cui la normale ha prodotto scalre negativo // con le normali di entrambi i triangoli che lo contengono bool bInversione2 = false ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni == 0 ? nVertComp[nCompCount - 1] - 1 : ni - 1) ; double dDLast = triContainer[ni].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; double dDPrev = triContainer[nj].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; if ( ( dDLast < EPS_SMALL && dDPrev < EPS_SMALL) || ( dDLast < - 0.75 || dDPrev < - 0.75)) { bInversione2 = true ; break ; } } // Se tale normale esiste if ( bInversione2) { // Soluzione del sistema nel sistema Zmap Point3d ptSolZMapFrame = ptSol ; // Se la soluzione non cade nel voxel di appartenenza vedo se può // essere riportata dentro muovendosi lungo la linea di feature. if ( ! IsPointInsideVoxelApprox( nVoxI, nVoxJ, nVoxK, ptSolZMapFrame)) { Vector3d vtNullSpace( dMatrixV( 0, 2), dMatrixV( 1, 2), dMatrixV( 2, 2)) ; double dParInt1, dParInt2 ; Point3d ptVoxMin( ( nVoxI * N_DEXVOXRATIO + 0.5) * m_dStep, ( nVoxJ * N_DEXVOXRATIO + 0.5) * m_dStep, ( nVoxK * N_DEXVOXRATIO + 0.5) * m_dStep) ; Point3d ptVoxMax( ( ( nVoxI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( nVoxJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( nVoxK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep) ; // Caso in cui può essere riportata dentro: se il voxel in cui cade la feature è pieno // la riporto muovendola lungo la sua linea if ( IntersLineBox( ptSolZMapFrame, vtNullSpace, ptVoxMin, ptVoxMax, dParInt1, dParInt2)) { triContainer.resize( 0) ; double dPar = abs( dParInt1) < abs( dParInt2) ? dParInt1 + ( dParInt2 - dParInt1) / 100 : dParInt2 + ( dParInt1 - dParInt2) / 100 ; Point3d ptNewSol = ptSolZMapFrame + dPar * vtNullSpace ; ptSol = ptNewSol ; // Costruisco triangoli di prova for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; // Il triangolo è pronto Triangle3d CurrentTriangle ; CurrentTriangle.Set( ptSol, CompoVert[nCompCount - 1][nj].ptInt, CompoVert[nCompCount - 1][ni].ptInt) ; CurrentTriangle.Validate( true) ; // Aggiungo triangolo al vettore temporaneo triContainer.emplace_back( CurrentTriangle) ; } } // Caso in cui non può essere riportata dentro: // si passa alla routine standard se il voxel // in cui cade è pieno. else { int nAdjVoxI, nAdjVoxJ, nAdjVoxK ; if ( GetPointVoxel( ptSolZMapFrame, nAdjVoxI, nAdjVoxJ, nAdjVoxK)) { // Classificazione del voxel adiacente int nAdjIndex = CalcIndex( nAdjVoxI, nAdjVoxJ, nAdjVoxK) ; // Se il voxel è pieno if ( EdgeTable[nAdjIndex] != 0) bDangerInversion = true ; } } } } } } } // Ventaglio con base a quattro vertici else if ( nVertComp[nCompCount - 1] == 4) { // Controllo se esiste almeno un triangolo con normale avente prodotto scalare // negativo con la normale di almeno uno dei vertici di base del ventaglio. bool bInversione = false ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; double dDI = triContainer[ni].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; double dDJ = triContainer[ni].GetN() * CompoVert[nCompCount - 1][nj].vtNorm ; if ( dDI < - EPS_SMALL || dDJ < - EPS_SMALL) bInversione = true ; } // Se tale triangolo esiste continuo i test if ( bInversione) { // Se la feature non cade nel suo voxel if ( ! IsPointInsideVoxelApprox( nVoxI, nVoxJ, nVoxK, ptSol)) { Vector3d vtNullSpace( dMatrixV( 0, 2), dMatrixV( 1, 2), dMatrixV( 2, 2)) ; double dParInt1, dParInt2 ; Point3d ptVoxMin( ( nVoxI * N_DEXVOXRATIO + 0.5) * m_dStep, ( nVoxJ * N_DEXVOXRATIO + 0.5) * m_dStep, ( nVoxK * N_DEXVOXRATIO + 0.5) * m_dStep) ; Point3d ptVoxMax( ( ( nVoxI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( nVoxJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( nVoxK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep) ; // Se è possibile riportarla dentro e il voxel in cui cade è pieno, la riporto nel suo voxel // lungo la sua linea if ( IntersLineBox( ptSol, vtNullSpace, ptVoxMin, ptVoxMax, dParInt1, dParInt2)) { triContainer.resize( 0) ; double dPar = abs( dParInt1) < abs( dParInt2) ? dParInt1 + ( dParInt2 - dParInt1) / 100 : dParInt2 + ( dParInt1 - dParInt2) / 100 ; Point3d ptNewSol = ptSol + dPar * vtNullSpace ; ptSol = ptNewSol ; // Costruisco triangoli di prova for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; // Il triangolo è pronto Triangle3d CurrentTriangle ; CurrentTriangle.Set( ptSol, CompoVert[nCompCount - 1][nj].ptInt, CompoVert[nCompCount - 1][ni].ptInt) ; CurrentTriangle.Validate( true) ; // Aggiungo triangolo al vettore temporaneo triContainer.emplace_back( CurrentTriangle) ; } } // Se non è possibile riportarla dentro e il voxel in // cui cade è pieno passo alla routine standard else { int nAdjVoxI, nAdjVoxJ, nAdjVoxK ; if ( GetPointVoxel( ptSol, nAdjVoxI, nAdjVoxJ, nAdjVoxK)) { // Classificazione del voxel adiacente int nAdjIndex = CalcIndex( nAdjVoxI, nAdjVoxJ, nAdjVoxK) ; // Se il voxel è pieno if ( EdgeTable[nAdjIndex] != 0) bDangerInversion = true ; } } } } } // Valuto normali: questo è ancora un controllo // sulle normali, se risultano in tutti i punti // approssimativamente uguali passiamo alla // routine standard int nContSize = int( triContainer.size()) ; bool bPlane = true ; for ( int ni = 0 ; ni < nContSize - 1 ; ++ ni) { for ( int nj = ni + 1 ; nj < nContSize ; ++ nj) { Vector3d vtI = triContainer[ni].GetN() ; Vector3d vtJ = triContainer[nj].GetN() ; if ( ! AreSameVectorApprox( vtI, vtJ)) { bPlane = false ; break ; } } if ( ! bPlane) break ; } // Se feature nei limiti e triangoli non in un piano, confermo ExtMC if ( ! bOutside && ! bPlane && ! bDangerInversion) { TRIA3DVECTOR vInnerTriaTemp ; for ( int ni = 0 ; ni < nContSize ; ++ ni) { // Se l'area è non nulla aggiungo il triangolo a uno dei due vettori. if ( triContainer[ni].GetArea() > SQ_EPS_SMALL) { int nVoxIJK[3] = { nVoxI, nVoxJ, nVoxK} ; Point3d ptTemp = ptSol ; Triangle3d trTemp = triContainer[ni] ; vInnerTriaTemp.emplace_back( triContainer[ni]) ; } } if ( vInnerTriaTemp.size() > 0) { // Aggiorno il numero di feature. ++ nInnerFeatureInVoxel ; // Se siamo in presenza della prima feature del // voxel, ridimensiono il vettore che contiene // la struttura dati del voxel. if ( nInnerFeatureInVoxel == 1) { triHold.resize( triHold.size() + 1) ; // Questi dati dipendono solo dal voxel int nCurrent = int( triHold.size()) - 1 ; triHold[nCurrent].i = nVoxI ; triHold[nCurrent].j = nVoxJ ; triHold[nCurrent].k = nVoxK ; } // Indice che identifica la posizione del voxel nel vector. int nCurrent = int( triHold.size()) - 1 ; // Aggiungo vertice della componente connessa alla lista dei vertici. triHold[nCurrent].ptCompoVert.emplace_back( ptSol) ; int nOldFeatureNum = int( triHold[nCurrent].vCompoTria.size()) ; int nNewFeatureNum = nOldFeatureNum + 1 ; // Aggiungo una componente per il vettore dei triangoli della componente connessa. triHold[nCurrent].vCompoTria.resize( nNewFeatureNum) ; for ( int ni = 0 ; ni < int( vInnerTriaTemp.size()) ; ++ ni) { triHold[nCurrent].vCompoTria[nOldFeatureNum].emplace_back( vInnerTriaTemp[ni]) ; } } } // ExtMC non confermato, si passa a MC else { // Costruzione dei triangoli for ( int TriIndex = 0; TriIndex < ( nVertComp[nCompCount - 1] - 2) * 3 ; TriIndex += 3) { // Il triangolo è pronto Triangle3d CurrentTriangle ; CurrentTriangle.Set( CompoTriVert[nCompCount - 1][TriIndex].ptInt, CompoTriVert[nCompCount - 1][TriIndex+1].ptInt, CompoTriVert[nCompCount - 1][TriIndex+2].ptInt) ; bool bV = CurrentTriangle.Validate( true) ; // Aggiungo alla lista lstTria.emplace_back( CurrentTriangle) ; } } } // Standard MC else { // Costruzione dei triangoli for ( int TriIndex = 0; TriIndex < ( nVertComp[nCompCount - 1] - 2) * 3 ; TriIndex += 3) { // Il triangolo è pronto Triangle3d CurrentTriangle ; CurrentTriangle.Set( CompoTriVert[nCompCount - 1][TriIndex].ptInt, CompoTriVert[nCompCount - 1][TriIndex+1].ptInt, CompoTriVert[nCompCount - 1][TriIndex+2].ptInt) ; bool bV = CurrentTriangle.Validate( true) ; // Aggiungo alla lista lstTria.emplace_back( CurrentTriangle) ; } } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::ExtMarchingCubes( int nBlock, TRIA3DEXLIST& lstTria, TriHolder& triHold) const { // Controllo sulla validità del blocco if ( nBlock < 0 || nBlock >= int( m_nNumBlock)) return false ; // Calcolo i limiti sugli indici dei voxel del blocco int nIJK[3] ; // Vettore indici i,j,k del blocco GetBlockIJKFromN( nBlock, nIJK) ; // Vettore limiti sugli indici dei voxel del blocco int nLimits[6] ; GetBlockLimitsIJK( nIJK, nLimits) ; // Unordered Map per la riduzione del numero di triangoli int nDim = m_nVoxNumPerBlock * m_nVoxNumPerBlock ; VoxelContainer VoxContXZInf( nDim) ; VoxelContainer VoxContXZSup( nDim) ; VoxelContainer VoxContXYInf( nDim) ; VoxelContainer VoxContXYSup( nDim) ; VoxelContainer VoxContYZInf( nDim) ; VoxelContainer VoxContYZSup( nDim) ; // Ciclo su tutti i voxel dello Zmap for ( int i = nLimits[0] ; i < nLimits[1] ; ++ i) { for ( int j = nLimits[2] ; j < nLimits[3] ; ++ j) { for ( int k = nLimits[4] ; k < nLimits[5] ; ++ k) { // Classificazione dei vertici: interni o esterni al materiale int nIndex = CalcIndex( i, j, k) ; // Se vi è qualche intersezione fra segmenti e superficie // continuo altrimenti passo al prossimo voxel. if ( EdgeTable[nIndex] == 0) continue ; // Indici i,j,k dei vertici int IndexCorner[8][3] = { { i, j, k}, { i + 1, j, k}, { i + 1, j + 1, k}, { i, j + 1, k}, { i, j, k + 1}, { i + 1, j, k + 1}, { i + 1, j + 1, k + 1}, { i, j + 1, k + 1} } ; static int intersections[12][2] = { { 0, 1 }, { 1, 2 }, { 3, 2 }, { 0, 3 }, { 4, 5 }, { 5, 6 }, { 7, 6 }, { 4, 7 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } } ; // Array di strutture punto di intersezione e normale alla superficie in esso. VectorField VecField[12] ; // Flag di regolarità dei campi scalare e vettoriale bool bReg = true ; // Ciclo sui segmenti for ( int EdgeIndex = 0 ; EdgeIndex < 12 ; ++ EdgeIndex) { // Se il segmento non attraversa la superficie passo al successivo if ( ( EdgeTable[nIndex] & ( 1 << EdgeIndex)) == 0) continue ; // Indici per linee di griglia sui vertici int n1 = intersections[EdgeIndex][0] ; int n2 = intersections[EdgeIndex][1] ; // Flag posizione corner bool bN1 = ( ( nIndex & ( 1 << n1)) != 0) ; // Determino con precisione il punto di intersezione sullo spigolo, // se i campi scalare e vettoriale non sono regolari bReg diviene falso. if ( ! IntersPos( IndexCorner[n1], IndexCorner[n2], bN1, VecField[EdgeIndex])) bReg = false ; } // Determino il numero di componenti connesse nel voxel in caso di configurazione standard int nComponents = TriangleTableEn[nIndex][1][0] ; // Matrici di campi vettoriali: // CompoVert[i] ha i vertici della base del triangle fan della (i+1)-esima componente connessa; // CompoTriVert[i] ha i vertici di tutti i triangoli, nel caso di assenza di sharp feature, // della (i+1)-esima componente connessa. VectorField CompoVert[6][12] ; VectorField CompoTriVert[6][17] ; // Arrey numero di vertici della base del fan per componente // connessa: nVertComp[i] contiene il numero di vertici // della base del fan della (i+1)-esima componente connessa. int nVertComp[6] ; // Matrice di indici dei punti: serve per la gestione del caso int nIndArrey[6][4] ; int nExtTabOff = nComponents ; int nStdTabOff = 0 ; // Carico le matrici CompoVert e CompoTriVert for ( int nCompCount = 1 ; nCompCount <= nComponents ; ++ nCompCount) { // Numero vertici per componenti nVertComp[nCompCount - 1] = TriangleTableEn[nIndex][1][nCompCount] ; // Riempio il nCompCount-esimo vettore di vertici della base del fan for ( int nVertCount = 0 ; nVertCount < nVertComp[nCompCount - 1] ; ++ nVertCount) CompoVert[nCompCount - 1][nVertCount] = VecField[TriangleTableEn[nIndex][1][nVertCount + nExtTabOff + 1]] ; // Serve per la gestione del caso ... if ( nVertComp[nCompCount - 1] == 4) { for ( int nVertCount = 0 ; nVertCount < nVertComp[nCompCount - 1] ; ++ nVertCount) nIndArrey[nCompCount - 1][nVertCount] = TriangleTableEn[nIndex][1][nVertCount + nExtTabOff + 1] ; } // Riempio il nCompCount-esimo vettore di vertici dei triangoli in assenza di // sharp feature: in una mesh di triangoli con n vertici vi sono n - 2 triangoli. for ( int nVertCount = 0 ; nVertCount < 3 * ( nVertComp[nCompCount - 1] - 2) ; nVertCount += 3) { CompoTriVert[nCompCount - 1][nVertCount] = VecField[TriangleTableEn[nIndex][0][nStdTabOff + nVertCount+2]] ; CompoTriVert[nCompCount - 1][nVertCount+1] = VecField[TriangleTableEn[nIndex][0][nStdTabOff + nVertCount+1]] ; CompoTriVert[nCompCount - 1][nVertCount+2] = VecField[TriangleTableEn[nIndex][0][nStdTabOff + nVertCount]] ; } // Aggiorno gli offsets per raggiungere i vertici della componente successiva. nExtTabOff += nVertComp[nCompCount - 1] ; nStdTabOff += 3 * ( nVertComp[nCompCount - 1] - 2) ; } // Controllo se il voxel ha una sola faccia che giace in un piano canonico e quindi ha gestione speciale // Faccia XY normale Z+ if ( nIndex == 15) { int nTool ; double dPos ; if ( CanonicPlaneTest( CompoVert[0], Z_PLUS, dPos, nTool)) { int nN ; GetVoxNFromIJK( i, j, k, nN) ; VoxContXYSup.emplace( nN, HeigthAndColor( nTool, dPos)) ; continue ; } } // Faccia YZ normale X+ else if ( nIndex == 153) { int nTool ; double dPos ; if ( CanonicPlaneTest( CompoVert[0], X_PLUS, dPos, nTool)) { int nN ; GetVoxNFromIJK( i, j, k, nN) ; VoxContYZSup.emplace( nN, HeigthAndColor( nTool, dPos)) ; continue ; } } // Faccia ZX normale Y+ else if ( nIndex == 51) { int nTool ; double dPos ; if ( CanonicPlaneTest( CompoVert[0], Y_PLUS, dPos, nTool)) { int nN ; GetVoxNFromIJK( i, j, k, nN) ; VoxContXZSup.emplace( nN, HeigthAndColor( nTool, dPos)) ; continue ; } } // Faccia YX normale Z- else if ( nIndex == 240) { int nTool ; double dPos ; if ( CanonicPlaneTest( CompoVert[0], Z_MINUS, dPos, nTool)) { int nN ; GetVoxNFromIJK( i, j, k, nN) ; VoxContXYInf.emplace( nN, HeigthAndColor( nTool, dPos)) ; continue ; } } // Faccia ZY normale X- else if ( nIndex == 102) { int nTool ; double dPos ; if ( CanonicPlaneTest( CompoVert[0], X_MINUS, dPos, nTool)) { int nN ; GetVoxNFromIJK( i, j, k, nN) ; VoxContYZInf.emplace( nN, HeigthAndColor( nTool, dPos)) ; continue ; } } // Faccia XZ normale Y- else if ( nIndex == 204) { int nTool ; double dPos ; if ( CanonicPlaneTest( CompoVert[0], Y_MINUS, dPos, nTool)) { int nN ; GetVoxNFromIJK( i, j, k, nN) ; VoxContXZInf.emplace( nN, HeigthAndColor( nTool, dPos)) ; continue ; } } // Test sulla topologia: richiede campo regolare perchè si fonda su angoli tra normali if ( bReg) { // Configurazione 3 if ( nAllConfig[nIndex] == 3) { // Verifico concordanza tra i versori di una stessa componente // (ogni coppia di vettori di una medesima componente deve avere prodotto scalare non inferiore a 0.7) Vector3d vtCmpAvg0, vtCmpAvg1 ; bool bTest0 = DotTest( CompoVert[0], 3, vtCmpAvg0, 0.7) ; bool bTest1 = DotTest( CompoVert[1], 3, vtCmpAvg1, 0.7) ; // Se i versori di entrambe le componenti sono concordi ha senso parlare di vettori medi. // Altrimenti assegno al loro prodotto scalare un valore assurdo come -2 double dScProd = - 2 ; if ( bTest0 && bTest1) dScProd = vtCmpAvg0 * vtCmpAvg1 ; if ( ! ( bTest0 && bTest1) || ( bTest0 && bTest1 && dScProd > 0.7)) { int nt = 0 ; while ( nIndexVsIndex3[nt][0] != nIndex) ++ nt ; int nRotCase = nIndexVsIndex3[nt][1] ; nComponents = Cases3Plus[nRotCase][1][0] ; // Riaggiorno gli offsets nExtTabOff = nComponents ; nStdTabOff = 0 ; // Modifico le matrici for ( int nC = 1 ; nC <= nComponents ; ++ nC) { // Numero vertici per componenti nVertComp[nC - 1] = Cases3Plus[nRotCase][1][nC] ; // Matrice dei vertici della base del fan for ( int nFanVert = 0 ; nFanVert < nVertComp[nC - 1] ; ++ nFanVert) CompoVert[nC - 1][nFanVert] = VecField[Cases3Plus[nRotCase][1][nFanVert + nExtTabOff + 1]] ; // Matrici dei vertici dei triangoli in assenza di sharp feature for ( int nTriVert = 0 ; nTriVert < 3 * ( nVertComp[nC - 1] - 2) ; nTriVert += 3) { CompoTriVert[nC - 1][nTriVert] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert+2]] ; CompoTriVert[nC - 1][nTriVert+1] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert+1]] ; CompoTriVert[nC - 1][nTriVert+2] = VecField[Cases3Plus[nRotCase][0][nStdTabOff + nTriVert]] ; } // Aggiorno gli offsets per raggiungere i vertici della componente successiva. nExtTabOff += nVertComp[nC - 1] ; nStdTabOff += 3 * ( nVertComp[nC - 1] - 2) ; } } } // Configurazione 6 else if ( nAllConfig[nIndex] == 6) { // Procedura analoga a quella della configurazione 3 Vector3d vtCmpAvg0, vtCmpAvg1 ; bool bTest0 = DotTest( CompoVert[0], 4, vtCmpAvg0, 0.7) ; bool bTest1 = DotTest( CompoVert[1], 3, vtCmpAvg1, 0.7) ; double dScProd = - 2 ; if ( bTest0 && bTest1) dScProd = vtCmpAvg0 * vtCmpAvg1 ; if ( ! ( bTest0 && bTest1) || ( bTest0 && bTest1 && dScProd > 0.7)) { int nt = 0 ; while ( nIndexVsIndex6[nt][0] != nIndex) ++ nt ; int nRotCase = nIndexVsIndex6[nt][1] ; // Costruzione dei triangoli for ( int TriIndex = 0 ; TriIndex < 15 ; TriIndex += 3) { // Indici vertici int i0 = Cases6Plus[nRotCase][TriIndex + 2] ; int i1 = Cases6Plus[nRotCase][TriIndex + 1] ; int i2 = Cases6Plus[nRotCase][TriIndex] ; // Costruzione triangolo Triangle3dEx CurrentTriangle ; CurrentTriangle.Set( VecField[i0].ptInt, VecField[i1].ptInt, VecField[i2].ptInt) ; CurrentTriangle.Validate( true) ; CurrentTriangle.SetVertexNorm( 0, VecField[i0].vtNorm) ; CurrentTriangle.SetVertexNorm( 1, VecField[i1].vtNorm) ; CurrentTriangle.SetVertexNorm( 2, VecField[i2].vtNorm) ; CurrentTriangle.ToGlob( m_MapFrame) ; // Aggiungo alla lista lstTria.emplace_back( CurrentTriangle) ; } continue ; } } // Configurazione 10 else if ( nAllConfig[nIndex] == 10) { // Verifico concordanza tra i versori di una stessa componente // (ogni coppia di vettori di una medesima componente deve avere prodotto scalare non inferiore a 0.0) Vector3d vtCmpAvg0, vtCmpAvg1 ; bool bTest0 = DotTest( CompoVert[0], 4, vtCmpAvg0, 0.0) ; bool bTest1 = DotTest( CompoVert[1], 4, vtCmpAvg1, 0.0) ; if ( ! bTest0 || ! bTest1) { int nt = 0 ; while ( nIndexVsIndex10[nt][0] != nIndex) ++ nt ; // Riaggiorno gli offsets nExtTabOff = 2 ; nStdTabOff = 0 ; // Modifico le matrici int nRotCase = nIndexVsIndex10[nt][1] ; for ( int nC = 1 ; nC <= 2 ; ++ nC) { // Numero vertici per componenti nVertComp[nC - 1] = Cases10Plus[nRotCase][1][nC] ; // Matrice dei vertici della base del fan for ( int nFanVert = 0 ; nFanVert < 4 ; ++ nFanVert) CompoVert[nC - 1][nFanVert] = VecField[Cases10Plus[nRotCase][1][nFanVert + nExtTabOff + 1]] ; // Matrici dei vertici dei triangoli in assenza di sharp feature for ( int nTriVert = 0 ; nTriVert < 6 ; nTriVert += 3) { CompoTriVert[nC - 1][nTriVert] = VecField[Cases10Plus[nRotCase][0][nStdTabOff + nTriVert+2]] ; CompoTriVert[nC - 1][nTriVert+1] = VecField[Cases10Plus[nRotCase][0][nStdTabOff + nTriVert+1]] ; CompoTriVert[nC - 1][nTriVert+2] = VecField[Cases10Plus[nRotCase][0][nStdTabOff + nTriVert]] ; } // Aggiorno gli offsets per raggiungere i vertici della componente successiva. nExtTabOff += nVertComp[nC - 1] ; nStdTabOff += 3 * ( nVertComp[nC - 1] - 2) ; } } } } // Numero di feature nel voxel: al più vi è una feature per componente connessa. int nInnerFeatureInVoxel = 0 ; int nBorderFeatureInVoxel = 0 ; // Ciclo sulle componenti for ( int nCompCount = 1 ; nCompCount <= nComponents ; ++ nCompCount) { int nFeatureType = NO_FEATURE ; // Se i componenti sono regolari valuto le normali per stabilire se eseguire ExtMC o MC if ( bReg) nFeatureType = TestOnNormal( CompoVert[nCompCount - 1], nVertComp[nCompCount - 1]) ; // Controllo per il caso piano su una griglia con versori normali a due a due paralleli bool bGridControl = true ; if ( nFeatureType != NO_FEATURE && nVertComp[nCompCount - 1] == 4) GridControl( VecField, CompoVert, nIndArrey, nVertComp, nCompCount, bGridControl) ; // Flag ExtMC bool bExtMC = ( nFeatureType != NO_FEATURE && bGridControl) ; // Extended MC if ( bExtMC) { // Passo al sistema di riferimento del baricentro Point3d ptGravityCenter( 0, 0, 0) ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) ptGravityCenter += CompoVert[nCompCount - 1][ni].ptInt ; ptGravityCenter = ptGravityCenter / nVertComp[nCompCount - 1] ; Vector3d vtTrasf[12] ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) vtTrasf[ni] = CompoVert[nCompCount - 1][ni].ptInt - ptGravityCenter ; // Preparo le matrici per il sistema typedef Eigen::Matrix dSystemMatrix ; typedef Eigen::Matrix dSystemVector ; typedef Eigen::JacobiSVD DecomposerSVD ; dSystemMatrix dMatrixN( nVertComp[nCompCount - 1], 3) ; dSystemVector dKnownVector( nVertComp[nCompCount - 1], 1) ; // medio le normali adiacenti molto vicine (delta angolare inferiore a 22.5 deg) Vector3d vtNorm[12] ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) vtNorm[ni] = CompoVert[nCompCount - 1][ni].vtNorm ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1) % nVertComp[nCompCount - 1] ; if ( vtNorm[ni] * vtNorm[nj] > 0.92) { Vector3d vtNI = ( 0.6 * vtNorm[ni] + 0.4 * vtNorm[nj]) ; Vector3d vtNJ = ( 0.4 * vtNorm[ni] + 0.6 * vtNorm[nj]) ; vtNorm[ni] = vtNI ; vtNorm[ni].Normalize() ; vtNorm[nj] = vtNJ ; vtNorm[nj].Normalize() ; ++ ni ; } } // Caso generale for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { dMatrixN( ni, 0) = vtNorm[ni].x ; dMatrixN( ni, 1) = vtNorm[ni].y ; dMatrixN( ni, 2) = vtNorm[ni].z ; dKnownVector( ni) = vtNorm[ni] * vtTrasf[ni] ; } // calcolo SVD DecomposerSVD svd( dMatrixN, Eigen::ComputeThinU | Eigen::ComputeThinV) ; dSystemMatrix dMatrixV = svd.matrixV() ; dSystemVector dSingularValue = svd.singularValues() ; // Se la feature è un edge annullo il valore singolare minore. if ( nFeatureType == EDGE) { double dThres = 0.5 * ( dSingularValue( 1) + dSingularValue( 2)) / dSingularValue( 0) ; svd.setThreshold( dThres) ; } // risolvo il sistema con SVD, quindi ai minimi quadrati dSystemVector dUnknownVector( 3, 1) ; dUnknownVector = svd.solve( dKnownVector) ; // Vettore Baricentro-Feature Vector3d vtFeature( dUnknownVector( 0), dUnknownVector( 1), dUnknownVector( 2)) ; // Esprimo la soluzione nel sistema di riferimento z-map Point3d ptSol = ptGravityCenter + vtFeature ; // Limito la feature entro i secondi voxel vicini, // nel caso essa esca dal reticolo la limito entro una // distanza dal baricentro pari alla diagonale del voxel. bool bOutside = false ; int nFtVxI, nFtVxJ, nFtVxK ; if ( GetPointVoxel( ptSol, nFtVxI, nFtVxJ, nFtVxK)) { if ( abs( nFtVxI - i) > 2 || abs( nFtVxJ - j) > 2 || abs( nFtVxK - k) > 2) bOutside = true ; } else { double dDistFeature = vtFeature.Len() ; const double MAX_DIST = sqrt( 3) * N_DEXVOXRATIO * m_dStep ; bOutside = ( dDistFeature > MAX_DIST) ; } TRIA3DEXVECTOR triContainer ; // Costruisco triangoli di prova for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; // Il triangolo è pronto Triangle3dEx CurrentTriangle ; // Setto i punti CurrentTriangle.Set( ptSol, CompoVert[nCompCount - 1][nj].ptInt, CompoVert[nCompCount - 1][ni].ptInt) ; // Setto il numero di utensile ai vertici di base del fan CurrentTriangle.SetAttrib( 1, CompoVert[nCompCount - 1][nj].nToolFlag) ; CurrentTriangle.SetAttrib( 2, CompoVert[nCompCount - 1][ni].nToolFlag) ; // Setto il numero di utensile al triangolo nel complesso if ( CurrentTriangle.GetAttrib( 1) < 0 || CurrentTriangle.GetAttrib( 2) < 0) CurrentTriangle.SetGrade( - 1) ; else if ( CurrentTriangle.GetAttrib( 1) > 0 || CurrentTriangle.GetAttrib( 2) > 0) CurrentTriangle.SetGrade( 1) ; else CurrentTriangle.SetGrade( 0) ; // Setto le normali a ogni vertice CurrentTriangle.SetVertexNorm( 1, CompoVert[nCompCount - 1][nj].vtNorm) ; CurrentTriangle.SetVertexNorm( 2, CompoVert[nCompCount - 1][ni].vtNorm) ; if ( CurrentTriangle.GetVertexNorm( 1) * CurrentTriangle.GetVertexNorm( 2) > 0) CurrentTriangle.SetVertexNorm( 0, 0.5 * ( CurrentTriangle.GetVertexNorm( 1) + CurrentTriangle.GetVertexNorm( 2))) ; // Valido il triangolo CurrentTriangle.Validate( true) ; // Aggiungo triangolo al vettore temporaneo triContainer.emplace_back( CurrentTriangle) ; } // Controllo delle inversioni dei triangoli bool bDangerInversion = false ; // Caso ventaglio con tre vertici di base if ( nVertComp[nCompCount - 1] == 3) { // Controllo se esiste almeno un triangolo con normale avente prodotto scalare // negativo con la normale di almeno uno dei vertici di base del ventaglio. bool bInversione = false ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; double dDI = triContainer[ni].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; double dDJ = triContainer[ni].GetN() * CompoVert[nCompCount - 1][nj].vtNorm ; if ( dDI < - EPS_SMALL || dDJ < - EPS_SMALL) { bInversione = true ; break ; } } // Se tale triangolo esiste procedo if ( bInversione) { // Conto le coppie di normali con angolo compreso maggiore di 90° int nNegDot = 0 ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] - 1 ; ++ ni) { for ( int nj = ni + 1 ; nj < nVertComp[nCompCount - 1] ; ++ nj) { if ( CompoVert[nCompCount - 1][ni].vtNorm * CompoVert[nCompCount - 1][nj].vtNorm < - EPS_SMALL) nNegDot ++ ; } } if ( nNegDot == nVertComp[nCompCount - 1] - 1) { // Cerco se esiste un punto in cui la normale ha prodotto scalre negativo // con le normali di entrambi i triangoli che lo contengono bool bInversione2 = false ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni == 0 ? nVertComp[nCompCount - 1] - 1 : ni - 1) ; double dDLast = triContainer[ni].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; double dDPrev = triContainer[nj].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; if ( ( dDLast < EPS_SMALL && dDPrev < EPS_SMALL) || ( dDLast < - 0.75 || dDPrev < - 0.75)) { bInversione2 = true ; break ; } } // Se tale normale esiste if ( bInversione2) { // Se la soluzione non cade nel voxel di appartenenza vedo se può // essere riportata dentro muovendosi lungo la linea di feature. if ( ! IsPointInsideVoxelApprox( i, j, k, ptSol)) { Vector3d vtNullSpace( dMatrixV( 0, 2), dMatrixV( 1, 2), dMatrixV( 2, 2)) ; double dParInt1, dParInt2 ; Point3d ptVoxMin( ( i * N_DEXVOXRATIO + 0.5) * m_dStep, ( j * N_DEXVOXRATIO + 0.5) * m_dStep, ( k * N_DEXVOXRATIO + 0.5) * m_dStep) ; Point3d ptVoxMax( ( ( i + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( j + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( k + 1) * N_DEXVOXRATIO + 0.5) * m_dStep) ; // Caso in cui può essere riportata dentro: se il voxel in cui cade la feature è pieno // la riporto muovendola lungo la sua linea if ( IntersLineBox( ptSol, vtNullSpace, ptVoxMin, ptVoxMax, dParInt1, dParInt2)) { triContainer.resize( 0) ; double dPar = abs( dParInt1) < abs( dParInt2) ? dParInt1 + ( dParInt2 - dParInt1) / 100 : dParInt2 + ( dParInt1 - dParInt2) / 100 ; ptSol += dPar * vtNullSpace ; // Costruisco triangoli di prova for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; // Il triangolo è pronto Triangle3dEx CurrentTriangle ; CurrentTriangle.Set( ptSol, CompoVert[nCompCount - 1][nj].ptInt, CompoVert[nCompCount - 1][ni].ptInt) ; CurrentTriangle.SetAttrib( 1, CompoVert[nCompCount - 1][nj].nToolFlag) ; CurrentTriangle.SetAttrib( 2, CompoVert[nCompCount - 1][ni].nToolFlag) ; CurrentTriangle.SetVertexNorm( 1, CompoVert[nCompCount - 1][nj].vtNorm) ; CurrentTriangle.SetVertexNorm( 2, CompoVert[nCompCount - 1][ni].vtNorm) ; if ( CurrentTriangle.GetVertexNorm( 1) * CurrentTriangle.GetVertexNorm( 2) > 0) CurrentTriangle.SetVertexNorm( 0, 0.5 * ( CurrentTriangle.GetVertexNorm( 1) + CurrentTriangle.GetVertexNorm( 2))) ; // Valido il triangolo CurrentTriangle.Validate( true) ; // Assegno i colori if ( CurrentTriangle.GetAttrib( 1) < 0 || CurrentTriangle.GetAttrib( 2) < 0) CurrentTriangle.SetGrade( - 1) ; else if ( CurrentTriangle.GetAttrib( 1) > 0 || CurrentTriangle.GetAttrib( 2) > 0) CurrentTriangle.SetGrade( 1) ; else CurrentTriangle.SetGrade( 0) ; // Aggiungo triangolo al vettore temporaneo triContainer.emplace_back( CurrentTriangle) ; } } // Caso in cui non può essere riportata dentro: // si passa alla routine standard se il voxel // in cui cade è pieno. else { int nAdjVoxI, nAdjVoxJ, nAdjVoxK ; if ( GetPointVoxel( ptSol, nAdjVoxI, nAdjVoxJ, nAdjVoxK)) { // Classificazione del voxel adiacente int nAdjIndex = CalcIndex( nAdjVoxI, nAdjVoxJ, nAdjVoxK) ; // Se il voxel è pieno if ( EdgeTable[nAdjIndex] != 0) bDangerInversion = true ; } } } } } } } // Ventaglio con base a quattro vertici else if ( nVertComp[nCompCount - 1] == 4) { // Controllo se esiste almeno un triangolo con normale avente prodotto scalare // negativo con la normale di almeno uno dei vertici di base del ventaglio. bool bInversione = false ; for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; double dDI = triContainer[ni].GetN() * CompoVert[nCompCount - 1][ni].vtNorm ; double dDJ = triContainer[ni].GetN() * CompoVert[nCompCount - 1][nj].vtNorm ; if ( dDI < - EPS_SMALL || dDJ < - EPS_SMALL) bInversione = true ; } // Se tale triangolo esiste continuo i test if ( bInversione) { // Se la feature non cade nel suo voxel if ( ! IsPointInsideVoxelApprox( i, j, k, ptSol)) { Vector3d vtNullSpace( dMatrixV( 0, 2), dMatrixV( 1, 2), dMatrixV( 2, 2)) ; double dParInt1, dParInt2 ; Point3d ptVoxMin( ( i * N_DEXVOXRATIO + 0.5) * m_dStep, ( j * N_DEXVOXRATIO + 0.5) * m_dStep, ( k * N_DEXVOXRATIO + 0.5) * m_dStep) ; Point3d ptVoxMax( ( ( i + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( j + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( k + 1) * N_DEXVOXRATIO + 0.5) * m_dStep) ; // Se è possibile riportarla dentro e il voxel in cui cade è pieno, la riporto nel suo voxel // lungo la sua linea if ( IntersLineBox( ptSol, vtNullSpace, ptVoxMin, ptVoxMax, dParInt1, dParInt2)) { triContainer.resize( 0) ; double dPar = abs( dParInt1) < abs( dParInt2) ? dParInt1 + ( dParInt2 - dParInt1) / 100 : dParInt2 + ( dParInt1 - dParInt2) / 100 ; ptSol += dPar * vtNullSpace ; // Costruisco triangoli di prova for ( int ni = 0 ; ni < nVertComp[nCompCount - 1] ; ++ ni) { int nj = ( ni + 1 < nVertComp[nCompCount - 1]) ? ni + 1 : 0 ; // Il triangolo è pronto Triangle3dEx CurrentTriangle ; CurrentTriangle.Set( ptSol, CompoVert[nCompCount - 1][nj].ptInt, CompoVert[nCompCount - 1][ni].ptInt) ; CurrentTriangle.SetAttrib( 1, CompoVert[nCompCount - 1][nj].nToolFlag) ; CurrentTriangle.SetAttrib( 2, CompoVert[nCompCount - 1][ni].nToolFlag) ; CurrentTriangle.SetVertexNorm( 1, CompoVert[nCompCount - 1][nj].vtNorm) ; CurrentTriangle.SetVertexNorm( 2, CompoVert[nCompCount - 1][ni].vtNorm) ; if ( CurrentTriangle.GetVertexNorm( 1) * CurrentTriangle.GetVertexNorm( 2) > 0) CurrentTriangle.SetVertexNorm( 0, 0.5 * ( CurrentTriangle.GetVertexNorm( 1) + CurrentTriangle.GetVertexNorm( 2))) ; CurrentTriangle.Validate( true) ; // Assegno i colori if ( CurrentTriangle.GetAttrib( 1) < 0 || CurrentTriangle.GetAttrib( 2) < 0) CurrentTriangle.SetGrade( - 1) ; else if ( CurrentTriangle.GetAttrib( 1) > 0 || CurrentTriangle.GetAttrib( 2) > 0) CurrentTriangle.SetGrade( 1) ; else CurrentTriangle.SetGrade( 0) ; // Aggiungo triangolo al vettore temporaneo triContainer.emplace_back( CurrentTriangle) ; } } // Se non è possibile riportarla dentro e il voxel in // cui cade è pieno passo alla routine standard else { int nAdjVoxI, nAdjVoxJ, nAdjVoxK ; if ( GetPointVoxel( ptSol, nAdjVoxI, nAdjVoxJ, nAdjVoxK)) { // Classificazione del voxel adiacente int nAdjIndex = CalcIndex( nAdjVoxI, nAdjVoxJ, nAdjVoxK) ; // Se il voxel è pieno if ( EdgeTable[nAdjIndex] != 0) bDangerInversion = true ; } } } } } // Controllo sulle normali, se risultano in tutti i punti // approssimativamente uguali passiamo alla routine standard int nContSize = int( triContainer.size()) ; bool bPlane = true ; for ( int ni = 0 ; ni < nContSize - 1 ; ++ ni) { for ( int nj = ni + 1 ; nj < nContSize ; ++ nj) { Vector3d vtI = triContainer[ni].GetN() ; Vector3d vtJ = triContainer[nj].GetN() ; if ( ! AreSameVectorApprox( vtI, vtJ)) { bPlane = false ; break ; } } if ( ! bPlane) break ; } // Se feature nei limiti e triangoli non in un piano, confermo ExtMC if ( ! bOutside && ! bPlane && ! bDangerInversion) { // Riconoscimento se voxel di frontiera int nVoxIndexes[3] = { i, j, k} ; bool bBoundary = IsAVoxelOnBoundary( nLimits, nVoxIndexes, true) ; TRIA3DEXVECTOR vInnerTriaTemp, vBorderTriaTemp ; for ( int ni = 0 ; ni < nContSize ; ++ ni) { // Se l'area è non nulla aggiungo il triangolo a uno dei due vettori. if ( triContainer[ni].GetArea() > SQ_EPS_SMALL) { int nVoxIJK[3] = { i, j, k} ; Point3d ptTemp = ptSol ; Triangle3dEx trTemp = triContainer[ni] ; bool bTriangleOnBorder = IsATriangleOnBorder( trTemp, ptTemp, nLimits, nVoxIJK) ; if ( ! bBoundary || ! bTriangleOnBorder) vInnerTriaTemp.emplace_back( triContainer[ni]) ; else vBorderTriaTemp.emplace_back( triContainer[ni]) ; } } // Porto la soluzione nel sistema in cui è immerso lo Zmap ptSol.ToGlob( m_MapFrame) ; // Metto i triangoli negli appositi contenitori: // Triangoli interni if ( vInnerTriaTemp.size() > 0) { // Aggiorno il numero di feature. ++ nInnerFeatureInVoxel ; // Se siamo in presenza della prima feature del // voxel, ridimensiono il vettore che contiene // la struttura dati del voxel. if ( nInnerFeatureInVoxel == 1) { triHold.resize( triHold.size() + 1) ; // Questi dati dipendono solo dal voxel, int nCurrent = int( triHold.size()) - 1 ; triHold[nCurrent].i = i ; triHold[nCurrent].j = j ; triHold[nCurrent].k = k ; } // Indice che identifica la posizione del voxel nel vector. int nCurrent = int( triHold.size()) - 1 ; // Aggiungo vertice della componente // connessa alla lista dei vertici. triHold[nCurrent].ptCompoVert.emplace_back( ptSol) ; int nOldFeatureNum = int( triHold[nCurrent].vCompoTria.size()) ; int nNewFeatureNum = nOldFeatureNum + 1 ; // Aggiungo una componente per il vettore // dei triangoli della componente connessa. triHold[nCurrent].vCompoTria.resize( nNewFeatureNum) ; triHold[nCurrent].vbFlipped.resize( nNewFeatureNum) ; for ( int ni = 0 ; ni < int( vInnerTriaTemp.size()) ; ++ ni) { // Riporto le coordinate nel sistema in cui è immerso lo Zmap vInnerTriaTemp[ni].ToGlob( m_MapFrame) ; triHold[nCurrent].vCompoTria[nOldFeatureNum].emplace_back( vInnerTriaTemp[ni]) ; } triHold[nCurrent].vbFlipped[nOldFeatureNum].resize( vInnerTriaTemp.size()) ; for ( int ni = 0 ; ni < int( vInnerTriaTemp.size()) ; ++ ni) { triHold[nCurrent].vbFlipped[nOldFeatureNum][ni] = false ; } } // Triangoli di frontiera if ( vBorderTriaTemp.size() > 0) { // Aggiorno il numero di feature. ++ nBorderFeatureInVoxel ; // Se siamo in presenza della prima feature del // voxel, ridimensiono il vettore che contiene // la struttura dati del voxel. if ( nBorderFeatureInVoxel == 1) { m_InterBlockTria[nBlock].resize( m_InterBlockTria[nBlock].size() + 1) ; // Questi dati dipendono solo dal voxel int nCurrent = int( m_InterBlockTria[nBlock].size()) - 1 ; m_InterBlockTria[nBlock][nCurrent].i = i ; m_InterBlockTria[nBlock][nCurrent].j = j ; m_InterBlockTria[nBlock][nCurrent].k = k ; } // Indice che identifica la posizione del voxel nel vector int nCurrent = int( m_InterBlockTria[nBlock].size()) - 1 ; // Aggiungo vertice della componente connessa alla lista dei vertici m_InterBlockTria[nBlock][nCurrent].ptCompoVert.emplace_back( ptSol) ; int nOldFeatureNum = int( m_InterBlockTria[nBlock][nCurrent].vCompoTria.size()) ; int nNewFeatureNum = nOldFeatureNum + 1 ; // Aggiungo una componente per il vettore dei triangoli della componente connessa m_InterBlockTria[nBlock][nCurrent].vCompoTria.resize( nNewFeatureNum) ; for ( int ni = 0 ; ni < int( vBorderTriaTemp.size()) ; ++ ni) { // Riporto le coordinate nel sistema in cui è immerso lo Zmap vBorderTriaTemp[ni].ToGlob( m_MapFrame) ; m_InterBlockTria[nBlock][nCurrent].vCompoTria[nOldFeatureNum].emplace_back( vBorderTriaTemp[ni]) ; } } } // ExtMC non confermato, si passa a MC else { vector vTria ; // Costruzione dei triangoli for ( int TriIndex = 0; TriIndex < ( nVertComp[nCompCount - 1] - 2) * 3 ; TriIndex += 3) { // Il triangolo è pronto Triangle3dEx CurrentTriangle ; CurrentTriangle.Set( CompoTriVert[nCompCount - 1][TriIndex].ptInt, CompoTriVert[nCompCount - 1][TriIndex+1].ptInt, CompoTriVert[nCompCount - 1][TriIndex+2].ptInt) ; // Setto il numero di utensile (conta solo positivo, nullo o negativo) int nTool0 = Clamp( CompoTriVert[nCompCount - 1][TriIndex].nToolFlag, -1, 1) ; int nTool1 = Clamp( CompoTriVert[nCompCount - 1][TriIndex+1].nToolFlag, -1, 1) ; int nTool2 = Clamp( CompoTriVert[nCompCount - 1][TriIndex+2].nToolFlag, -1, 1) ; // Setto il numero dei colori if ( nTool0 == nTool1 || nTool0 == nTool2) CurrentTriangle.SetGrade( nTool0) ; else if ( nTool1 == nTool2) CurrentTriangle.SetGrade( nTool1) ; // Valido il triangolo e setto le normali del campo vettoriale ai corrispondenti vertici if ( CurrentTriangle.Validate( true)) { for ( int nV = 0 ; nV < 3 ; ++ nV) { const Vector3d& vtVertNorm = CompoTriVert[nCompCount - 1][TriIndex+nV].vtNorm ; if ( CurrentTriangle.GetN() * vtVertNorm > 0.6) CurrentTriangle.SetVertexNorm( nV, vtVertNorm) ; else CurrentTriangle.SetVertexNorm( nV, CurrentTriangle.GetN()) ; } } // Riporto le coordinate nel sistema in cui è immerso lo Zmap CurrentTriangle.ToGlob( m_MapFrame) ; // Aggiungo alla lista vTria.emplace_back( CurrentTriangle) ; } // Controllo i colori di configurazioni 2 e 8 if ( ( nAllConfig[nIndex] == 2 || nAllConfig[nIndex] == 8) && vTria[0].GetN() * vTria[1].GetN() > 0.8) { if ( vTria[0].GetGrade() < 0 || vTria[1].GetGrade() < 0) { vTria[0].SetGrade( -1) ; vTria[1].SetGrade( -1) ; } else if ( vTria[0].GetGrade() > 0 || vTria[1].GetGrade() > 0) { vTria[0].SetGrade( 1) ; vTria[1].SetGrade( 1) ; } } for ( int nT = 0 ; nT < int( vTria.size()) ; ++ nT) lstTria.emplace_back( vTria[nT]) ; } } // Standard MC else { vector vTria ; // Costruzione dei triangoli for ( int TriIndex = 0; TriIndex < ( nVertComp[nCompCount - 1] - 2) * 3 ; TriIndex += 3) { // Il triangolo è pronto Triangle3dEx CurrentTriangle ; CurrentTriangle.Set( CompoTriVert[nCompCount - 1][TriIndex].ptInt, CompoTriVert[nCompCount - 1][TriIndex+1].ptInt, CompoTriVert[nCompCount - 1][TriIndex+2].ptInt) ; // Setto il numero di utensile (conta solo positivo, nullo o negativo) int nTool0 = Clamp( CompoTriVert[nCompCount - 1][TriIndex].nToolFlag, -1, 1) ; int nTool1 = Clamp( CompoTriVert[nCompCount - 1][TriIndex+1].nToolFlag, -1, 1) ; int nTool2 = Clamp( CompoTriVert[nCompCount - 1][TriIndex+2].nToolFlag, -1, 1) ; if ( nTool0 == nTool1 || nTool0 == nTool2) CurrentTriangle.SetGrade( nTool0) ; else if ( nTool1 == nTool2) CurrentTriangle.SetGrade( nTool1) ; // Valido il triangolo e setto le normali del campo vettoriale ai corrispondenti vertici if ( CurrentTriangle.Validate( true)) { for ( int nV = 0 ; nV < 3 ; ++ nV) { const Vector3d& vtVertNorm = CompoTriVert[nCompCount - 1][TriIndex+nV].vtNorm ; if ( CurrentTriangle.GetN() * vtVertNorm > 0.6) CurrentTriangle.SetVertexNorm( nV, vtVertNorm) ; else CurrentTriangle.SetVertexNorm( nV, CurrentTriangle.GetN()) ; } } // si può inserire controllo sui colori per i casi 2 e 8 come per ext non confermato // Riporto le coordinate nel sistema in cui è immerso lo Zmap CurrentTriangle.ToGlob( m_MapFrame) ; // Aggiungo alla lista vTria.emplace_back( CurrentTriangle) ; } // Controllo i colori di configurazioni 2 e 8 if ( ( nAllConfig[nIndex] == 2 || nAllConfig[nIndex] == 8) && vTria[0].GetN() * vTria[1].GetN() > 0.8) { if ( vTria[0].GetGrade() < 0 || vTria[1].GetGrade() < 0) { vTria[0].SetGrade( -1) ; vTria[1].SetGrade( -1) ; } else if ( vTria[0].GetGrade() > 0 || vTria[1].GetGrade() > 0) { vTria[0].SetGrade( 1) ; vTria[1].SetGrade( 1) ; } } for ( int nT = 0 ; nT < int( vTria.size()) ; ++ nT) lstTria.emplace_back( vTria[nT]) ; } } } } } // Processo i Voxel con possibile superficie piana ProcessVoxContXY( VoxContXYInf, false, lstTria) ; ProcessVoxContXY( VoxContXYSup, true, lstTria) ; ProcessVoxContYZ( VoxContYZInf, false, lstTria) ; ProcessVoxContYZ( VoxContYZSup, true, lstTria) ; ProcessVoxContXZ( VoxContXZInf, false, lstTria) ; ProcessVoxContXZ( VoxContXZSup, true, lstTria) ; return true ; } //---------------------------------------------------------------------------- // Calcola i triangoli dei voxel contenuti nel vettore, se si vuole il riconoscimento // delle sharp-feature passare true in bEhn. In questo caso vengono analizzai anche i // voxel adiacenti a quelli contenenti sharp-feature, e viene eseguito il flipping. bool VolZmap::ExtMarchingCubes( vector& vVox, TRIA3DEXLIST& lstTria, bool bEnh) const { // Contenitore dei triangoli costituenti sharp-feaure TriHolder triHold ; int nOriginalSize = int( vVox.size()) ; for ( int nV = 0 ; nV < int( vVox.size()) ; ++ nV) { // I voxel intersecati dalla retta hanno indice nel vettore // nV < OriginalSize; quelli adiacenti avranno indice // nV >= OriginalSize if ( nV < nOriginalSize) { // Se a questa iterazione troviamo una sharp-feature // la dimensione del TriHolder aumenta int nCurrentSize = int( triHold.size()) ; ProcessCube( vVox[nV].nI, vVox[nV].nJ, vVox[nV].nK, lstTria, triHold, bEnh) ; int nNewSize = int( triHold.size()) ; // Se abbiamo trovato una sharp-feature if ( nNewSize > nCurrentSize) { // Ciclo fra tutti i possibili voxel adiacenti for ( int i = - 1 ; i <= 1 ; ++ i) { for ( int j = - 1 ; j <= 1 ; ++ j) { for ( int k = - 1 ; k <= 1 ; ++ k) { if ( i == 0 && j == 0 && k == 0) continue ; if ( IsValidVoxel( vVox[nV].nI + i, vVox[nV].nJ + j, vVox[nV].nK + k)) { // Se il voxel adiacente è già nella lista di quelli attraversati dalla retta // lo ignoro, altrimenti lo metto in coda nel TriHolder. int nOldV = 0 ; for ( ; nOldV < nOriginalSize ; ++ nOldV) { if ( vVox[nOldV].nI == vVox[nV].nI + i || vVox[nOldV].nJ == vVox[nV].nJ + j || vVox[nOldV].nK == vVox[nV].nK + k) continue ; } if ( nOldV == nOriginalSize) { Voxel NewVox ; NewVox.nI = vVox[nV].nI + i ; NewVox.nJ = vVox[nV].nJ + j ; NewVox.nK = vVox[nV].nK + k ; vVox.emplace_back( NewVox) ; } } } } } } } // Se il voxel non è attraversato dalla retta, ma fa parte di // quelli adiacenti lo processiamo normalmente else ProcessCube( vVox[nV].nI, vVox[nV].nJ, vVox[nV].nK, lstTria, triHold, bEnh) ; } // Eseguo il flipping FlipEdgesII( triHold) ; // Aggiungo alla lista di triangoli, tutti quelli che formano una sharp-feature. for ( int nVox = 0 ; nVox < int( triHold.size()) ; ++ nVox) { for ( int nCompo = 0 ; nCompo < int( triHold[nVox].vCompoTria.size()) ; ++ nCompo) { for ( int nTri = 0 ; nTri < int( triHold[nVox].vCompoTria[nCompo].size()) ; ++ nTri) { lstTria.emplace_back( triHold[nVox].vCompoTria[nCompo][nTri]) ; } } } return true ; } //---------------------------------------------------------------------------- // Esegue il flipping dei triangoli contenuti nel TriHolder, // bGraph indica se chiamata per grafica o per calcolo di profondità. bool VolZmap::FlipEdgesII( TriHolder& TriHold) const { // Numero di voxel in cui si presentano sharp feature int nVoxelNum = int( TriHold.size()) ; // Ciclo sui voxel con sharp feature for ( int n1 = 0 ; n1 < nVoxelNum ; ++ n1) { for ( int n2 = n1 ; n2 < nVoxelNum ; ++ n2) { // Se i voxel sono adiacenti proseguo if ( abs( TriHold[n2].i - TriHold[n1].i) <= 1 || abs( TriHold[n2].j - TriHold[n1].j) <= 1 || abs( TriHold[n2].k - TriHold[n1].k) <= 1 ) { // Numero delle componenti connesse nei due voxel int nNumCompo1 = int( TriHold[n1].ptCompoVert.size()) ; int nNumCompo2 = int( TriHold[n2].ptCompoVert.size()) ; // Ciclo sulle componenti int nCompo1 = 0 ; for ( ; nCompo1 < nNumCompo1 ; ++ nCompo1) { int nCompo2 = ( n1 == n2 ? nCompo1 + 1 : 0) ; for ( ; nCompo2 < nNumCompo2 ; ++ nCompo2) { // Numero di triangoli per le componenti connesse int nTriNum1 = int( TriHold[n1].vCompoTria[nCompo1].size()) ; int nTriNum2 = int( TriHold[n2].vCompoTria[nCompo2].size()) ; for ( int nTri1 = 0 ; nTri1 < nTriNum1 ; ++ nTri1) { bool bModified = false ; for ( int nTri2 = 0 ; nTri2 < nTriNum2 ; ++ nTri2) { // Punti che devono essere in comune fra i due triangoli Point3d ptP11 = TriHold[n1].vCompoTria[nCompo1][nTri1].GetP( 1) ; Point3d ptP12 = TriHold[n1].vCompoTria[nCompo1][nTri1].GetP( 2) ; Point3d ptP21 = TriHold[n2].vCompoTria[nCompo2][nTri2].GetP( 1) ; Point3d ptP22 = TriHold[n2].vCompoTria[nCompo2][nTri2].GetP( 2) ; // I triangoli sono da flippare if ( AreSamePointEpsilon( ptP11, ptP22, EPS_ZERO) && AreSamePointEpsilon( ptP12, ptP21, EPS_ZERO)) { // Assegno l'array dei punti di contorno Point3d vPnt[4] ; vPnt[0] = TriHold[n1].vCompoTria[nCompo1][nTri1].GetP( 1) ; vPnt[1] = TriHold[n1].ptCompoVert[nCompo1] ; vPnt[2] = TriHold[n1].vCompoTria[nCompo1][nTri1].GetP( 2) ; vPnt[3] = TriHold[n2].ptCompoVert[nCompo2] ; // Valuto se i triangoli giacciono su un piano PolygonPlane Polygon ; for ( int i = 0 ; i < 4 ; ++ i) Polygon.AddPoint( vPnt[i]) ; Plane3d plPlane ; bool bOnPlane = Polygon.GetPlane( plPlane) ; for ( int i = 0 ; i < 4 && bOnPlane ; ++ i) bOnPlane = PointInPlaneApprox( vPnt[i], plPlane) ; // Se sono su un piano controllo se avviene inversione bool bInv = false ; if ( bOnPlane) { Triangle3d trT1 = TriHold[n1].vCompoTria[nCompo1][nTri1] ; Triangle3d trT2 = TriHold[n2].vCompoTria[nCompo2][nTri2] ; int nVert1, nVert2 ; // Determino gli indici dei punti sharp-feature for ( int nP = 0 ; nP < 3 ; ++ nP) { if ( nP != 1 && nP != 2) nVert1 = nP ; if ( nP != 2 && nP != 1) nVert2 = nP ; } trT1.SetP( 1, trT2.GetP( nVert2)) ; trT2.SetP( 1, trT1.GetP( nVert1)) ; trT1.Validate( true) ; trT2.Validate( true) ; bInv = ( trT1.GetN() * trT2.GetN() < 0) ; } // Se non vi è inversione eseguo il flipping if ( ! bInv) { // Vertice condiviso fra nTri1 e quello del suo fan int nCol1 = TriHold[n1].vCompoTria[nCompo1][nTri1].GetAttrib( 2) ; int nCol2 = TriHold[n2].vCompoTria[nCompo2][nTri2].GetAttrib( 2) ; // Modifico i punti e gli indici TriHold[n1].vCompoTria[nCompo1][nTri1].SetP( 1, TriHold[n2].ptCompoVert[nCompo2]) ; TriHold[n2].vCompoTria[nCompo2][nTri2].SetP( 1, TriHold[n1].ptCompoVert[nCompo1]) ; TriHold[n1].vCompoTria[nCompo1][nTri1].SetGrade( nCol1) ; TriHold[n2].vCompoTria[nCompo2][nTri2].SetGrade( nCol2) ; // Setto le normali Vector3d vtN1 = TriHold[n1].vCompoTria[nCompo1][nTri1].GetVertexNorm( 2) ; Vector3d vtN2 = TriHold[n2].vCompoTria[nCompo2][nTri2].GetVertexNorm( 2) ; TriHold[n1].vCompoTria[nCompo1][nTri1].SetVertexNorm( 0, vtN1) ; TriHold[n1].vCompoTria[nCompo1][nTri1].SetVertexNorm( 1, vtN1) ; TriHold[n2].vCompoTria[nCompo2][nTri2].SetVertexNorm( 0, vtN2) ; TriHold[n2].vCompoTria[nCompo2][nTri2].SetVertexNorm( 1, vtN2) ; // Valido i triangoli TriHold[n1].vCompoTria[nCompo1][nTri1].Validate( true) ; TriHold[n2].vCompoTria[nCompo2][nTri2].Validate( true) ; // Avvenuto flipping bModified = true ; break ; } else { // In questo caso i due triangoli sono necessariamente su un piano, // quindi hanno normali concordi. Per ognuno dei due cerco nei rispettivi // ventagli un triangolo con normale concorde con colore definito. Assegno // tale colore ai triangoli. int nPrv1 = ( nTri1 != 0 ? nTri1 : int( TriHold[n1].vCompoTria[nCompo1].size())) - 1 ; int nNxt1 = ( nTri1 != TriHold[n1].vCompoTria[nCompo1].size() - 1 ? nTri1 + 1 : 0) ; int nPrv2 = ( nTri2 != 0 ? nTri2 : int( TriHold[n2].vCompoTria[nCompo2].size())) - 1 ; int nNxt2 = ( nTri2 != TriHold[n2].vCompoTria[nCompo2].size() - 1 ? nTri2 + 1 : 0) ; // Prodotti scalari del primo triangolo con i suoi adiacenti double dDotP1 = TriHold[n1].vCompoTria[nCompo1][nTri1].GetN() * TriHold[n1].vCompoTria[nCompo1][nPrv1].GetN() ; double dDotN1 = TriHold[n1].vCompoTria[nCompo1][nTri1].GetN() * TriHold[n1].vCompoTria[nCompo1][nNxt1].GetN() ; // Prendo il maggiore fra i due, e comunque maggiore di 0.5 int nAdjT1 = - 1 ; if ( dDotP1 > 0.5 || dDotN1 > 0.5) nAdjT1 = ( dDotP1 > dDotN1 ? nPrv1 : nNxt1) ; // Prodotti scalari del primo triangolo con i suoi adiacenti double dDotP2 = TriHold[n2].vCompoTria[nCompo2][nTri2].GetN() * TriHold[n2].vCompoTria[nCompo2][nPrv2].GetN() ; double dDotN2 = TriHold[n2].vCompoTria[nCompo2][nTri2].GetN() * TriHold[n2].vCompoTria[nCompo2][nNxt2].GetN() ; // Prendo il maggiore fra i due, e comunque maggiore di 0.5 int nAdjT2 = - 1 ; if ( dDotP2 > 0.5 || dDotN2 > 0.5) nAdjT2 = ( dDotP2 > dDotN2 ? nPrv2 : nNxt2) ; // Se abbiamo trovato triangoli adiacenti validi // assegnamo il colorea quelli correnti. if ( nAdjT1 != - 1) { int nCol = TriHold[n1].vCompoTria[nCompo1][nAdjT1].GetGrade() ; TriHold[n1].vCompoTria[nCompo1][nTri1].SetGrade( nCol) ; TriHold[n2].vCompoTria[nCompo2][nTri2].SetGrade( nCol) ; } else if ( nAdjT2 != - 1) { int nCol = TriHold[n2].vCompoTria[nCompo2][nAdjT2].GetGrade() ; TriHold[n1].vCompoTria[nCompo1][nTri1].SetGrade( nCol) ; TriHold[n2].vCompoTria[nCompo2][nTri2].SetGrade( nCol) ; } } } } if ( bModified) break ; } } } } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::FlipEdgesBB( TriaMatrix& InterTria) const { // Numero di blocchi size_t nBlocksNum = InterTria.size() ; // ciclo sui blocchi for ( size_t tFB = 0 ; tFB < nBlocksNum ; ++ tFB) { int nFBijk[3] ; GetBlockIJKFromN( int( tFB), nFBijk) ; for ( size_t tLB = tFB ; tLB < nBlocksNum ; ++ tLB) { int nLBijk[3] ; GetBlockIJKFromN( int( tLB), nLBijk) ; // Se i blocchi non sono adiacenti salto l'iterazione if ( ! ( abs( nFBijk[0] - nLBijk[0]) <= 1 && abs( nFBijk[1] - nLBijk[1]) <= 1 && abs( nFBijk[2] - nLBijk[2]) <= 1)) continue ; // Numero di voxel nei blocchi correnti size_t nVoxelNumFB = InterTria[tFB].size() ; size_t nVoxelNumLB = InterTria[tLB].size() ; // Ciclo sui voxel dei due blocchi for ( size_t tVFB = 0 ; tVFB < nVoxelNumFB ; ++ tVFB) { for ( size_t tVLB = 0 ; tVLB < nVoxelNumLB ; ++ tVLB) { // Se i voxel non sono adiacenti salto l'iterazione if ( ! ( abs( InterTria[tFB][tVFB].i - InterTria[tLB][tVLB].i) <= 1 && abs( InterTria[tFB][tVFB].j - InterTria[tLB][tVLB].j) <= 1 && abs( InterTria[tFB][tVFB].k - InterTria[tLB][tVLB].k) <= 1)) continue ; // Numero di componenti connesse dei voxel size_t nCompoVFBNum = InterTria[tFB][tVFB].ptCompoVert.size() ; size_t nCompoVLBNum = InterTria[tLB][tVLB].ptCompoVert.size() ; // Ciclo sulle componenti connesse for ( size_t tCmpF = 0 ; tCmpF < nCompoVFBNum ; ++ tCmpF) { for ( size_t tCmpL = 0 ; tCmpL < nCompoVLBNum ; ++ tCmpL) { // Numero di triangoli delle componenti connesse size_t nTriFBNum = InterTria[tFB][tVFB].vCompoTria[tCmpF].size() ; size_t nTriLBNum = InterTria[tLB][tVLB].vCompoTria[tCmpL].size() ; // Ciclo sui triangoli for ( size_t tTriFB = 0 ; tTriFB < nTriFBNum ; ++ tTriFB) { bool bModified = false ; for ( size_t tTriLB = 0 ; tTriLB < nTriLBNum ; ++ tTriLB) { // Punti che devono essere in comune fra i due triangoli Point3d ptPF1 = InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].GetP( 1) ; Point3d ptPF2 = InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].GetP( 2) ; Point3d ptPL1 = InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].GetP( 1) ; Point3d ptPL2 = InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].GetP( 2) ; // Si deve operare la modifica dei triangoli if ( AreSamePointEpsilon( ptPF1, ptPL2, EPS_ZERO) && AreSamePointEpsilon( ptPF2, ptPL1, EPS_ZERO)) { // Assegno l'array dei punti di contorno Point3d vPnt[4] ; vPnt[0] = InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].GetP( 1) ; vPnt[1] = InterTria[tFB][tVFB].ptCompoVert[tCmpF] ; vPnt[2] = InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].GetP( 2) ; vPnt[3] = InterTria[tLB][tVLB].ptCompoVert[tCmpL] ; // Valuto se i triangoli giacciono su un piano PolygonPlane Polygon ; for ( int i = 0 ; i < 4 ; ++ i) Polygon.AddPoint( vPnt[i]) ; Plane3d plPlane ; bool bOnPlane = Polygon.GetPlane( plPlane) ; for ( int i = 0 ; i < 4 && bOnPlane ; ++ i) bOnPlane = PointInPlaneApprox( vPnt[i], plPlane) ; // Se sono su un piano controllo se avviene inversione bool bInv = false ; if ( bOnPlane) { Triangle3dEx trTF = InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB] ; Triangle3dEx trTL = InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB] ; int nVertF, nVertL ; // Determino gli indici dei punti sharp-feature for ( int nP = 0 ; nP < 3 ; ++ nP) { if ( nP != 1 && nP != 2) nVertF = nP ; if ( nP != 2 && nP != 1) nVertL = nP ; } trTF.SetP( 1, trTL.GetP( nVertL)) ; trTF.Validate( true) ; trTL.SetP( 1, trTF.GetP( nVertF)) ; trTL.Validate( true) ; bInv = ( trTF.GetN() * trTL.GetN() < 0) ; } // Se non vi è inversione eseguo il flipping if ( ! bInv) { // Vertice condiviso fra nTri1 e quello del suo fan int nColF = InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].GetAttrib( 2) ; int nColL = InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].GetAttrib( 2) ; // modifico punti e colori InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].SetP( 1, InterTria[tLB][tVLB].ptCompoVert[tCmpL]) ; InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].SetP( 1, InterTria[tFB][tVFB].ptCompoVert[tCmpF]) ; InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].SetGrade( nColF) ; InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].SetGrade( nColL) ; // Valido i triangoli InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].Validate( true) ; InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].Validate( true) ; // Setto le normali a ogni vertice Vector3d vtNormF = InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].GetVertexNorm( 2) ; Vector3d vtNormL = InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].GetVertexNorm( 2) ; InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].SetVertexNorm( 1, vtNormF) ; InterTria[tFB][tVFB].vCompoTria[tCmpF][tTriFB].SetVertexNorm( 0, vtNormF) ; InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].SetVertexNorm( 1, vtNormL) ; InterTria[tLB][tVLB].vCompoTria[tCmpL][tTriLB].SetVertexNorm( 0, vtNormL) ; bModified = true ; break ; } } } if ( bModified) break ; } } } } } } } return true ; } //---------------------------------------------------------------------------- bool VolZmap::IsThereMat( int nI, int nJ, int nK) const { // Trasformo gl indici della griglia voxel in quelli della griglia dexel nI *= N_DEXVOXRATIO ; nJ *= N_DEXVOXRATIO ; nK *= N_DEXVOXRATIO ; // Se l'indice è alla frontiera del reticolo non vi è materiale if ( nI <= - 1 || nI >= int( m_nNx[0]) || nJ <= - 1 || nJ >= int( m_nNy[0]) || nK <= - 1 || nK >= int( m_nNy[1])) return false ; // ciclo sulle griglie int nCount = 0 ; for ( int nGrid = 0 ; nGrid < int ( m_nMapNum) ; ++ nGrid) { // assegnazione dati vertice dipendenti dalla griglia unsigned int nGrI, nGrJ ; double dZ ; switch ( nGrid) { case 0 : nGrI = nI ; nGrJ = nJ ; dZ = ( nK + 0.5) * m_dStep ; break ; case 1 : nGrI = nJ ; nGrJ = nK ; dZ = ( nI + 0.5) * m_dStep ; break ; case 2 : nGrI = nK ; nGrJ = nI ; dZ = ( nJ + 0.5) * m_dStep ; break ; } // verifica spillone su vertice size_t nIndex = 0 ; unsigned int nPos = nGrJ * m_nNx[nGrid] + nGrI ; size_t nDexSize = m_Values[nGrid][nPos].size() ; while ( nIndex < nDexSize) { if ( dZ > m_Values[nGrid][nPos][nIndex].dMin - 2 * EPS_SMALL && dZ < m_Values[nGrid][nPos][nIndex].dMax + 2 * EPS_SMALL) { ++ nCount ; break ; } nIndex += 1 ; } } return ( nCount == 3) ; } //---------------------------------------------------------------------------- int VolZmap::CalcIndex( int nI, int nJ, int nK) const { int nIndex = 0 ; if ( IsThereMat( nI, nJ, nK)) nIndex |= ( 1 << 0) ; if ( IsThereMat( nI + 1, nJ, nK)) nIndex |= ( 1 << 1) ; if ( IsThereMat( nI + 1, nJ + 1, nK)) nIndex |= ( 1 << 2) ; if ( IsThereMat( nI, nJ + 1, nK)) nIndex |= ( 1 << 3) ; if ( IsThereMat( nI, nJ, nK + 1)) nIndex |= ( 1 << 4) ; if ( IsThereMat( nI + 1, nJ, nK + 1)) nIndex |= ( 1 << 5) ; if ( IsThereMat( nI + 1, nJ + 1, nK + 1)) nIndex |= ( 1 << 6) ; if ( IsThereMat( nI, nJ + 1, nK + 1)) nIndex |= ( 1 << 7) ; return nIndex ; } //---------------------------------------------------------------------------- bool VolZmap::IntersPos( int nVec1[], int nVec2[], bool bFirstCorner, VectorField& vfField) const { const double dEps = 2 * EPS_SMALL ; bool bFound = false ; if ( nVec1[0] != nVec2[0]) { int nMinI = min( nVec1[0], nVec2[0]) * N_DEXVOXRATIO ; int nMaxI = max( nVec1[0], nVec2[0]) * N_DEXVOXRATIO ; double dMinX = ( nMinI + 0.5) * m_dStep ; double dMaxX = ( nMaxI + 0.5) * m_dStep ; vfField.ptInt.y = ( nVec1[1] * N_DEXVOXRATIO + 0.5) * m_dStep ; vfField.ptInt.z = ( nVec1[2] * N_DEXVOXRATIO + 0.5) * m_dStep ; size_t nDexel = ( nVec1[2] * m_nNx[1] + nVec1[1]) * N_DEXVOXRATIO ; int nSize = int( m_Values[1][nDexel].size()) ; if ( bFirstCorner) { int n = nSize - 1 ; double dX = m_Values[1][nDexel][n].dMax ; while ( n >= 0 && dX > dMinX - dEps) { if ( dX < dMaxX + dEps) { vfField.ptInt.x = dX ; vfField.vtNorm = m_Values[1][nDexel][n].vtMaxN ; vfField.nToolFlag = m_Values[1][nDexel][n].nToolMax ; bFound = true ; break ; } n -= 1 ; if ( n >= 0) dX = m_Values[1][nDexel][n].dMax ; } } else { int n = 0 ; double dX = m_Values[1][nDexel][n].dMin ; while ( n < nSize && dX < dMaxX + dEps) { if ( dX > dMinX - dEps) { vfField.ptInt.x = dX ; vfField.vtNorm = m_Values[1][nDexel][n].vtMinN ; vfField.nToolFlag = m_Values[1][nDexel][n].nToolMin ; bFound = true ; break ; } n += 1 ; if ( n < nSize) dX = m_Values[1][nDexel][n].dMin ; } } if ( ! bFound) vfField.ptInt.x = 0.5 * ( dMinX + dMaxX) ; } else if ( nVec1[1] != nVec2[1]) { int nMinJ = min( nVec1[1], nVec2[1]) * N_DEXVOXRATIO ; int nMaxJ = max( nVec1[1], nVec2[1]) * N_DEXVOXRATIO ; double dMinY = ( nMinJ + 0.5) * m_dStep ; double dMaxY = ( nMaxJ + 0.5) * m_dStep ; vfField.ptInt.x = ( nVec1[0] * N_DEXVOXRATIO + 0.5) * m_dStep ; vfField.ptInt.z = ( nVec1[2] * N_DEXVOXRATIO + 0.5) * m_dStep ; size_t nDexel = ( nVec1[0] * m_nNx[2] + nVec1[2]) * N_DEXVOXRATIO ; int nSize = int( m_Values[2][nDexel].size()) ; if ( bFirstCorner) { int n = nSize - 1 ; double dY = m_Values[2][nDexel][n].dMax ; while ( n >= 0 && dY > dMinY - dEps) { if ( dY < dMaxY + dEps) { vfField.ptInt.y = dY ; vfField.vtNorm = m_Values[2][nDexel][n].vtMaxN ; vfField.nToolFlag = m_Values[2][nDexel][n].nToolMax; bFound = true ; break ; } n -= 1 ; if ( n >= 0) dY = m_Values[2][nDexel][n].dMax ; } } else { int n = 0 ; double dY = m_Values[2][nDexel][n].dMin ; while ( n < nSize && dY < dMaxY + dEps) { if ( dY > dMinY - dEps) { vfField.ptInt.y = dY ; vfField.vtNorm = m_Values[2][nDexel][n].vtMinN ; vfField.nToolFlag = m_Values[2][nDexel][n].nToolMin ; bFound = true ; break ; } n += 1 ; if ( n < nSize) dY = m_Values[2][nDexel][n].dMin ; } } if ( ! bFound) vfField.ptInt.y = 0.5 * ( dMinY + dMaxY) ; } else if ( nVec1[2] != nVec2[2]) { int nMinK = min( nVec1[2], nVec2[2]) * N_DEXVOXRATIO ; int nMaxK = max( nVec1[2], nVec2[2]) * N_DEXVOXRATIO ; double dMinZ = ( nMinK + 0.5) * m_dStep ; double dMaxZ = ( nMaxK + 0.5) * m_dStep ; vfField.ptInt.x = ( nVec1[0] * N_DEXVOXRATIO + 0.5) * m_dStep ; vfField.ptInt.y = ( nVec1[1] * N_DEXVOXRATIO + 0.5) * m_dStep ; size_t nDexel = ( nVec1[1] * m_nNx[0] + nVec1[0]) * N_DEXVOXRATIO ; int nSize = int( m_Values[0][nDexel].size()) ; if ( bFirstCorner) { int n = nSize - 1 ; double dZ = m_Values[0][nDexel][n].dMax ; while ( n >= 0 && dZ > dMinZ - dEps) { if ( dZ < dMaxZ + dEps) { vfField.ptInt.z = dZ ; vfField.vtNorm = m_Values[0][nDexel][n].vtMaxN ; vfField.nToolFlag = m_Values[0][nDexel][n].nToolMax ; bFound = true ; break ; } n -= 1 ; if ( n >= 0) dZ = m_Values[0][nDexel][n].dMax ; } } else { int n = 0 ; double dZ = m_Values[0][nDexel][n].dMin ; while ( n < nSize && dZ < dMaxZ + dEps) { if ( dZ > dMinZ - dEps) { vfField.ptInt.z = dZ ; vfField.vtNorm = m_Values[0][nDexel][n].vtMinN ; vfField.nToolFlag = m_Values[0][nDexel][n].nToolMin ; bFound = true ; break ; } n += 1 ; if ( n < nSize) dZ = m_Values[0][nDexel][n].dMin ; } } if ( ! bFound) vfField.ptInt.z = 0.5 * ( dMinZ + dMaxZ) ; } return bFound ; } //---------------------------------------------------------------------------- bool VolZmap::IsValidVoxel( int nN) const { // Calcolo il numero di voxel lungo X,Y e Z unsigned int nVoxNumX = m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2) ; unsigned int nVoxNumY = m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2) ; unsigned int nVoxNumZ = m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2) ; // Verifico la validità del voxel return ( nN >= 0 && nN < int( nVoxNumX * nVoxNumY * nVoxNumZ)) ; } //---------------------------------------------------------------------------- bool VolZmap::IsValidVoxel( int nI, int nJ, int nK) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Verifico la validità del voxel return ( nI >= - 1 && nI < nVoxNumX - 1 && nJ >= - 1 && nJ < nVoxNumY - 1 && nK >= - 1 && nK < nVoxNumZ - 1 ) ; } //---------------------------------------------------------------------------- bool VolZmap::GetVoxIJKFromN( int nN, int& nI, int& nJ, int& nK) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Controllo sulla validità del voxel if ( nN < 0 || nN >= nVoxNumX * nVoxNumY * nVoxNumZ) return false ; // Calcolo gli indici nI = ( nN % ( nVoxNumX * nVoxNumY)) % nVoxNumX - 1 ; nJ = ( nN % ( nVoxNumX * nVoxNumY)) / nVoxNumX - 1 ; nK = ( nN / ( nVoxNumX * nVoxNumY)) - 1 ; // Controllo la sensatezza del risultato ottenuto return ( nI >= - 1 && nI < nVoxNumX - 1 && nJ >= - 1 && nJ < nVoxNumY - 1 && nK >= - 1 && nK < nVoxNumZ - 1 ) ; } //---------------------------------------------------------------------------- bool VolZmap::GetVoxNFromIJK( int nI, int nJ, int nK, int& nN) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Controllo la validità del voxel if ( nI <= - 2 || nI >= nVoxNumX - 1 || nJ <= - 2 || nJ >= nVoxNumY - 1 || nK <= - 2 || nK >= nVoxNumZ - 1 ) return false ; // Calcolo il numero di Voxel nN = nVoxNumX * nVoxNumY * ( nK + 1) + nVoxNumX * ( nJ + 1) + nI + 1 ; // controllo sulla sensatezza del numero ottenuto return ( nN >= 0 && nN < nVoxNumX * nVoxNumY * nVoxNumZ) ; } //---------------------------------------------------------------------------- bool VolZmap::GetBlockIJKFromN( int nBlock, int nIJK[]) const { // Controllo sulla validità del blocco if ( nBlock < 0 || nBlock >= int( m_nNumBlock)) return false ; // Calcolo posizione del blocco nel reticolo nIJK[0] = ( nBlock % int( m_nFracLin[0] * m_nFracLin[1])) % int( m_nFracLin[0]) ; nIJK[1] = ( nBlock % int( m_nFracLin[0] * m_nFracLin[1])) / int( m_nFracLin[0]) ; nIJK[2] = ( nBlock / int( m_nFracLin[0] * m_nFracLin[1])) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetBlockNFromIJK( int nIJK[], int& nBlock) const { // Controllo sulla validità degli indici i, j, k del blocco if ( nIJK[0] < 0 || nIJK[0] >= int( m_nFracLin[0]) || nIJK[1] < 0 || nIJK[1] >= int( m_nFracLin[1]) || nIJK[2] < 0 || nIJK[2] >= int( m_nFracLin[2])) return false ; // Determino il blocco nBlock = m_nFracLin[0] * m_nFracLin[1] * nIJK[2] + m_nFracLin[0] * nIJK[1] + nIJK[0] ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetBlockLimitsIJK( const int nIJK[], int nLimits[]) const { // Controllo sulla validità degli indici i, j, k del blocco if ( nIJK[0] < 0 || nIJK[0] >= int( m_nFracLin[0]) || nIJK[1] < 0 || nIJK[1] >= int( m_nFracLin[1]) || nIJK[2] < 0 || nIJK[2] >= int( m_nFracLin[2])) return false ; // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Calcolo limiti per l'indice i nLimits[0] = ( nIJK[0] == 0 ? - 1 : nIJK[0] * int( m_nVoxNumPerBlock)) ; nLimits[1] = ( nIJK[0] + 1 == int( m_nFracLin[0]) ? nVoxNumX - 1 : ( nIJK[0] + 1) * int( m_nVoxNumPerBlock)) ; // Calcolo limiti per l'indice j nLimits[2] = ( nIJK[1] == 0 ? - 1 : nIJK[1] * int( m_nVoxNumPerBlock)) ; nLimits[3] = ( nIJK[1] + 1 == int( m_nFracLin[1]) ? nVoxNumY - 1 : ( nIJK[1] + 1) * int( m_nVoxNumPerBlock)) ; // Calcolo limiti per l'indice k nLimits[4] = ( nIJK[2] == 0 ? - 1 : nIJK[2] * int( m_nVoxNumPerBlock)) ; nLimits[5] = ( nIJK[2] + 1 == int( m_nFracLin[2]) ? nVoxNumZ - 1 : ( nIJK[2] + 1) * int( m_nVoxNumPerBlock)) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::IsPointInsideVoxelApprox( int nI, int nJ, int nK, const Point3d& ptP, double dPrec) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Controllo sulla validità del voxel if ( nI <= - 2 || nI >= nVoxNumX - 1 || nJ <= - 2 || nJ >= nVoxNumY - 1 || nK <= - 2 || nK >= nVoxNumZ - 1 ) return false ; // Se la tolleranza è minore di EPS_SMALL, la considero nulla if ( dPrec < EPS_ZERO) dPrec = 0 ; // Controllo che ogni coordinata stia dentro le relative limitazioni del voxel bool bI = ptP.x > ( nI * N_DEXVOXRATIO + 0.5) * m_dStep - dPrec && ptP.x < ( ( nI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep + dPrec ; bool bJ = ptP.y > ( nJ * N_DEXVOXRATIO + 0.5) * m_dStep - dPrec && ptP.y < ( ( nJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep + dPrec ; bool bK = ptP.z > ( nK * N_DEXVOXRATIO + 0.5) * m_dStep - dPrec && ptP.z < ( ( nK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep + dPrec ; return ( bI && bJ && bK) ; } //---------------------------------------------------------------------------- bool VolZmap::GetPointVoxel( const Point3d& ptP, int& nVoxI, int& nVoxJ, int& nVoxK) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Calcolo gli indici del voxel nVoxI = int( floor( ( ptP.x - 0.5 * m_dStep) / ( m_dStep * N_DEXVOXRATIO))) ; nVoxJ = int( floor( ( ptP.y - 0.5 * m_dStep) / ( m_dStep * N_DEXVOXRATIO))) ; nVoxK = int( floor( ( ptP.z - 0.5 * m_dStep) / ( m_dStep * N_DEXVOXRATIO))) ; // Controllo la validità del voxel return ( nVoxI >= - 1 && nVoxI < nVoxNumX - 1) && ( nVoxJ >= - 1 && nVoxJ < nVoxNumY - 1) && ( nVoxK >= - 1 && nVoxK < nVoxNumZ - 1) ; } //---------------------------------------------------------------------------- bool VolZmap::GetVoxelBlockIJK( const int nVoxIJK[], int nBlockIJK[]) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Controllo sull'ammissibilità del voxel if ( nVoxIJK[0] <= - 2 || nVoxIJK[0] >= nVoxNumX - 1 || nVoxIJK[1] <= - 2 || nVoxIJK[1] >= nVoxNumY - 1 || nVoxIJK[2] <= - 2 || nVoxIJK[2] >= nVoxNumZ - 1 ) return false ; // Divisioni intere int nIntRatio0 = nVoxIJK[0] / m_nVoxNumPerBlock ; int nIntRatio1 = nVoxIJK[1] / m_nVoxNumPerBlock ; int nIntRatio2 = nVoxIJK[2] / m_nVoxNumPerBlock ; // Calcolo indici del blocco nBlockIJK[0] = ( nVoxIJK[0] == -1 ? 0 : max( 0, nIntRatio0 - ( nIntRatio0 == m_nFracLin[0] ? 1 : 0))) ; nBlockIJK[1] = ( nVoxIJK[1] == -1 ? 0 : max( 0, nIntRatio1 - ( nIntRatio1 == m_nFracLin[1] ? 1 : 0))) ; nBlockIJK[2] = ( nVoxIJK[2] == -1 ? 0 : max( 0, nIntRatio2 - ( nIntRatio2 == m_nFracLin[2] ? 1 : 0))) ; return true ; } //---------------------------------------------------------------------------- bool VolZmap::GetAdjBlockToBlock( int nBlockN, int nDeltaI, int nDeltaJ, int nDeltaK, int& nAdjBlockN) const { // Test sulla validità degli incrementi su i,j,k if ( nDeltaI < - 1 || nDeltaI > 1 || nDeltaJ < - 1 || nDeltaJ > 1 || nDeltaK < - 1 || nDeltaK > 1) return false ; // Determino blocco adiacente nAdjBlockN = nBlockN ; nAdjBlockN += nDeltaI ; nAdjBlockN += nDeltaJ * m_nFracLin[0] ; nAdjBlockN += nDeltaK * m_nFracLin[0] * m_nFracLin[1] ; // Se il blocco adiacente esiste restituisco vero, altrimenti falso. return ( nAdjBlockN > -1 && nAdjBlockN < int( m_nNumBlock)) ; } //---------------------------------------------------------------------------- bool VolZmap::IsAVoxelOnBoundary( const int nLimits[], const int nIJK[], bool bType) const { // Calcolo il numero di voxel lungo X,Y e Z int nVoxNumX = int( m_nNx[0] / N_DEXVOXRATIO + ( m_nNx[0] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumY = int( m_nNy[0] / N_DEXVOXRATIO + ( m_nNy[0] / N_DEXVOXRATIO == 0 ? 1 : 2)) ; int nVoxNumZ = int( m_nNy[1] / N_DEXVOXRATIO + ( m_nNy[1] % N_DEXVOXRATIO == 0 ? 1 : 2)) ; // Test sulla validità dei limiti if ( nLimits[0] < - 1 || nLimits[0] > nVoxNumX - 1 || nLimits[1] < - 1 || nLimits[1] > nVoxNumX - 1 || nLimits[2] < - 1 || nLimits[2] > nVoxNumY - 1 || nLimits[3] < - 1 || nLimits[3] > nVoxNumY - 1 || nLimits[4] < - 1 || nLimits[4] > nVoxNumZ - 1 || nLimits[5] < - 1 || nLimits[5] > nVoxNumZ - 1 ) return false ; // Controllo sull'ammissibilità del voxel if ( nIJK[0] <= -2 || nIJK[0] > nVoxNumX - 2 || nIJK[1] <= -2 || nIJK[1] > nVoxNumY - 2 || nIJK[2] <= -2 || nIJK[2] > nVoxNumZ - 2) return false ; // Se cerchiamo i voxel che sono sulla frontiera del blocco if ( ! bType) { return ( nIJK[0] == nLimits[0] || nIJK[0] == nLimits[1] - 1 || nIJK[1] == nLimits[2] || nIJK[1] == nLimits[3] - 1 || nIJK[2] == nLimits[4] || nIJK[2] == nLimits[5] - 1) ; } // Altrimenti cerchiamo i voxel che confinano con quelli di altri blocchi // Condizione necessaria è che il voxel sia sulla frontiera if ( nIJK[0] == nLimits[0] || nIJK[0] == nLimits[1] - 1 || nIJK[1] == nLimits[2] || nIJK[1] == nLimits[3] - 1 || nIJK[2] == nLimits[4] || nIJK[2] == nLimits[5] - 1) { // Indici del blocco int nCurrentBlockIJK[3] ; GetVoxelBlockIJK( nIJK, nCurrentBlockIJK) ; // Ciclo sulle possibili posizioni dei voxel adiacenti for ( int nDeltaI = -1 ; nDeltaI <= 1 ; ++ nDeltaI) { for ( int nDeltaJ = -1 ; nDeltaJ <= 1 ; ++ nDeltaJ) { for ( int nDeltaK = -1 ; nDeltaK <= 1 ; ++ nDeltaK) { // Evito controllo con se stesso if ( nDeltaI == 0 && nDeltaJ == 0 && nDeltaK == 0) continue ; // Indici del voxel adiacente int nAdjIJK[3] = { nIJK[0] + nDeltaI, nIJK[1] + nDeltaJ, nIJK[2] + nDeltaK} ; // Determino (se esiste) il blocco in cui cade il voxel adiacente. int nAdjBlockIJK[3] ; if ( GetVoxelBlockIJK( nAdjIJK, nAdjBlockIJK)) { if ( nAdjBlockIJK[0] > -1 && nAdjBlockIJK[0] < int( m_nFracLin[0]) && nAdjBlockIJK[1] > -1 && nAdjBlockIJK[1] < int( m_nFracLin[1]) && nAdjBlockIJK[2] > -1 && nAdjBlockIJK[2] < int( m_nFracLin[2]) && ( nCurrentBlockIJK[0] != nAdjBlockIJK[0] || nCurrentBlockIJK[1] != nAdjBlockIJK[1] || nCurrentBlockIJK[2] != nAdjBlockIJK[2])) { return true ; } } } } } } return false ; } //---------------------------------------------------------------------------- bool VolZmap::IsATriangleOnBorder( const Triangle3dEx& trTria, const Point3d& ptVert, const int nBlockLimits[], const int nVoxIJK[]) const { // Se il triangolo ha area nulla, esco if ( trTria.GetArea() < EPS_SMALL) return false ; // Determino i punti del triangolo sulla griglia int nNotVert[2] ; int nCount = 0 ; for ( int nV = 0 ; nV < 3 ; ++ nV) { if ( SqDist( trTria.GetP( nV), ptVert) > SQ_EPS_SMALL) { if ( nCount == 0) nNotVert[nCount] = nV ; else if ( nCount == 1) nNotVert[nCount] = nV ; nCount ++ ; } } // Se non ho trovato due punti, errore if ( nCount != 2) return false ; // Punti del triangolo sulla griglia Point3d ptFirstGrPt = trTria.GetP( nNotVert[0]) ; Point3d ptSecondGrPt = trTria.GetP( nNotVert[1]) ; // Verifico se tali punti sono sulla griglia for ( int nC = 0 ; nC < 3 ; ++ nC) { if ( nVoxIJK[nC] == nBlockLimits[2*nC]) { double dGrid = ( nBlockLimits[2*nC] * N_DEXVOXRATIO + 0.5) * m_dStep ; if ( abs( ptFirstGrPt.v[nC] - dGrid) < EPS_SMALL && abs( ptSecondGrPt.v[nC] - dGrid) < EPS_SMALL) return true ; } if ( nVoxIJK[nC] + 1 == nBlockLimits[2*nC+1]) { double dGrid = ( nBlockLimits[2*nC+1] * N_DEXVOXRATIO + 0.5) * m_dStep ; if ( abs( ptFirstGrPt.v[nC] - dGrid) < EPS_SMALL && abs( ptSecondGrPt.v[nC] - dGrid) < EPS_SMALL) return true ; } } return false ; } //---------------------------------------------------------------------------- bool VolZmap::ProcessVoxContXY( VoxelContainer& VoxContXY, bool bPlus, TRIA3DEXLIST& lstTria) const { VoxelContainer::iterator it = VoxContXY.begin() ; while ( it != VoxContXY.end()) { int nN = ( *it).first ; int nI, nJ, nK ; GetVoxIJKFromN( nN, nI, nJ, nK) ; // Costruzione del primo rettangolo: un singolo voxel int nMinI = nI ; int nMinJ = nJ ; int nMaxI = nI ; int nMaxJ = nJ ; int nToolNum = ( *it).second.nTool ; double dCordZ = ( *it).second.dHeigth ; // Flag sul ritrovamento di un rettangolo più grande. bool bOkI = true ; bool bOkJ = true ; while ( bOkI || bOkJ) { // Se precedente espansione ok e lato I più lungo o non ok J if ( bOkI && ( nMaxI - nMinI >= nMaxJ - nMinJ || ! bOkJ)) { // Analizzo linea superiore bool bSupJ = true ; for ( int i = nMinI ; bSupJ && i <= nMaxI ; ++ i) { if ( ! Find( VoxContXY, i, nMaxJ + 1, nK, dCordZ, nToolNum)) bSupJ = false ; } // Se linea superiore accettata, elimino i voxel if ( bSupJ) { for ( int i = nMinI ; i <= nMaxI ; ++ i) Remove( VoxContXY, i, nMaxJ + 1, nK) ; ++ nMaxJ ; } // Analizzo linea inferiore bool bInfJ = true ; for ( int i = nMinI ; bInfJ && i <= nMaxI ; ++ i) { if ( ! Find( VoxContXY, i, nMinJ - 1, nK, dCordZ, nToolNum)) bInfJ = false ; } // Se linea inferiore accettata, elimino i voxel if ( bInfJ) { for ( int i = nMinI ; i <= nMaxI ; ++ i) Remove( VoxContXY, i, nMinJ - 1, nK) ; -- nMinJ ; } bOkI = bSupJ || bInfJ ; } // altrimenti se precedente espansione J ok else if ( bOkJ) { // Analizzo linea destra bool bSupI = true ; for ( int j = nMinJ ; bSupI && j <= nMaxJ ; ++ j) { if ( ! Find( VoxContXY, nMaxI + 1, j, nK, dCordZ, nToolNum)) bSupI = false ; } // Se linea destra accettata, elimino i voxel if ( bSupI) { for ( int j = nMinJ ; j <= nMaxJ ; ++ j) Remove( VoxContXY, nMaxI + 1, j, nK) ; ++ nMaxI ; } // Analizzo linea sinistra bool bInfI = true ; for ( int j = nMinJ ; bInfI && j <= nMaxJ ; ++ j) { if ( ! Find( VoxContXY, nMinI - 1, j, nK, dCordZ, nToolNum)) bInfI = false ; } // Se linea sinistra accettata, elimino i voxel if ( bInfI) { for ( int j = nMinJ ; j <= nMaxJ ; ++ j) Remove( VoxContXY, nMinI - 1, j, nK) ; -- nMinI ; } bOkJ = bSupI || bInfI ; } } Point3d ptT0( ( nMinI * N_DEXVOXRATIO + 0.5) * m_dStep, ( nMinJ * N_DEXVOXRATIO + 0.5) * m_dStep, dCordZ) ; Point3d ptT1( ( ( nMaxI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( nMinJ * N_DEXVOXRATIO + 0.5) * m_dStep), dCordZ) ; Point3d ptT2( ( ( nMaxI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( ( nMaxJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep), dCordZ) ; Point3d ptT3( ( nMinI * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( ( nMaxJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep), dCordZ) ; ptT0.ToGlob( m_MapFrame) ; ptT1.ToGlob( m_MapFrame) ; ptT2.ToGlob( m_MapFrame) ; ptT3.ToGlob( m_MapFrame) ; Triangle3dEx Tria0, Tria1 ; if ( bPlus) { Tria0.Set( ptT0, ptT1, ptT3) ; Tria1.Set( ptT1, ptT2, ptT3) ; } else { Tria0.Set( ptT0, ptT3, ptT1) ; Tria1.Set( ptT1, ptT3, ptT2) ; } Tria0.SetGrade( nToolNum) ; Tria1.SetGrade( nToolNum) ; bool bV0 = Tria0.Validate( true) ; bool bV1 = Tria1.Validate( true) ; // Aggiungo alla lista lstTria.emplace_back( Tria0) ; lstTria.emplace_back( Tria1) ; // Elimino il voxel da cui sono partito a ingrandire. VoxContXY.erase( nN) ; // Passo al primo voxel rimasto it = VoxContXY.begin() ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::ProcessVoxContYZ( VoxelContainer& VoxContYZ, bool bPlus, TRIA3DEXLIST& lstTria) const { VoxelContainer::iterator it = VoxContYZ.begin() ; while ( it != VoxContYZ.end()) { int nN = ( *it).first ; int nI, nJ, nK ; GetVoxIJKFromN( nN, nI, nJ, nK) ; // Costruzione del primo rettangolo: un singolo voxel int nMinJ = nJ ; int nMinK = nK ; int nMaxJ = nJ ; int nMaxK = nK ; int nToolNum = ( *it).second.nTool ; double dCordX = ( *it).second.dHeigth ; // Flag sul ritrovamento di un rettangolo più grande. bool bOkJ = true ; bool bOkK = true ; while ( bOkJ || bOkK) { // Se precedente espansione ok e lato J più lungo o non ok K if ( bOkJ && ( nMaxJ - nMinJ >= nMaxK - nMinK || ! bOkK)) { // Analizzo linea superiore bool bSupK = true ; for ( int j = nMinJ ; bSupK && j <= nMaxJ ; ++ j) { if ( ! Find( VoxContYZ, nI, j, nMaxK + 1, dCordX, nToolNum)) bSupK = false ; } // Se linea superiore accettata, elimino i voxel if ( bSupK) { for ( int j = nMinJ ; j <= nMaxJ ; ++ j) Remove( VoxContYZ, nI, j, nMaxK + 1) ; ++ nMaxK ; } // Analizzo linea inferiore bool bInfK = true ; for ( int j = nMinJ ; bInfK && j <= nMaxJ ; ++ j) { if ( ! Find( VoxContYZ, nI, j, nMinK - 1, dCordX, nToolNum)) bInfK = false ; } // Se linea inferiore accettata, elimino i voxel if ( bInfK) { for ( int j = nMinJ ; j <= nMaxJ ; ++ j) Remove( VoxContYZ, nI, j, nMinK - 1) ; -- nMinK ; } bOkJ = bSupK || bInfK ; } // altrimenti se precedente espansione K ok else if ( bOkK) { // Analizzo linea destra bool bSupJ = true ; for ( int k = nMinK ; bSupJ && k <= nMaxK ; ++ k) { if ( ! Find( VoxContYZ, nI, nMaxJ + 1, k, dCordX, nToolNum)) bSupJ = false ; } // Se linea destra accettata, elimino i voxel if ( bSupJ) { for ( int k = nMinK ; k <= nMaxK ; ++ k) Remove( VoxContYZ, nI, nMaxJ + 1, k) ; ++ nMaxJ ; } // Analizzo linea sinistra bool bInfJ = true ; for ( int k = nMinK ; bInfJ && k <= nMaxK ; ++ k) { if ( ! Find( VoxContYZ, nI, nMinJ - 1, k, dCordX, nToolNum)) bInfJ = false ; } // Se linea sinistra accettata, elimino i voxel if ( bInfJ) { for ( int k = nMinK ; k <= nMaxK ; ++ k) Remove( VoxContYZ, nI, nMinJ - 1, k) ; -- nMinJ ; } bOkK = bSupJ || bInfJ ; } } Point3d ptT0( dCordX, ( nMinJ * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( nMinK * N_DEXVOXRATIO + 0.5) * m_dStep)) ; Point3d ptT1( dCordX, ( ( nMaxJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( nMinK * N_DEXVOXRATIO + 0.5) * m_dStep)) ; Point3d ptT2( dCordX, ( ( nMaxJ + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( ( nMaxK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep)) ; Point3d ptT3( dCordX, ( nMinJ * N_DEXVOXRATIO + 0.5) * m_dStep, ( ( ( nMaxK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep)) ; ptT0.ToGlob( m_MapFrame) ; ptT1.ToGlob( m_MapFrame) ; ptT2.ToGlob( m_MapFrame) ; ptT3.ToGlob( m_MapFrame) ; Triangle3dEx Tria0, Tria1 ; if ( bPlus) { Tria0.Set( ptT0, ptT1, ptT3) ; Tria1.Set( ptT1, ptT2, ptT3) ; } else { Tria0.Set( ptT0, ptT3, ptT1) ; Tria1.Set( ptT1, ptT3, ptT2) ; } Tria0.SetGrade( nToolNum) ; Tria1.SetGrade( nToolNum) ; bool bV0 = Tria0.Validate( true) ; bool bV1 = Tria1.Validate( true) ; // Aggiungo alla lista lstTria.emplace_back( Tria0) ; lstTria.emplace_back( Tria1) ; // Elimino il voxel da cui sono partito a ingrandire. VoxContYZ.erase( nN) ; // Passo al primo voxel rimasto it = VoxContYZ.begin() ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::ProcessVoxContXZ( VoxelContainer& VoxContXZ, bool bPlus, TRIA3DEXLIST& lstTria) const { VoxelContainer::iterator it = VoxContXZ.begin() ; while ( it != VoxContXZ.end()) { int nN = ( *it).first ; int nI, nJ, nK ; GetVoxIJKFromN( nN, nI, nJ, nK) ; // Costruzione del primo rettangolo: un singolo voxel int nMinI = nI ; int nMinK = nK ; int nMaxI = nI ; int nMaxK = nK ; int nToolNum = ( *it).second.nTool ; double dCordY = ( *it).second.dHeigth ; // Flag sul ritrovamento di un rettangolo più grande. bool bOkI = true ; bool bOkK = true ; while ( bOkI || bOkK) { // Se lato I più lungo e precedente espansione ok if ( bOkI && ( nMaxI - nMinI >= nMaxK - nMinK || ! bOkK)) { // Analizzo linea superiore bool bSupK = true ; for ( int i = nMinI ; bSupK && i <= nMaxI ; ++ i) { if ( ! Find( VoxContXZ, i, nJ, nMaxK + 1, dCordY, nToolNum)) bSupK = false ; } // Se linea superiore accettata, elimino i voxel if ( bSupK) { for ( int i = nMinI ; i <= nMaxI ; ++ i) Remove( VoxContXZ, i, nJ, nMaxK + 1) ; ++ nMaxK ; } // Analizzo linea inferiore bool bInfK = true ; for ( int i = nMinI ; bInfK && i <= nMaxI ; ++ i) { if ( ! Find( VoxContXZ, i, nJ, nMinK - 1, dCordY, nToolNum)) bInfK = false ; } // Se linea inferiore accettata, elimino i voxel if ( bInfK) { for ( int i = nMinI ; i <= nMaxI ; ++ i) Remove( VoxContXZ, i, nJ, nMinK - 1) ; -- nMinK ; } bOkI = bSupK || bInfK ; } // altrimenti se precedente espansione K ok else if ( bOkK) { // Analizzo linea destra bool bSupI = true ; for ( int k = nMinK ; bSupI && k <= nMaxK ; ++ k) { if ( ! Find( VoxContXZ, nMaxI + 1, nJ, k, dCordY, nToolNum)) bSupI = false ; } // Se linea destra accettata, elimino i voxel if ( bSupI) { for ( int k = nMinK ; k <= nMaxK ; ++ k) Remove( VoxContXZ, nMaxI + 1, nJ, k) ; ++ nMaxI ; } // Analizzo linea sinistra bool bInfI = true ; for ( int k = nMinK ; bInfI && k <= nMaxK ; ++ k) { if ( ! Find( VoxContXZ, nMinI - 1, nJ, k, dCordY, nToolNum)) bInfI = false ; } // Se linea sinistra accettata, elimino i voxel if ( bInfI) { for ( int k = nMinK ; k <= nMaxK ; ++ k) Remove( VoxContXZ, nMinI - 1, nJ, k) ; -- nMinI ; } bOkK = bSupI || bInfI ; } } Point3d ptT0( ( nMinI * N_DEXVOXRATIO + 0.5) * m_dStep, dCordY, ( ( nMinK * N_DEXVOXRATIO + 0.5) * m_dStep)) ; Point3d ptT1( ( ( nMaxI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, dCordY, ( ( nMinK * N_DEXVOXRATIO + 0.5) * m_dStep)) ; Point3d ptT2( ( ( nMaxI + 1) * N_DEXVOXRATIO + 0.5) * m_dStep, dCordY, ( ( ( nMaxK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep)) ; Point3d ptT3( ( nMinI * N_DEXVOXRATIO + 0.5) * m_dStep, dCordY, ( ( ( nMaxK + 1) * N_DEXVOXRATIO + 0.5) * m_dStep)) ; ptT0.ToGlob( m_MapFrame) ; ptT1.ToGlob( m_MapFrame) ; ptT2.ToGlob( m_MapFrame) ; ptT3.ToGlob( m_MapFrame) ; Triangle3dEx Tria0, Tria1 ; if ( bPlus) { Tria0.Set( ptT0, ptT3, ptT1) ; Tria1.Set( ptT1, ptT3, ptT2) ; } else { Tria0.Set( ptT0, ptT1, ptT3) ; Tria1.Set( ptT1, ptT2, ptT3) ; } Tria0.SetGrade( nToolNum) ; Tria1.SetGrade( nToolNum) ; bool bV0 = Tria0.Validate( true) ; bool bV1 = Tria1.Validate( true) ; // Aggiungo alla lista lstTria.emplace_back( Tria0) ; lstTria.emplace_back( Tria1) ; // Elimino il voxel da cui sono partito a ingrandire. VoxContXZ.erase( nN) ; // Passo al primo voxel rimasto it = VoxContXZ.begin() ; } return true ; } //---------------------------------------------------------------------------- bool VolZmap::Find( const VoxelContainer& VoxCont, int nI, int nJ, int nK, double dPos, int nTool) const { // indice globale del voxel int nN ; if ( ! GetVoxNFromIJK( nI, nJ, nK, nN)) return false ; // cerco il voxel nel contenitore auto iter = VoxCont.find( nN) ; return ( iter != VoxCont.end() && abs( dPos - ( *iter).second.dHeigth) < EPS_SMALL && nTool == ( *iter).second.nTool) ; } //---------------------------------------------------------------------------- bool VolZmap::Remove( VoxelContainer& VoxCont, int nI, int nJ, int nK) const { int nN ; if ( ! GetVoxNFromIJK( nI, nJ, nK, nN)) return false ; return ( VoxCont.erase( nN) > 0) ; }