diff --git a/SurfBezier.cpp b/SurfBezier.cpp index ee450d1..cda91d5 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -315,17 +315,30 @@ SurfBezier::GetCentroid( Point3d& ptCen) const return m_pSTM->GetCentroid( ptCen) ; } +mutex mapBernstein ; + //---------------------------------------------------------------------------- bool SurfBezier::GetBernstein( double dU, int nDegU, DBLVECTOR& vBernU) const { INTINT key( nDegU, int( dU * pow(2,24))) ; - if ( m_mBernCache.find( key) == m_mBernCache.end()) { + bool bCalculated = false ; + { + lock_guard lock( mapBernstein) ; + bCalculated = m_mBernCache.find( key) != m_mBernCache.end() ; + } + if ( ! bCalculated) { DBLVECTOR vBern( nDegU + 1) ; GetAllBernstein( dU, nDegU, vBern) ; - m_mBernCache[key] = vBern ; + { + lock_guard lock( mapBernstein) ; + m_mBernCache[key] = vBern ; + } + } + { + lock_guard lock( mapBernstein) ; + vBernU = m_mBernCache.at( key) ; } - vBernU = m_mBernCache[key] ; return true ; } @@ -1620,7 +1633,7 @@ SurfBezier::GetAuxSurf( void) const if ( m_pSTM != nullptr) return m_pSTM ; // eseguo calcolo - m_pSTM = GetApproxSurf( 50 * EPS_SMALL, 100 * EPS_SMALL) ; + m_pSTM = GetApproxSurf( 1000 * EPS_SMALL, 100 * EPS_SMALL) ; return m_pSTM ; } @@ -1959,7 +1972,7 @@ SurfBezier::GetLeaves( vector>& vLeaves) const //Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; // per debug } else { - Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ; + Tree.BuildTree( 100 * LIN_TOL_FINE, 0.1) ; } vector vCells ; Tree.GetLeaves( vCells) ; diff --git a/Tree.cpp b/Tree.cpp index 6080363..e5efc73 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -32,9 +32,6 @@ #include #include #include -#include -#include -#include #include using namespace std ; @@ -109,17 +106,30 @@ Tree::AdjustLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) return true ; } +mutex map3D ; + //---------------------------------------------------------------------------- bool Tree::GetPoint( double dU, double dV, Point3d& pt) const { pair key (static_cast(dU * pow(2,15)), static_cast(dV * pow(2,15))) ; bool bOk = true ; - if ( m_mPt3d.find( key) == m_mPt3d.end()) { - bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt) ; - m_mPt3d[key] = pt ; + bool bCalculated = false ; + { + lock_guard lock( map3D) ; + bCalculated = m_mPt3d.find( key) != m_mPt3d.end() ; + } + if ( ! bCalculated) { + bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt) ; + { + lock_guard lock( map3D) ; + m_mPt3d[key] = pt ; + } + } + { + lock_guard lock( map3D) ; + pt = m_mPt3d[key] ; } - pt = m_mPt3d[key] ; return bOk ; } @@ -128,8 +138,15 @@ bool Tree::SavePoint( double dU, double dV, Point3d& pt) { pair key (static_cast(dU * pow(2,15)), static_cast(dV * pow(2,15))) ; - if ( m_mPt3d.find( key) == m_mPt3d.end()) + bool bCalculated = true ; + { + lock_guard lock( map3D) ; + bCalculated = m_mPt3d.find( key) != m_mPt3d.end() ; + } + if ( ! bCalculated){ + lock_guard lock( map3D) ; m_mPt3d[key] = pt ; + } return true ; } @@ -147,6 +164,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_mChunk.clear() ; m_vPlApprox.clear() ; m_vCCLoop2D.clear() ; + CellCounter = 0 ; m_pSrfBz = pSrfBz ; m_bSplitPatches = bSplitPatches ; @@ -646,24 +664,30 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax) return true ; } +mutex queueMutex ; + //---------------------------------------------------------------------------- void -Tree::BranchManager( queue>& tasks, condition_variable& cv, bool& done) +Tree::BranchManager( queue>& qTasks, condition_variable& cv, bool& done) { while (true) { function task ; { - std::unique_lock lock(mapMutex); - cv.wait(lock, [&tasks, &done]() { return !tasks.empty() || done; }); + std::unique_lock lock( queueMutex) ; + cv.wait(lock, [&qTasks, &done]() { return ! qTasks.empty() || done; }) ; - if (tasks.empty() && done) { - return; + if ( qTasks.empty() && done) { + return ; } - task = move(tasks.front()); - tasks.pop(); + task = std::move( qTasks.front()) ; + qTasks.pop() ; + + // notifico il thread principale che non ci sono più task + if ( qTasks.empty() && ! done) + cv.notify_all() ; } - task(); // Execute the task + task() ; // Execute the task } } @@ -673,85 +697,108 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) { // lancio in parallelo vari thread in modo da calcolare separatamente i branch da ogni foglia attuale int nThreadMax = ( thread::hardware_concurrency()) / 2 ; - int nStartingLeaves = m_vnLeaves.size() ; + int nStartingLeaves = m_vnParents.size() ; condition_variable cv ; vector> vBranches( nStartingLeaves) ; - // ad ogni ramo, metto come cella di partenza una foglia - for ( int i = 0 ; i < nStartingLeaves ; ++i) { - Cell cLeaf = m_mTree.at( i) ; - vBranches[i].insert( pair( i, cLeaf)) ; + INTVECTOR vFirstCells ; + + // creo la coda dei task + queue> qTasks ; + bool done = false ; + for (int i = 0; i < nStartingLeaves; ++i) { + // ad ogni ramo, metto come cella di partenza una foglia + Cell cLeaf = m_mTree.at( m_vnParents[i]) ; + vBranches[i].insert( pair( cLeaf.m_nId, cLeaf)) ; + int nFirst = cLeaf.m_nId ; + vFirstCells.push_back( nFirst) ; + qTasks.emplace([this, i, &vBranches, dLinTol, dSideMin, dSideMax, nFirst] + {Tree::BuildBranch( nFirst, vBranches[i], dLinTol, dSideMin, dSideMax) ;} ) ; } + + // Create worker threads + vector workers ; + for (int i = 0 ; i < nThreadMax ; ++i) + workers.emplace_back( &Tree::BranchManager, this, std::ref( qTasks), std::ref( cv),std::ref( done)) ; - queue> tasks; - // Add tasks to the queue + // dico ai thread di iniziare a lavorare + cv.notify_all() ; + + // Wait for all tasks to be processed { - std::lock_guard lock(queueMutex); - for (int i = 0; i < nStartingLeaves; ++i) { - tasks.emplace([this]() {}); - } + unique_lock lock( queueMutex); + cv.wait( lock, [&qTasks] { return qTasks.empty(); }) ; } - // Notify threads that tasks are available - cv.notify_all(); - - // Mark work as done and notify all threads to exit + // Wait for all tasks to be processed { - std::lock_guard lock(queueMutex); - done = true; - } - cv.notify_all(); - - // Wait for all threads to finish - for (auto& t : threads) { - t.join(); + unique_lock lock( queueMutex) ; + done = true ; } + cv.notify_all() ; - vector>> vectorBranches( nStartingLeaves); + // Join all threads + for ( auto& t : workers) + t.join() ; - // Step 1: Convert each map to a vector in parallel - for_each(execution::par, vectorBranches.begin(), vectorBranches.end(), - [&](auto& map) { - size_t index = &map - &vectorBranches[0]; // Get the index of the current map - vectorBranches[index].assign( make_move_iterator(map.begin()), - make_move_iterator(map.end())); - }); + // debug + for ( int i = 0 ; i < nStartingLeaves ; ++i) + m_mTree.erase( vFirstCells[i]) ; + for ( int i = 0 ; i < nStartingLeaves ; ++i) + m_mTree.insert( vBranches[i].begin(), vBranches[i].end()) ; - // Step 2: Precompute total size and allocate final vector - size_t totalSize = accumulate(vectorBranches.begin(), vectorBranches.end(), 0, - [](size_t sum, const vector>& v) { - return sum + v.size(); - }) ; + return true ; + // debug - vector> mergedVector( totalSize) ; - // Step 3: Assign thread-specific ranges and move elements in parallel - vector offsets( nStartingLeaves + 1, 0) ; - for (size_t i = 0; i < nStartingLeaves; ++i) - offsets[i + 1] = offsets[i] + vectorBranches[i].size() ; + //vector>> vectorBranches( nStartingLeaves); - for_each( execution::par, vectorBranches.begin(), vectorBranches.end(), - [&]( auto& vec) { - size_t index = &vec - &vectorBranches[0]; - move( vec.begin(), vec.end(), mergedVector.begin() + offsets[index]) ; - }); + //// Step 1: Convert each map to a vector in parallel + //for_each(execution::par, vBranches.begin(), vBranches.end(), + // [&](auto& map) { + // size_t index = &map - &vBranches[0]; // Get the index of the current map + // vectorBranches[index].assign( make_move_iterator(map.begin()), + // make_move_iterator(map.end())); + // }); - // Step 4: Construct final unordered_map in one bulk step - //unordered_map finalMap( mergedVector.begin(), mergedVector.end()) ; - Cell cRoot = m_mTree.at( -1) ; - m_mTree.clear() ; - m_mTree.insert( pair(cRoot.m_nId, cRoot)) ; - m_mTree.insert( mergedVector.begin(), mergedVector.end()) ; + //// Step 2: Precompute total size and allocate final vector + //size_t totalSize = accumulate(vectorBranches.begin(), vectorBranches.end(), 0, + // [](size_t sum, const vector>& v) { + // return sum + v.size(); + // }) ; + + //vector> mergedVector( totalSize) ; + + //// Step 3: Assign thread-specific ranges and move elements in parallel + //vector offsets( nStartingLeaves + 1, 0) ; + //for (int i = 0; i < nStartingLeaves; ++i) + // offsets[i + 1] = offsets[i] + vectorBranches[i].size() ; + + //for_each( execution::par, vectorBranches.begin(), vectorBranches.end(), + // [&]( auto& vec) { + // size_t index = &vec - &vectorBranches[0]; + // move( vec.begin(), vec.end(), mergedVector.begin() + offsets[index]) ; + // }); + + //// Step 4: Construct final unordered_map in one bulk step + ////unordered_map finalMap( mergedVector.begin(), mergedVector.end()) ; + //Cell cRoot = m_mTree.at( -1) ; + //m_mTree.clear() ; + //unordered_map mContainer( mergedVector.begin(), mergedVector.end()) ; + //m_mTree = std::move( mContainer) ; + //m_mTree.insert( pair( cRoot.m_nId, cRoot)) ; + + //return true ; } //---------------------------------------------------------------------------- bool -Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBranchRoot, unordered_map& mBranch) +Tree::BuildBranch( int nFirstCell, unordered_map& mBranch, double dLinTol, double dSideMin, double dSideMax) { // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri - int nCToSplit = cBranchRoot->m_nId ; - int nBranchRoot = cBranchRoot->m_nId ; - Cell* pcToSplit = cBranchRoot ; + int nCToSplit = nFirstCell ; + Cell* pcToSplit = &mBranch.at(nFirstCell) ; + int nBranchRoot = pcToSplit->m_nParent ; bool bIsPlanar = m_pSrfBz->IsPlanar() ; if ( ! m_bBilinear) { while ( pcToSplit->IsProcessed() == false) { @@ -1017,7 +1064,7 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran // procedo con lo split del Child1 nCToSplit = pcToSplit->m_nChild1 ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } else { // sono arrivato ad una cella Leaf, quindi salvo la cella @@ -1025,37 +1072,37 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran pcToSplit->SetProcessed() ; // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = pcToSplit->m_nParent ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; if ( nCToSplit == nBranchRoot) return true ; - if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed()) + if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed()) pcToSplit->SetProcessed() ; - while ( m_mTree[pcToSplit->m_nChild2].IsProcessed()) { + while ( mBranch[pcToSplit->m_nChild2].IsProcessed()) { if ( pcToSplit->m_nParent != nBranchRoot) { nCToSplit = pcToSplit->m_nParent ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } else return true ; - if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed()) + if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed()) pcToSplit->SetProcessed() ; - if ( nCToSplit == -1 && m_mTree[pcToSplit->m_nChild2].IsProcessed()) + if ( nCToSplit == -1 && mBranch[pcToSplit->m_nChild2].IsProcessed()) break ; } nCToSplit = pcToSplit->m_nChild2 ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } } else { nCToSplit = pcToSplit->m_nChild1 ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } } Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà // probabilmente mi servirà salvare nella cella il livello di profondità } // bilineare else { - while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) { + while ( nCToSplit != nBranchRoot && pcToSplit->IsProcessed() == false) { if ( pcToSplit->IsLeaf()) { // vertici della cella Point3d ptP00, ptP10, ptP11, ptP01 ; @@ -1126,7 +1173,7 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran // procedo con lo split del Child1 nCToSplit = pcToSplit->m_nChild1 ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } else { // sono arrivato ad una cella Leaf, quindi salvo la cella @@ -1134,28 +1181,28 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran pcToSplit->SetProcessed() ; // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = pcToSplit->m_nParent ; - pcToSplit = &m_mTree[nCToSplit] ; - if ( nCToSplit == -2) + pcToSplit = &mBranch[nCToSplit] ; + if ( nCToSplit == nBranchRoot) return true ; - if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed()) + if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed()) pcToSplit->SetProcessed() ; - while ( m_mTree[pcToSplit->m_nChild2].IsProcessed()) { - if ( pcToSplit->m_nParent != -2) { + while ( mBranch[pcToSplit->m_nChild2].IsProcessed()) { + if ( pcToSplit->m_nParent != nBranchRoot) { nCToSplit = pcToSplit->m_nParent ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } - if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed()) + if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed()) pcToSplit->SetProcessed() ; - if ( nCToSplit == -1 && m_mTree[pcToSplit->m_nChild2].IsProcessed()) + if ( nCToSplit == -1 && mBranch[pcToSplit->m_nChild2].IsProcessed()) break ; } nCToSplit = pcToSplit->m_nChild2 ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } } else { nCToSplit = pcToSplit->m_nChild1 ; - pcToSplit = &m_mTree[nCToSplit] ; + pcToSplit = &mBranch[nCToSplit] ; } } } @@ -1173,6 +1220,8 @@ Tree::Balance() // al momento il problema viene bypassato in fase di generazione dei poligoni, considerando per ogni cella, oltre ai propri vertici // i vertici dei vicini che giacciono sui suoi lati + // in realtà non è vero: perchè non basta avere più triangoli nella singola cella, può servire proprio spezzare la cella e avere più celle che rappresentano + // facce diverse (quindi con pendenze diverse) } //---------------------------------------------------------------------------- diff --git a/Tree.h b/Tree.h index b5c7261..90f51a9 100644 --- a/Tree.h +++ b/Tree.h @@ -21,6 +21,9 @@ #include "/EgtDev/Include/EGkChainCurves.h" #include #include +#include +#include +#include struct PairHashInt64 { size_t operator()(const pair& key) const { @@ -249,16 +252,16 @@ class Tree Tree( const Point3d ptBl, const Point3d ptTr) ; // creatore da usare solo nel caso in cui si voglia aggiungere tagli ad un'unica cella e del risultato ottenere il contorno bool SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true, const Point3d& ptMin = ORIG, const Point3d& ptMax = ORIG) ; bool GetIndependentTrees( BIPNTVECTOR& vTrees) ; // calcolo la suddivisione della superficie solo sulle singole bbox dei loop di trim ( unendo quelli vicini) - void BranchManager( queue>& tasks, condition_variable& cv, bool& done) ; + void BranchManager( queue>& tasks, condition_variable& cv, bool& done) ; bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ; - bool BuildBranch( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO, Cell* cBranchRoot, unordered_map& mBranch) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh + bool BuildBranch( int nFirstCell, unordered_map& mBranch, double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh // dSideMin è lunghezza minima del lato di una cella nello spazio reale bool BuildTree_test( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ; bool GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vector& vCCEdges3D, ICRVCOMPOPOVECTOR& vCCLoops) ; bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, POLYLINEVECTOR& vPolygonsCorrected, POLYLINEVECTOR& vPolygons3d) ; // restituisce il poligono corrispondente ad ogni cella foglia dell'albero // ad ogni poligono sono stati aggiunti tutti i vertici dei vicini posizionati sui suoi lati // ad alcuni poligoni potrebbero venire tolti dei punti per evitare errori dovuti ad eventuali poli sui bordi del parametrico - bool GetLeaves ( std::vector& vLeaves) const ; // restituisce gli indici delle foglie nell'albero + bool GetLeaves ( vector& vLeaves) const ; // restituisce gli indici delle foglie nell'albero bool GetEdges3D ( vector& mCCEdge, POLYLINEVECTOR& vPolygons) ; // restituisce gli edge 3D come polyline bool GetSplitLoops( ICRVCOMPOPOVECTOR& vCCLoopSplit) const // funzione che restituisce i loop splitatti ai confini delle celle { for ( int i = 0 ; i < int( m_vCCLoop2D.size()); ++i) vCCLoopSplit.emplace_back( m_vCCLoop2D[i]->Clone()) ; return true ; };