From fa71f3c38d4b27a8725d2495028ee503a6ee825a Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 16 Jul 2026 09:20:13 +0200 Subject: [PATCH 1/2] EgtGeomKernel : - aggiunto parametro alla CreateFromSurfTm di VolZMap per poter lavorare anche con una SurfTm non chiusa per colpa di crepe. - aggiunte sottofunzioni relative. --- VolZmap.h | 19 ++++- VolZmapCreation.cpp | 188 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 195 insertions(+), 12 deletions(-) diff --git a/VolZmap.h b/VolZmap.h index 24cb4b9..5f5dfb0 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -37,6 +37,19 @@ struct AppliedVector { int nPropIndex ; } ; +struct IntersToCheck { + Point3d ptInters ; + Vector3d vtN ; + double dU ; + int nG ; + int nI ; + int nJ ; + IntersToCheck( const Point3d& _ptI, const Vector3d& _vtN, double _dU, int _nG, int _nI, int _nJ) : + ptInters( _ptI), vtN( _vtN), dU( _dU), nG( _nG), nI( _nI), nJ( _nJ) { ;} +}; + +typedef std::vector INTTOCHECKVEC ; + //---------------------------------------------------------------------------- class VolZmap : public IVolZmap, public IGeoObjRW { @@ -84,7 +97,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW bool Create( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex, int* nError = nullptr) override ; bool CreateEmpty( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex, int* nError = nullptr) override ; bool CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double dStep, bool bTriDex, int* nError = nullptr) override ; - bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 0, int* nError = nullptr) override ; + bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 0, int* nError = nullptr, bool bForceClosed = false) override ; int GetBlockCount( void) const override ; int GetBlockUpdatingCounter( int nBlock) const override ; bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ; @@ -463,11 +476,13 @@ class VolZmap : public IVolZmap, public IGeoObjRW bool CDeSimpleTorus( const Frame3d& frTorus, double dMaxRad, double dMinRad, bool bPrecise = false) const ; // Funzione per crezione solido in parallelo bool CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, - const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, INTTOCHECKVEC& vIntToCheck) ; bool AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; bool SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; + bool AdjustDexelThroughCracks( const std::vector& vvIntersToCheck) ; + INTINTVECTOR GetNeighbours( int nG, int nI, int nJ) ; // Funzioni per Offset di superfici bool InitVolZMapOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; bool InitVolZMapThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp index 696dfaf..bc8e425 100644 --- a/VolZmapCreation.cpp +++ b/VolZmapCreation.cpp @@ -19,6 +19,7 @@ #include "GeoConst.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" +#include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EgtNumUtils.h" #include @@ -542,7 +543,7 @@ VolZmap::CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double //---------------------------------------------------------------------------- bool VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, - const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, INTTOCHECKVEC& vIntToCheck) { if ( nMap < 0 || nMap > 2 || nInfI < 0 || nInfI > m_nNx[nMap] || @@ -592,6 +593,14 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co for ( int k = 0 ; k < nInt ; ++ k) { + if ( k > 0) { + int z = k - 1 ; + // controllo se l'intersezione corrente è coincidente con la precedente, per esempio se ILTT == 4 ( intersezione su un lato di un triangolo, quindi con 2 triangoli) + if ( IntersectionResults[k].dU - IntersectionResults[z].dU < EPS_SMALL && + IntersectionResults[k].dCosDN - IntersectionResults[z].dCosDN < EPS_SMALL) + continue ; + } + int nIntType = IntersectionResults[k].nILTT ; // Se c'è intersezione @@ -601,7 +610,12 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co // entro nella superficie trimesh if ( dCos < - dCosSmall) { - + if ( bInside) { + // salvo la precedente, perché vuol dire che manca la sua uscita + // poi procedo con l'intersezione corrente + int z = k - 1 ; + vIntToCheck.emplace_back( IntersectionResults[z].ptI, vtInN, IntersectionResults[z].dU, nMap, i, j) ; + } ptIn = IntersectionResults[k].ptI ; int nT = IntersectionResults[k].nT ; @@ -613,8 +627,7 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co } // esco dalla superficie trimesh - else if ( dCos > dCosSmall && bInside) { - + else if ( dCos > dCosSmall) { Point3d ptOut = IntersectionResults[k].ptI ; int nT = IntersectionResults[k].nT ; @@ -623,6 +636,13 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co Vector3d vtOutN ; Surf.GetFacetNormal( nF, vtOutN) ; + if ( ! bInside) { + // se l'intersezione è uscente, ma non ho un'entrata allora devo salvare l'intersezione corrente, perché è andata persa la sua entrata + // procedo poi con la prossima intersezione + vIntToCheck.emplace_back( IntersectionResults[k].ptI, vtOutN, IntersectionResults[k].dU, nMap, i, j) ; + continue ; + } + int nCurrentSize = int( m_Values[nMap][nPos].size()) ; // Aggiungo un tratto al dexel @@ -834,11 +854,14 @@ VolZmap::SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, //---------------------------------------------------------------------------- bool -VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox, int* nError) +VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox, int* nError, bool bForceClosed) { // Se la superficie non è chiusa oppure orientata al contrario non ha senso continuare double dVol ; - if ( ! Surf.IsClosed() || ! Surf.GetVolume( dVol) || dVol < 0) + if ( ( ! Surf.IsClosed() || ! Surf.GetVolume( dVol) || dVol < 0) && ! bForceClosed) + return false ; + + if ( bForceClosed && ! bTriDex) return false ; // Assegno la dimensione della mappa 1 o 3 @@ -925,6 +948,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // ciclo sulle griglie bool bCompleted = true ; + vector vvIntersToCheck(3) ; for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) { // Definisco dei sistemi di riferimento ausiliari @@ -940,7 +964,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex IntersParLinesSurfTm intPLSTM( frMapFrame, Surf) ; // Standarda è multithread - constexpr bool MULTITHREAD = true ; + constexpr bool MULTITHREAD = false ; if ( MULTITHREAD) { // Numero massimo di thread @@ -956,7 +980,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex nInfI = nSupI ; nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG, - nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ; + nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM), ref(vvIntersToCheck[nG])) ; } } else { @@ -968,7 +992,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex nInfJ = nSupJ ; nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG, - 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ; + 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM), ref(vvIntersToCheck[nG])) ; } } @@ -987,7 +1011,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // !!!! NON MULTITHREAD : SOLO PER DEBUG !!!! else { - CreateMapPart( nG, 0, m_nNx[nG], 0, m_nNy[nG], vtLen, ptMapOrig, Surf, intPLSTM) ; + CreateMapPart( nG, 0, m_nNx[nG], 0, m_nNy[nG], vtLen, ptMapOrig, Surf, intPLSTM, vvIntersToCheck[nG]) ; } } @@ -1003,8 +1027,152 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // Con espansione non va considerato box (calcolo trimesh va in crash) m_nShape = ( dExtraBox <= EPS_ZERO && IsBox() ? BOX : GENERIC) ; + if ( bForceClosed) { + if ( ! AdjustDexelThroughCracks( vvIntersToCheck)) { + Clear() ; + if ( nError != nullptr) + *nError = 2 ; + return false ; + } + } + // Aggiornamento dello stato m_nStatus = OK ; return bCompleted ; } + +INTINTVECTOR +VolZmap::GetNeighbours( int nG, int nI, int nJ) +{ + INTINTVECTOR vNeigh ; + // parto da in basso a sinistra e procedo per righe, saltando il punto corrente + if ( nI > 0 && nJ > 0) + vNeigh.emplace_back( nI - 1, nJ - 1) ; + if ( nJ > 0) { + vNeigh.emplace_back( nI, nJ - 1) ; + if ( nI < m_nNx[nG] - 1) + vNeigh.emplace_back( nI + 1, nJ - 1) ; + } + // passo alla fila contenente il punto corrente + if ( nI > 0) + vNeigh.emplace_back( nI - 1, nJ) ; + if ( nI < m_nNx[nG] - 1) + vNeigh.emplace_back( nI + 1, nJ) ; + // passo alla fila successiva a quella del corrente + if ( nJ < m_nNy[nG] - 1) { + if ( nI > 0) + vNeigh.emplace_back( nI - 1, nJ + 1) ; + vNeigh.emplace_back( nI, nJ + 1) ; + if ( nI < m_nNx[nG]) + vNeigh.emplace_back( nI + 1, nJ + 1) ; + } + return vNeigh ; +} + +//---------------------------------------------------------------------------- +bool +VolZmap::AdjustDexelThroughCracks( const std::vector& vvIntToCheck) +{ + // per ogni intersezione segnalata devo cercare sugli spilloni vicini l'intervallo con l'estremo più vicino a questa intersezione + // e usare l'altro estremo, insieme a quello degli altri spilloni vicini, per estrapolare quello mancante sullo spillone corrente + for ( int nG = 0 ; nG < m_nMapNum ; ++nG) { + Vector3d vtAx ; + if ( nG == 0) + vtAx = Z_AX ; + else if ( nG == 1) + vtAx = X_AX ; + else if ( nG == 2) + vtAx = Y_AX ; + for ( const auto& itc : vvIntToCheck[nG]) { + INTINTVECTOR vNeigh = GetNeighbours( nG, itc.nI, itc.nJ) ; + int nPos = itc.nJ * m_nNx[nG] + itc.nI ; + PNTVECTOR vNeighInters ; + double dPosRef = itc.ptInters.z ; + Vector3d vtMeanN = V_NULL ; + bool bSearchingInOrOut = itc.vtN * vtAx > 0 ; + for ( const auto& [i,j] : vNeigh) { + double dMinDist = INFINITO ; + double dNearestPos = NAN ; + Vector3d vtNearestN ; + int nNeighPos = j * m_nNx[nG] + i ; + for ( const auto& data: m_Values[nG][nNeighPos]) { + double dDist1 = abs( dPosRef - data.dMin) ; + double dDist2 = abs( dPosRef - data.dMax) ; + if ( dDist1 < dMinDist || dDist2 < dMinDist) { + dMinDist = min( dDist1, dDist2) ; + + // se sto cercando un ingresso + if ( bSearchingInOrOut) { + if ( data.vtMaxN * vtAx < 0) { + dNearestPos = data.dMax ; + vtNearestN = data.vtMaxN ; + } + else if ( data.vtMinN * vtAx < 0) { + dNearestPos = data.dMin ; + vtNearestN = data.vtMinN ; + } + } + else { + if ( data.vtMaxN * vtAx > 0) { + dNearestPos = data.dMax ; + vtNearestN = data.vtMaxN ; + } + else if ( data.vtMinN * vtAx > 0) { + dNearestPos = data.dMin ; + vtNearestN = data.vtMinN ; + } + } + } + } + if ( isfinite( dNearestPos)) { + double dX = ( i + 0.5) * m_dStep ; + double dY = ( j + 0.5) * m_dStep ; + vNeighInters.emplace_back( dX, dY, dNearestPos) ; + vtMeanN += vtNearestN ; + } + } + vtMeanN.Normalize() ; + Plane3d plLoc ; + PolyLine PL ; PL.FromPointVector( vNeighInters) ; + PL.IsFlat( plLoc, INFINITO) ; + Point3d ptInt ; + // porto anche il punto dell'intersezione nel frame della griglia + Point3d ptKnown = itc.ptInters ; + Frame3d frGrid ; + if ( nG == 0) + frGrid.Set( ORIG, Frame3d::TOP) ; + else if ( nG == 1) + frGrid.Set( ORIG, Frame3d::RIGHT) ; + else if ( nG == 2) + frGrid.Set( ORIG, Z_AX, X_AX, Y_AX) ; + ptKnown.ToLoc( frGrid) ; + IntersLinePlane( ptKnown, Z_AX, INFINITO, plLoc, ptInt, false) ; + + double dMin, dMax ; + Vector3d vtMinN, vtMaxN ; + if ( itc.dU < ptInt.z) { + dMin = itc.dU ; + dMax = ptInt.z ; + vtMinN = itc.vtN ; + vtMaxN = vtMeanN ; + } + else { + dMin = ptInt.z ; + dMax = itc.dU ; + vtMinN = vtMeanN ; + vtMaxN = itc.vtN ; + } + m_Values[nG][nPos].emplace_back() ; + m_Values[nG][nPos].back().dMin = dMin; + m_Values[nG][nPos].back().dMax = dMax ; + m_Values[nG][nPos].back().vtMinN = vtMinN ; + m_Values[nG][nPos].back().vtMaxN = vtMaxN ; + m_Values[nG][nPos].back().nToolMin = 0 ; + m_Values[nG][nPos].back().nToolMax = 0 ; + m_Values[nG][nPos].back().nCompo = 0 ; + std::sort( m_Values[nG][nPos].begin(), m_Values[nG][nPos].end(), []( Data& a, Data& b) { return a.dMin < b.dMin ;}) ; + } + } + return true ; +} \ No newline at end of file From a69be04cf7e1474eb537830d7487535329cfcd0a Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Fri, 17 Jul 2026 17:24:11 +0200 Subject: [PATCH 2/2] EgtGeomKernel : - milgiorie e correzioni alla funzione per ottenere lo ZMap da una trimesh con crack. --- VolZmap.h | 7 +- VolZmapCreation.cpp | 381 ++++++++++++++++++++++++++++++++------------ 2 files changed, 286 insertions(+), 102 deletions(-) diff --git a/VolZmap.h b/VolZmap.h index 5f5dfb0..f782695 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -476,13 +476,14 @@ class VolZmap : public IVolZmap, public IGeoObjRW bool CDeSimpleTorus( const Frame3d& frTorus, double dMaxRad, double dMinRad, bool bPrecise = false) const ; // Funzione per crezione solido in parallelo bool CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, - const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, INTTOCHECKVEC& vIntToCheck) ; + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, bool bForceClosed) ; bool AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; bool SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; - bool AdjustDexelThroughCracks( const std::vector& vvIntersToCheck) ; - INTINTVECTOR GetNeighbours( int nG, int nI, int nJ) ; + bool AdjustDexelThroughCracks( int nG, const Vector3d& vtLen, const INTTOCHECKVEC& vIntToCheck, const Point3d& ptMapOrig, + const ISurfTriMesh& Surf, const IntersParLinesSurfTm& intPLSTM) ; + DBLDBLVECTOR GetNeighbours( int nG, int nI, int nJ, double dPar) ; // Funzioni per Offset di superfici bool InitVolZMapOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; bool InitVolZMapThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp index bc8e425..5fd0fd2 100644 --- a/VolZmapCreation.cpp +++ b/VolZmapCreation.cpp @@ -543,7 +543,7 @@ VolZmap::CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double //---------------------------------------------------------------------------- bool VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, - const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, INTTOCHECKVEC& vIntToCheck) + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, bool bForceClosed) { if ( nMap < 0 || nMap > 2 || nInfI < 0 || nInfI > m_nNx[nMap] || @@ -554,6 +554,8 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co double dCosSmall = sin( EPS_ANG_SMALL * DEGTORAD) ; + INTTOCHECKVEC vIntToCheck ; + // Determinazione e ridimensionamento dei dexel interni alla trimesh for ( int i = nInfI ; i < nSupI ; ++ i) { for ( int j = nInfJ ; j < nSupJ ; ++ j) { @@ -585,6 +587,14 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co int nInt = int( IntersectionResults.size()) ; + if ( nInt == 1) { + int nT = IntersectionResults[0].nT ; + int nF = Surf.GetFacetFromTria( nT) ; + Vector3d vtN ; Surf.GetFacetNormal( nF, vtN) ; + vIntToCheck.emplace_back( IntersectionResults[0].ptI, vtN, IntersectionResults[0].dU, nMap, i, j) ; + continue ; + } + int nPos = j * m_nNx[nMap] + i ; bool bInside = false ; @@ -663,6 +673,12 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co } } } + + if ( bForceClosed) { + if ( ! AdjustDexelThroughCracks( nMap, vtLen, vIntToCheck, ptMapOrig, Surf, intPLSTM)) + return false ; + } + return true ; } @@ -948,7 +964,6 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // ciclo sulle griglie bool bCompleted = true ; - vector vvIntersToCheck(3) ; for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) { // Definisco dei sistemi di riferimento ausiliari @@ -980,7 +995,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex nInfI = nSupI ; nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG, - nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM), ref(vvIntersToCheck[nG])) ; + nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM), bForceClosed) ; } } else { @@ -992,7 +1007,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex nInfJ = nSupJ ; nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG, - 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM), ref(vvIntersToCheck[nG])) ; + 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM), bForceClosed) ; } } @@ -1011,7 +1026,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // !!!! NON MULTITHREAD : SOLO PER DEBUG !!!! else { - CreateMapPart( nG, 0, m_nNx[nG], 0, m_nNy[nG], vtLen, ptMapOrig, Surf, intPLSTM, vvIntersToCheck[nG]) ; + CreateMapPart( nG, 0, m_nNx[nG], 0, m_nNy[nG], vtLen, ptMapOrig, Surf, intPLSTM, bForceClosed) ; } } @@ -1027,116 +1042,174 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // Con espansione non va considerato box (calcolo trimesh va in crash) m_nShape = ( dExtraBox <= EPS_ZERO && IsBox() ? BOX : GENERIC) ; - if ( bForceClosed) { - if ( ! AdjustDexelThroughCracks( vvIntersToCheck)) { - Clear() ; - if ( nError != nullptr) - *nError = 2 ; - return false ; - } - } - // Aggiornamento dello stato m_nStatus = OK ; return bCompleted ; } -INTINTVECTOR -VolZmap::GetNeighbours( int nG, int nI, int nJ) +DBLDBLVECTOR +VolZmap::GetNeighbours( int nG, int nI, int nJ, double dPar) { - INTINTVECTOR vNeigh ; + DBLDBLVECTOR vNeigh ; // parto da in basso a sinistra e procedo per righe, saltando il punto corrente if ( nI > 0 && nJ > 0) - vNeigh.emplace_back( nI - 1, nJ - 1) ; + vNeigh.emplace_back( nI - dPar, nJ - dPar) ; if ( nJ > 0) { - vNeigh.emplace_back( nI, nJ - 1) ; - if ( nI < m_nNx[nG] - 1) - vNeigh.emplace_back( nI + 1, nJ - 1) ; + vNeigh.emplace_back( nI, nJ - dPar) ; + if ( nI < m_nNx[nG] - dPar) + vNeigh.emplace_back( nI + dPar, nJ - dPar) ; } // passo alla fila contenente il punto corrente if ( nI > 0) - vNeigh.emplace_back( nI - 1, nJ) ; - if ( nI < m_nNx[nG] - 1) - vNeigh.emplace_back( nI + 1, nJ) ; + vNeigh.emplace_back( nI - dPar, nJ) ; + if ( nI < m_nNx[nG] - dPar) + vNeigh.emplace_back( nI + dPar, nJ) ; // passo alla fila successiva a quella del corrente - if ( nJ < m_nNy[nG] - 1) { + if ( nJ < m_nNy[nG] - dPar) { if ( nI > 0) - vNeigh.emplace_back( nI - 1, nJ + 1) ; - vNeigh.emplace_back( nI, nJ + 1) ; + vNeigh.emplace_back( nI - dPar, nJ + dPar) ; + vNeigh.emplace_back( nI, nJ + dPar) ; if ( nI < m_nNx[nG]) - vNeigh.emplace_back( nI + 1, nJ + 1) ; + vNeigh.emplace_back( nI + dPar, nJ + dPar) ; } return vNeigh ; } //---------------------------------------------------------------------------- bool -VolZmap::AdjustDexelThroughCracks( const std::vector& vvIntToCheck) +VolZmap::AdjustDexelThroughCracks( int nG, const Vector3d& vtLen, const INTTOCHECKVEC& vIntToCheck, const Point3d& ptMapOrig, + const ISurfTriMesh& Surf, const IntersParLinesSurfTm& intPLSTM) { + double dAngSameFace = 45 ; + double dCosSmall = sin( EPS_ANG_SMALL * DEGTORAD) ; // per ogni intersezione segnalata devo cercare sugli spilloni vicini l'intervallo con l'estremo più vicino a questa intersezione // e usare l'altro estremo, insieme a quello degli altri spilloni vicini, per estrapolare quello mancante sullo spillone corrente - for ( int nG = 0 ; nG < m_nMapNum ; ++nG) { - Vector3d vtAx ; - if ( nG == 0) - vtAx = Z_AX ; - else if ( nG == 1) - vtAx = X_AX ; - else if ( nG == 2) - vtAx = Y_AX ; - for ( const auto& itc : vvIntToCheck[nG]) { - INTINTVECTOR vNeigh = GetNeighbours( nG, itc.nI, itc.nJ) ; - int nPos = itc.nJ * m_nNx[nG] + itc.nI ; - PNTVECTOR vNeighInters ; - double dPosRef = itc.ptInters.z ; - Vector3d vtMeanN = V_NULL ; - bool bSearchingInOrOut = itc.vtN * vtAx > 0 ; - for ( const auto& [i,j] : vNeigh) { - double dMinDist = INFINITO ; - double dNearestPos = NAN ; - Vector3d vtNearestN ; - int nNeighPos = j * m_nNx[nG] + i ; - for ( const auto& data: m_Values[nG][nNeighPos]) { - double dDist1 = abs( dPosRef - data.dMin) ; - double dDist2 = abs( dPosRef - data.dMax) ; - if ( dDist1 < dMinDist || dDist2 < dMinDist) { - dMinDist = min( dDist1, dDist2) ; + Vector3d vtAx ; + if ( nG == 0) + vtAx = Z_AX ; + else if ( nG == 1) + vtAx = X_AX ; + else if ( nG == 2) + vtAx = Y_AX ; + for ( const auto& itc : vIntToCheck) { + int nPos = itc.nJ * m_nNx[nG] + itc.nI ; + double dPosRef = itc.ptInters.v[( nG + 2) % 3] ; + // controllo se esiste già un intervallo con un estremo quasi coincidente a quello segnalato + // ed entrambi sono entrate o uscite + bool bNeedToReconstruct = true ; + for ( const auto& data: m_Values[nG][nPos]) { + if ( (( abs( dPosRef - data.dMin) < 10 * EPS_SMALL && ( itc.vtN * vtAx) * ( data.vtMinN * vtAx) > 0)) || + (( abs( dPosRef - data.dMax) < 10 * EPS_SMALL && ( itc.vtN * vtAx) * ( data.vtMaxN * vtAx) > 0))) { + bNeedToReconstruct = false ; + break ; + } + } + if ( ! bNeedToReconstruct) + continue ; + DBLDBLVECTOR vNeigh = GetNeighbours( nG, itc.nI, itc.nJ, m_dStep) ; + PNTVECTOR vNeighInters ; + Vector3d vtMeanN = V_NULL ; + bool bSearchingInOrOut = itc.vtN * vtAx > 0 ; + bool bUseNeighInfo = true ; + for ( const auto& [i,j] : vNeigh) { + double dMinDist = INFINITO ; + double dCorrespInters = INFINITO ; + double dNearestPos = NAN ; + Vector3d vtNearestN ; + int nNeighPos = int( j) * m_nNx[nG] + int( i) ; + for ( const auto& data: m_Values[nG][nNeighPos]) { + double dDist1 = abs( dPosRef - data.dMin) ; + double dDist2 = abs( dPosRef - data.dMax) ; + if ( dDist1 < dMinDist || dDist2 < dMinDist) { + dMinDist = min( dDist1, dDist2) ; - // se sto cercando un ingresso - if ( bSearchingInOrOut) { - if ( data.vtMaxN * vtAx < 0) { - dNearestPos = data.dMax ; - vtNearestN = data.vtMaxN ; - } - else if ( data.vtMinN * vtAx < 0) { - dNearestPos = data.dMin ; - vtNearestN = data.vtMinN ; - } + // se sto cercando un ingresso + if ( bSearchingInOrOut) { + if ( data.vtMaxN * vtAx < 0) { + dNearestPos = data.dMax ; + vtNearestN = data.vtMaxN ; + dCorrespInters = data.dMin ; } - else { - if ( data.vtMaxN * vtAx > 0) { - dNearestPos = data.dMax ; - vtNearestN = data.vtMaxN ; - } - else if ( data.vtMinN * vtAx > 0) { - dNearestPos = data.dMin ; - vtNearestN = data.vtMinN ; - } + else if ( data.vtMinN * vtAx < 0) { + dNearestPos = data.dMin ; + vtNearestN = data.vtMinN ; + dCorrespInters = data.dMax ; + } + } + // se sto cercando un'uscita + else { + if ( data.vtMaxN * vtAx > 0) { + dNearestPos = data.dMax ; + vtNearestN = data.vtMaxN ; + dCorrespInters = data.dMin ; + } + else if ( data.vtMinN * vtAx > 0) { + dNearestPos = data.dMin ; + vtNearestN = data.vtMinN ; + dCorrespInters = data.dMax ; } } } - if ( isfinite( dNearestPos)) { + } + // verifico che il dNearestPos sia effettivamente associato al tratto che sto cercando di ricostruire + // e non ad un altro presente sullo spillone corrente + bool bAddNearest = true ; + for ( const auto& data: m_Values[nG][nPos]) { + double dDist1 = abs( dCorrespInters - data.dMin) ; + double dDist2 = abs( dCorrespInters - data.dMax) ; + if ( dDist1 < dMinDist || dDist2 < dMinDist) { + bAddNearest = false ; + break ; + } + } + + if ( bAddNearest && isfinite( dNearestPos)) { + // controllo anche che i punti non siano troppo lontani tra loro, altrimenti + // il piano calcolato potrebbe essere una media troppo grezza + double dMaxDist = 3 * m_dStep ; + const bool bTooFar = any_of( vNeighInters.begin(), vNeighInters.end(), + [ dNearestPos, dMaxDist]( const Point3d& pt) { + return abs( pt.z - dNearestPos) > dMaxDist ; + }) ; + double dAng ; + if ( ! bTooFar) { + // controllo anche che gli angoli delle normali non cambino troppo + // calcolo l'angolo con la media delle precedenti perché il valore oltre cui + // considero le normali diverse è grande + vtNearestN.GetAngle( vtMeanN, dAng) ; + } + bAddNearest = ! bTooFar && dAng < dAngSameFace ; + if ( bAddNearest) { double dX = ( i + 0.5) * m_dStep ; double dY = ( j + 0.5) * m_dStep ; vNeighInters.emplace_back( dX, dY, dNearestPos) ; vtMeanN += vtNearestN ; } + else { + bUseNeighInfo = false ; + break ; + } } + } + Point3d ptInt ; + // se riesco uso i vicini per calcolare l'intersezione mancante + if ( bUseNeighInfo) { + // se non ci sono almeno tre punti, non allineati, non riesco a determinare il piano con cui tagliare lo spillone + if ( ssize( vNeighInters) < 3) + continue ; + else if ( ssize( vNeighInters) == 3){ + // verifico che non siano allineati + if ( ( vNeighInters[0].x == vNeighInters[1].x && vNeighInters[0].x == vNeighInters[1].x) || + ( vNeighInters[0].y == vNeighInters[1].y && vNeighInters[0].y == vNeighInters[1].y)) + continue ; + } + // se sono più di tre sicuramente non sono allieanti, visto che sono intorno allo spillone corrente vtMeanN.Normalize() ; Plane3d plLoc ; PolyLine PL ; PL.FromPointVector( vNeighInters) ; PL.IsFlat( plLoc, INFINITO) ; - Point3d ptInt ; + // porto anche il punto dell'intersezione nel frame della griglia Point3d ptKnown = itc.ptInters ; Frame3d frGrid ; @@ -1148,31 +1221,141 @@ VolZmap::AdjustDexelThroughCracks( const std::vector& vvIntToChec frGrid.Set( ORIG, Z_AX, X_AX, Y_AX) ; ptKnown.ToLoc( frGrid) ; IntersLinePlane( ptKnown, Z_AX, INFINITO, plLoc, ptInt, false) ; - - double dMin, dMax ; - Vector3d vtMinN, vtMaxN ; - if ( itc.dU < ptInt.z) { - dMin = itc.dU ; - dMax = ptInt.z ; - vtMinN = itc.vtN ; - vtMaxN = vtMeanN ; - } - else { - dMin = ptInt.z ; - dMax = itc.dU ; - vtMinN = vtMeanN ; - vtMaxN = itc.vtN ; - } - m_Values[nG][nPos].emplace_back() ; - m_Values[nG][nPos].back().dMin = dMin; - m_Values[nG][nPos].back().dMax = dMax ; - m_Values[nG][nPos].back().vtMinN = vtMinN ; - m_Values[nG][nPos].back().vtMaxN = vtMaxN ; - m_Values[nG][nPos].back().nToolMin = 0 ; - m_Values[nG][nPos].back().nToolMax = 0 ; - m_Values[nG][nPos].back().nCompo = 0 ; - std::sort( m_Values[nG][nPos].begin(), m_Values[nG][nPos].end(), []( Data& a, Data& b) { return a.dMin < b.dMin ;}) ; } + // altrimenti sposto di poco lo spillone e ricalcolo le intersezioni con la superficie, finché trovo l'intersezione mancante + else { + bool bFound = false ; + DBLVECTOR vSmallStep ; + vSmallStep.push_back( Clamp( 0.05 * m_dStep, 50 * EPS_SMALL, 1.)) ; + vSmallStep.push_back( Clamp( 0.2 * m_dStep, 50 * EPS_SMALL, 1.)) ; + // ciclo una raggiera di spilloni ( a distanza inferiore allo m_dStep) attorno allo spillone + // appena trova un'intersezione buona mi fermo + // se ciclando la raggiera non trovo un'intersezione valida allora potrei essermi spostato troppo poco dallo spillone originale e essere caduto ancora nella fessura + // quindi ciclo nuovamente aumentando un poco la distanza dallo spillone originale ( comunque sempre meno della distanza m_dStep) + for ( int c = 0 ; c < ssize( vSmallStep) ; ++c) { + DBLDBLVECTOR vSmallMoveNeigh = GetNeighbours( nG, itc.nI, itc.nJ, vSmallStep[c]) ; + for ( int n = 0 ; n < 8 ; ++n) { + double dX = ( vSmallMoveNeigh[n].first + 0.5) * m_dStep ; + double dY = ( vSmallMoveNeigh[n].second + 0.5) * m_dStep ; + Point3d ptP0( dX, dY, 0) ; + ILSIVECTOR IntersectionResults ; + intPLSTM.GetInters( ptP0, vtLen.v[(nG+2)%3], IntersectionResults) ; + // intervalli dalle intersezioni + vector vNewIntervals ; + bool bInside = false ; + Vector3d vtInN ; + Point3d ptIn ; + for ( int i = 0 ; i < ssize( IntersectionResults) ; ++i) { + // Se c'è intersezione + if ( IntersectionResults[i].nILTT != ILTT_NO) { + if ( i > 0) { + int z = i - 1 ; + // controllo se l'intersezione corrente è coincidente con la precedente, per esempio se ILTT == 4 ( intersezione su un lato di un triangolo, quindi con 2 triangoli) + if ( IntersectionResults[i].dU - IntersectionResults[z].dU < EPS_SMALL && + IntersectionResults[i].dCosDN - IntersectionResults[z].dCosDN < EPS_SMALL) + continue ; + } + double dCos = IntersectionResults[i].dCosDN ; + // entro nella superficie trimesh + if ( dCos < - dCosSmall) { + ptIn = IntersectionResults[i].ptI ; + + int nT = IntersectionResults[i].nT ; + int nF = Surf.GetFacetFromTria( nT) ; + + Surf.GetFacetNormal( nF, vtInN) ; + + bInside = true ; + } + + // esco dalla superficie trimesh + else if ( dCos > dCosSmall && bInside) { + Point3d ptOut = IntersectionResults[i].ptI ; + + int nT = IntersectionResults[i].nT ; + int nF = Surf.GetFacetFromTria( nT) ; + + Vector3d vtOutN ; + Surf.GetFacetNormal( nF, vtOutN) ; + + // Aggiungo un tratto al dexel + vNewIntervals.emplace_back() ; + + // Aggiorno dati del tratto di dexel + vNewIntervals.back().dMin = ptIn.v[(nG+2)%3] - ptMapOrig.v[(nG+2)%3] ; + vNewIntervals.back().dMax = ptOut.v[(nG+2)%3] - ptMapOrig.v[(nG+2)%3] ; + vNewIntervals.back().vtMinN = vtInN ; + vNewIntervals.back().vtMaxN = vtOutN ; + vNewIntervals.back().nToolMin = 0 ; + vNewIntervals.back().nToolMax = 0 ; + vNewIntervals.back().nCompo = 0 ; + + bInside = false ; + } + } + } + // controllo che abbia un intervallo in più rispetto a quelli di prima + if ( ssize( vNewIntervals) == ssize( m_Values[nG][nPos]) + 1) { + // dovrei verificare che quello in più sia effettivamente quello ricercato???? + double dMinDist = INFINITO ; + for ( const auto& data : vNewIntervals) { + if ( abs( data.dMin - dPosRef) < dMinDist) { + dMinDist = abs( data.dMin - dPosRef) ; + ptInt.Set( itc.nI + 0.5, itc.nJ + 0.5, data.dMax) ; + vtMeanN = data.vtMaxN ; + bFound = true ; + } + if ( abs( data.dMax - dPosRef) < dMinDist) { + dMinDist = abs( data.dMax - dPosRef) ; + ptInt.Set( itc.nI + 0.5, itc.nJ + 0.5, data.dMin) ; + vtMeanN = data.vtMinN ; + bFound = true ; + } + } + } + if ( bFound) + break ; + } + if ( bFound) + break ; + } + // se cercando nei d'intorni dello spillone non ho trovato l'intersezione mancante, mi arrendo + if ( ! bFound) + continue ; + } + + double dMin, dMax ; + Vector3d vtMinN, vtMaxN ; + if ( itc.dU < ptInt.z) { + dMin = itc.dU ; + dMax = ptInt.z ; + vtMinN = itc.vtN ; + vtMaxN = vtMeanN ; + } + else { + dMin = ptInt.z ; + dMax = itc.dU ; + vtMinN = vtMeanN ; + vtMaxN = itc.vtN ; + } + //// prima di aggiungere il tratto verifico che non si sovrapponga con un tratto già presente + //for ( const auto& data: m_Values[nG][nPos]) { + // if ( ( dMin > data.dMin && dMin < data.dMax) || + // ( dMax > data.dMin && dMax < data.dMax) || + // ( dMin < data.dMin && dMax > data.dMax)) + // continue ; + //} + + m_Values[nG][nPos].emplace_back() ; + m_Values[nG][nPos].back().dMin = dMin; + m_Values[nG][nPos].back().dMax = dMax ; + m_Values[nG][nPos].back().vtMinN = vtMinN ; + m_Values[nG][nPos].back().vtMaxN = vtMaxN ; + m_Values[nG][nPos].back().nToolMin = 0 ; + m_Values[nG][nPos].back().nToolMax = 0 ; + m_Values[nG][nPos].back().nCompo = 0 ; + std::sort( m_Values[nG][nPos].begin(), m_Values[nG][nPos].end(), []( Data& a, Data& b) { return a.dMin < b.dMin ;}) ; } + return true ; } \ No newline at end of file