diff --git a/Tree.cpp b/Tree.cpp index 077221e..6080363 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -29,9 +29,18 @@ #include "/EgtDev/Include/EGkSfrCreate.h" #include #include +#include +#include +#include +#include +#include +#include +#include using namespace std ; +atomic CellCounter( 0) ; + //---------------------------------------------------------------------------- Tree::Tree( void) : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_vbPole( { false, false, false, false}), @@ -255,7 +264,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi for ( int i = 1 ; i < nSplit ; ++i) { m_mTree[nId].SetSplitDirVert( true) ; double dSplit = bSplitInHalf ? i * SBZ_TREG_COEFF / 2 : i * SBZ_TREG_COEFF ; - if ( Split( nId, dSplit)) { + if ( Split( nId, dSplit, m_mTree)) { //++ nId ; //++ nId ; nId = m_mTree[nId].m_nChild2 ; @@ -274,7 +283,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi for ( int j = nSplit ; j > 0 ; --j) { m_mTree[nId].SetSplitDirVert( false) ; double dSplit = bSplitInHalf ? j * SBZ_TREG_COEFF / 2 : j * SBZ_TREG_COEFF ; - if ( Split( nId, dSplit)) + if ( Split( nId, dSplit, m_mTree)) nId = m_mTree[nId].m_nChild2 ; } } @@ -295,7 +304,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_bClosedV = true ; } m_mTree[-1].SetSplitDirVert( false) ; - Split( -1) ; + Split( -1, m_mTree) ; } //////// @@ -316,9 +325,9 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_vbPole[3] = bPole1 ; if ( bPole0 && bPole1 && int( m_mTree.size() == 3)) { m_mTree[0].SetSplitDirVert( true) ; - Split( 0) ; + Split( 0, m_mTree) ; m_mTree[1].SetSplitDirVert( true) ; - Split( 1) ; + Split( 1, m_mTree) ; } } // nella condizione di questo if non controllo eventuali divisioni preliminari, perché ne tengo conto dopo @@ -332,7 +341,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_bClosedU = true ; } m_mTree[-1].SetSplitDirVert( true) ; - Split( -1) ; + Split( -1, m_mTree) ; } //////// @@ -352,9 +361,9 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_vbPole[2] = bPole0 ; if ( bPole0 && bPole1 && int( m_mTree.size()) == 3) { m_mTree[0].SetSplitDirVert( false) ; - Split( 0) ; + Split( 0, m_mTree) ; m_mTree[1].SetSplitDirVert( false) ; - Split( 1) ; + Split( 1, m_mTree) ; } // se ho fatto solo 1 split orizzontale e ho due celle foglie nId = 0 e nId = 1 if ( int( m_mTree.size() == 3) && ! m_mTree.at(-1).IsSplitVert()) { @@ -363,9 +372,9 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_mTree[1].m_nLeft = -1 ; m_mTree[1].m_nRight = -1 ; m_mTree[0].SetSplitDirVert( true) ; - Split( 0) ; + Split( 0, m_mTree) ; m_mTree[1].SetSplitDirVert( true) ; - Split( 1) ; + Split( 1, m_mTree) ; } } } @@ -489,9 +498,9 @@ Tree::GetIndependentTrees( BIPNTVECTOR& vTrees) //---------------------------------------------------------------------------- bool -Tree::Split( int nId, double dSplitValue) +Tree::Split( int nId, double dSplitValue, unordered_map& mBranch) { - Cell& cToSplit = m_mTree.at(nId) ; + Cell& cToSplit = mBranch.at(nId) ; // controllo che lo split non venga fatto sul lato della cella if ( ( cToSplit.IsSplitVert() && dSplitValue > cToSplit.GetBottomLeft().x + EPS_SMALL && dSplitValue < cToSplit.GetTopRight().x - EPS_SMALL) || @@ -502,11 +511,10 @@ Tree::Split( int nId, double dSplitValue) Cell cChild1, cChild2 ; cChild1.m_nDepth = cToSplit.m_nDepth + 1 ; cChild2.m_nDepth = cToSplit.m_nDepth + 1 ; - int nNodes = (int) m_mTree.size() ; - cChild1.m_nId = nNodes - 1 ; - cToSplit.m_nChild1 = nNodes - 1 ; - cChild2.m_nId = nNodes ; - cToSplit.m_nChild2 = nNodes ; + cChild1.m_nId = CellCounter.fetch_add( 1) ; + cToSplit.m_nChild1 = cChild1.m_nId ; + cChild2.m_nId = CellCounter.fetch_add( 1) ; + cToSplit.m_nChild2 = cChild2.m_nId ; Point3d ptVert1, ptVert2 ; if ( ! cToSplit.IsSplitVert()) { // la cella figlio 1 è quella sopra @@ -553,8 +561,8 @@ Tree::Split( int nId, double dSplitValue) cChild1.SetParent( nId) ; cChild2.SetParent( nId) ; // inserisco nell'albero - m_mTree.insert( pair( nNodes - 1, cChild1)) ; - m_mTree.insert( pair( nNodes, cChild2)) ; + mBranch.insert( pair( cChild1.m_nId, cChild1)) ; + mBranch.insert( pair( cChild2.m_nId, cChild2)) ; return true ; } return false ; @@ -562,15 +570,15 @@ Tree::Split( int nId, double dSplitValue) //---------------------------------------------------------------------------- bool -Tree::Split( int nId) +Tree::Split( int nId, unordered_map& mBranch) { double dValue ; - Cell& cCell = m_mTree.at(nId) ; + Cell& cCell = mBranch.at(nId) ; if ( cCell.IsSplitVert()) dValue = ( cCell.GetBottomLeft().x + cCell.GetTopRight().x) / 2 ; else dValue = ( cCell.GetBottomLeft().y + cCell.GetTopRight().y) / 2 ; - return Split( nId, dValue) ; + return Split( nId, dValue, mBranch) ; } //---------------------------------------------------------------------------- @@ -583,25 +591,25 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax) //celle 0,1 m_mTree[-1].SetSplitDirVert( true) ; - Split( -1) ; + Split( -1, m_mTree) ; //celle 2,3 m_mTree[0].SetSplitDirVert( false) ; - Split( 0) ; + Split( 0, m_mTree) ; //celle 4,5 m_mTree[2].SetSplitDirVert( false) ; - Split( 2) ; + Split( 2, m_mTree) ; //celle 6,7 m_mTree[3].SetSplitDirVert( true) ; - Split( 3) ; + Split( 3, m_mTree) ; //celle 8,9 m_mTree[1].SetSplitDirVert( false) ; - Split( 1) ; + Split( 1, m_mTree) ; //celle 10,11 m_mTree[8].SetSplitDirVert( true) ; - Split( 8) ; + Split( 8, m_mTree) ; //celle 12,13 m_mTree[9].SetSplitDirVert( false) ; - Split( 9) ; + Split( 9, m_mTree) ; m_vnLeaves.push_back( 4) ; //m_vnLeaves.push_back( 5) ; m_vnLeaves.push_back( 6) ; @@ -614,22 +622,22 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax) // aggiunta di split //celle 14,15 m_mTree[5].SetSplitDirVert( true) ; - Split( 5) ; + Split( 5, m_mTree) ; m_vnLeaves.push_back( 14) ; m_vnLeaves.push_back( 15) ; //celle 16,17 m_mTree[7].SetSplitDirVert( false) ; - Split( 7) ; + Split( 7, m_mTree) ; m_vnLeaves.push_back( 16) ; m_vnLeaves.push_back( 17) ; //celle 18,19 m_mTree[12].SetSplitDirVert( true) ; - Split( 12) ; + Split( 12, m_mTree) ; m_vnLeaves.push_back( 18) ; m_vnLeaves.push_back( 19) ; //celle 20,21 m_mTree[10].SetSplitDirVert( false) ; - Split( 10) ; + Split( 10, m_mTree) ; m_vnLeaves.push_back( 20) ; m_vnLeaves.push_back( 21) ; // riempio anche la lista dei parent delle celle @@ -638,16 +646,115 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax) return true ; } +//---------------------------------------------------------------------------- +void +Tree::BranchManager( queue>& tasks, condition_variable& cv, bool& done) +{ + while (true) { + function task ; + { + std::unique_lock lock(mapMutex); + cv.wait(lock, [&tasks, &done]() { return !tasks.empty() || done; }); + + if (tasks.empty() && done) { + return; + } + task = move(tasks.front()); + tasks.pop(); + } + + task(); // Execute the task + } +} + //---------------------------------------------------------------------------- bool 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() ; + 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)) ; + } + + queue> tasks; + // Add tasks to the queue + { + std::lock_guard lock(queueMutex); + for (int i = 0; i < nStartingLeaves; ++i) { + tasks.emplace([this]() {}); + } + } + + // Notify threads that tasks are available + cv.notify_all(); + + // Mark work as done and notify all threads to exit + { + std::lock_guard lock(queueMutex); + done = true; + } + cv.notify_all(); + + // Wait for all threads to finish + for (auto& t : threads) { + t.join(); + } + + + vector>> vectorBranches( nStartingLeaves); + + // 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())); + }); + + // 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 (size_t 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() ; + m_mTree.insert( pair(cRoot.m_nId, cRoot)) ; + m_mTree.insert( mergedVector.begin(), mergedVector.end()) ; +} + +//---------------------------------------------------------------------------- +bool +Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBranchRoot, unordered_map& mBranch) { // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri - int nCToSplit = -1 ; - Cell* pcToSplit = &m_mTree[nCToSplit] ; + int nCToSplit = cBranchRoot->m_nId ; + int nBranchRoot = cBranchRoot->m_nId ; + Cell* pcToSplit = cBranchRoot ; bool bIsPlanar = m_pSrfBz->IsPlanar() ; if ( ! m_bBilinear) { - while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) { + while ( pcToSplit->IsProcessed() == false) { // controllo che la cella non sia già stata preliminarmente splittata if ( pcToSplit->IsLeaf()) { // calcolo in quale direzione ho più curvatura @@ -906,7 +1013,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) if ( bSplit || dSideMaxVal > dSideMax) { pcToSplit->SetSplitDirVert( bVert) ; // effettuo lo split - Split( nCToSplit) ; + Split( nCToSplit, mBranch) ; // procedo con lo split del Child1 nCToSplit = pcToSplit->m_nChild1 ; @@ -919,15 +1026,17 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = pcToSplit->m_nParent ; pcToSplit = &m_mTree[nCToSplit] ; - if ( nCToSplit == -2) + if ( nCToSplit == nBranchRoot) return true ; if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed()) pcToSplit->SetProcessed() ; while ( m_mTree[pcToSplit->m_nChild2].IsProcessed()) { - if ( pcToSplit->m_nParent != -2) { + if ( pcToSplit->m_nParent != nBranchRoot) { nCToSplit = pcToSplit->m_nParent ; pcToSplit = &m_mTree[nCToSplit] ; } + else + return true ; if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed()) pcToSplit->SetProcessed() ; if ( nCToSplit == -1 && m_mTree[pcToSplit->m_nChild2].IsProcessed()) @@ -1013,7 +1122,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { pcToSplit->SetSplitDirVert( bVert) ; // effettuo lo split - Split( nCToSplit) ; + Split( nCToSplit, mBranch) ; // procedo con lo split del Child1 nCToSplit = pcToSplit->m_nChild1 ; diff --git a/Tree.h b/Tree.h index 67d5c8d..b5c7261 100644 --- a/Tree.h +++ b/Tree.h @@ -249,7 +249,9 @@ 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) - bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh + 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 // 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) ; @@ -269,8 +271,8 @@ class Tree std::vector GetPoles( void) { return m_vbPole ;} ; // funzione che restituisce i flag che indicano se i lati sono collassati in dei poli private : - bool Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert - bool Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert + bool Split( int nId, double dSplitValue, unordered_map& mBranch) ;// funzione di split di una cella al parametro indicato nella direzione data da bVert + bool Split( int nId,unordered_map& mBranch) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert void Balance( void) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profondità di +- 1 int GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d = 0) const ; // altezza del subtree a partire dal nodo nId int GetDepth( int nId, int nRef) const ; // livello del nodo nId