From 42a3af6ce220e505d0bd23470448f739c2d1eb6d Mon Sep 17 00:00:00 2001 From: Daniel Girardeau-Montaut Date: Wed, 10 Apr 2024 11:38:57 +0200 Subject: [PATCH] Syntax fix --- include/DgmOctree.h | 18 +-- src/DgmOctree.cpp | 293 +++++++++++++++++++++++--------------------- 2 files changed, 163 insertions(+), 148 deletions(-) diff --git a/include/DgmOctree.h b/include/DgmOctree.h index ba94d47..cfa3a8a 100644 --- a/include/DgmOctree.h +++ b/include/DgmOctree.h @@ -349,7 +349,7 @@ namespace CCCoreLib - (NormalizedProgress*) optional (normalized) progress callback - return success **/ - using octreeCellFunc = bool (*)(const octreeCell &, void **, NormalizedProgress *); + using octreeCellFunc = bool (*)(const octreeCell&, void**, NormalizedProgress*); /******************************/ /** METHODS **/ @@ -1114,7 +1114,7 @@ namespace CCCoreLib //! Computes statistics about cells for a given level of subdivision /** This method requires some computation, therefore it shouldn't be - called too often. + called too often. \param level the level of subdivision **/ void computeCellsStatistics(unsigned char level); @@ -1128,9 +1128,9 @@ namespace CCCoreLib \param level the level of subdivision **/ void getNeighborCellsAround(const Tuple3i& cellPos, - cellIndexesContainer &neighborCellsIndexes, - int neighbourhoodLength, - unsigned char level) const; + cellIndexesContainer &neighborCellsIndexes, + int neighbourhoodLength, + unsigned char level) const; //! Gets point in the neighbourhing cells of a specific cell /** \warning May throw a std::bad_alloc exception if memory is insufficient. @@ -1138,9 +1138,9 @@ namespace CCCoreLib \param neighbourhoodLength the new distance (in terms of cells) at which to look for neighbour cells \param getOnlyPointsWithValidScalar whether to ignore points having an invalid associated scalar value **/ - void getPointsInNeighbourCellsAround(NearestNeighboursSearchStruct &nNSS, - int neighbourhoodLength, - bool getOnlyPointsWithValidScalar = false) const; + void getPointsInNeighbourCellsAround( NearestNeighboursSearchStruct &nNSS, + int neighbourhoodLength, + bool getOnlyPointsWithValidScalar = false) const; //! Returns the index of a given cell represented by its code /** Same algorithm as the other "getCellIndex" method, but in an optimized form. @@ -1215,7 +1215,7 @@ namespace CCCoreLib //! Std. dev. of cell population per level of subdivision double m_stdDevCellPopulation[MAX_OCTREE_LEVEL + 1]; - //! Multithreading wrapper + //! Multi-threading wrapper structure MultiThreadingWrapper* m_MT_wrapper; //! Whether the octree build is in progress diff --git a/src/DgmOctree.cpp b/src/DgmOctree.cpp index e347284..8286b10 100644 --- a/src/DgmOctree.cpp +++ b/src/DgmOctree.cpp @@ -14,20 +14,21 @@ //system #include #include +#include //DGM: tests in progress //#define COMPUTE_NN_SEARCH_STATISTICS //#define ADAPTATIVE_BINARY_SEARCH //Qt -#include #include -#ifndef CC_DEBUG +//#ifndef CC_DEBUG //enables multi-threading handling (Release only) //requires TBB or QtConcurrent #if defined(CC_CORE_LIB_USES_QT_CONCURRENT) #define ENABLE_MT_OCTREE +#include #include #include #elif defined(CC_CORE_LIB_USES_TBB) @@ -35,7 +36,7 @@ #include #include #endif -#endif // #ifndef CC_DEBUG +//#endif // #ifndef CC_DEBUG namespace CCCoreLib { @@ -124,18 +125,35 @@ namespace CCCoreLib //! Structure containing objects needed to run octree operations in parallel struct MultiThreadingWrapper { + DgmOctree::octreeCellFunc cellFunc = nullptr; + bool cellFuncSuccess = true; DgmOctree* octree = nullptr; - DgmOctree::octreeCellFunc cell_func = nullptr; - void** userParams = nullptr; GenericProgressCallback* progressCb = nullptr; - NormalizedProgress* normProgressCb = nullptr; - bool cellFunc_success = true; + std::unique_ptr normProgressCb{ nullptr }; + void** userParams = nullptr; + + void reset() + { + cellFunc = nullptr; + cellFuncSuccess = true; + octree = nullptr; + normProgressCb.reset(); + progressCb = nullptr; + userParams = nullptr; + } void launchOctreeCellFunc(const octreeCellDesc& desc) { //skip cell if process is aborted/has failed - if (!cellFunc_success) + if (!cellFuncSuccess) + { + return; + } + + if (!octree) { + // structure is invalid + assert(false); return; } @@ -153,7 +171,7 @@ namespace CCCoreLib cell.points->addPointIndex(pointsAndCodes[i].theIndex); } - cellFunc_success &= (*cell_func)(cell, userParams, normProgressCb); + cellFuncSuccess &= (*cellFunc)(cell, userParams, normProgressCb.get()); if (normProgressCb) { @@ -162,28 +180,19 @@ namespace CCCoreLib } else { - cellFunc_success = false; + cellFuncSuccess = false; } - if (!cellFunc_success) + if (!cellFuncSuccess) { - //TODO: display a message to make clear that the cancel order has been acknowledged! if (progressCb) { if (progressCb->textCanBeEdited()) { + // display a message to make clear that the cancel order has been acknowledged! progressCb->setInfo("Cancelling..."); } } - - //if (normProgressCb) - //{ - // if (!normProgressCb->oneStep()) - // { - // cellFunc_success = false; - // return; - // } - //} } } }; @@ -2114,13 +2123,13 @@ int DgmOctree::findNeighborsInASphereStartingFromCell(NearestNeighboursSearchStr const PointCoordinateType& cs = getCellSize(nNSS.level); //we compute the minimal distance between the query point and all cell borders - const PointCoordinateType minDistToBorder = ComputeMinDistanceToCellBorder(nNSS.queryPoint,cs,nNSS.cellCenter); + const PointCoordinateType minDistToBorder = ComputeMinDistanceToCellBorder(nNSS.queryPoint, cs, nNSS.cellCenter); //we deduce the minimum cell neighbourhood size (integer) that includes the search sphere - const int minNeighbourhoodSize = 1+(radius>minDistToBorder ? static_cast(ceil((radius-minDistToBorder)/cs)) : 0); + const int minNeighbourhoodSize = 1 + (radius > minDistToBorder ? static_cast(ceil((radius - minDistToBorder) / cs)) : 0); //if we don't have visited such a neighbourhood... - if (nNSS.alreadyVisitedNeighbourhoodSize MAX_OCTREE_LEVEL) + { + // Invalid octree level return 0; + } #ifdef ENABLE_MT_OCTREE @@ -3052,16 +3070,16 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, { if (maxThreadCount == 0) { - // retrieve the maximum number of threads + //retrieve the maximum number of threads maxThreadCount = QThread::idealThreadCount(); } - if (maxThreadCount == 1) - { - // if only one thread should/cloud be used, the direct approach is more efficient - multiThread = false; - } + //if (maxThreadCount == 1) + //{ + // //if only one thread should/could be used, the non-concurrent approach is more efficient + // multiThread = false; + //} } -#endif +#endif // CC_CORE_LIB_USES_QT_CONCURRENT //cells that will be processed by QtConcurrent::map or tbb::parallel_for const unsigned cellsNumber = getCellNumber(level); @@ -3082,15 +3100,16 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, } if (!multiThread) -#endif +#endif // ENABLE_MT_OCTREE { //we get the maximum cell population for this level unsigned maxCellPopulation = m_maxCellPopulation[level]; //cell descriptor (initialize it with first cell/point) octreeCell cell(this); - if (!cell.points->reserve(maxCellPopulation)) //not enough memory + if (!cell.points->reserve(maxCellPopulation)) { + //not enough memory return 0; } cell.level = level; @@ -3099,18 +3118,10 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, //binary shift for cell code truncation unsigned char bitShift = GET_BIT_SHIFT(level); - //iterator on cell codes - cellsContainer::const_iterator p = m_thePointsAndTheirCellCodes.begin(); - - //init with first cell - cell.truncatedCode = (p->theCode >> bitShift); - cell.points->addPointIndex(p->theIndex); //can't fail (see above) - ++p; - //number of cells for this level unsigned cellCount = getCellNumber(level); - //progress bar + //progress report if (progressCb) { if (progressCb->textCanBeEdited()) @@ -3126,16 +3137,25 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, progressCb->update(0); progressCb->start(); } + NormalizedProgress nprogress(progressCb, m_theAssociatedCloud->size()); - bool result = true; - #ifdef COMPUTE_NN_SEARCH_STATISTICS s_skippedPoints = 0; s_testedPoints = 0; s_jumps = 0.0; s_binarySearchCount = 0.0; -#endif +#endif // COMPUTE_NN_SEARCH_STATISTICS + + bool result = true; + + //iterator on cell codes + cellsContainer::const_iterator p = m_thePointsAndTheirCellCodes.begin(); + + //init with first cell + cell.truncatedCode = (p->theCode >> bitShift); + cell.points->addPointIndex(p->theIndex); //can't fail (see above) + ++p; //for each point for (; p != m_thePointsAndTheirCellCodes.end(); ++p) @@ -3156,19 +3176,12 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, cell.index += cell.points->size(); cell.points->clear(); cell.truncatedCode = nextCode; - - //if (!nprogress.oneStep()) - //{ - // //process canceled by user - // result = false; - // break; - //} } cell.points->addPointIndex(p->theIndex); //can't fail (see above) } - //don't forget the last cell! + //don't forget the very last cell! if (result) { result = (*func)(cell, additionalParameters, &nprogress); @@ -3216,30 +3229,31 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, { CellCode nextCode = (p->theCode >> bitShift); + //check if it belongs to the current cell if (nextCode != cellDesc.truncatedCode) { + //if not, we can start a new cell cells.push_back(cellDesc); cellDesc.i1 = cellDesc.i2 + 1; + cellDesc.truncatedCode = nextCode; } - cellDesc.truncatedCode = nextCode; ++cellDesc.i2; } - //don't forget the last cell! + //don't forget the very last cell! cells.push_back(cellDesc); - //static wrap - assert(m_MT_wrapper); - m_MT_wrapper->octree = this; - m_MT_wrapper->cell_func = func; - m_MT_wrapper->userParams = additionalParameters; - m_MT_wrapper->cellFunc_success = true; - m_MT_wrapper->progressCb = progressCb; - if (m_MT_wrapper->normProgressCb) + //prepare the static wrapper + if (!m_MT_wrapper) { - delete m_MT_wrapper->normProgressCb; - m_MT_wrapper->normProgressCb = 0; + assert(false); + return 0; } + m_MT_wrapper->reset(); + m_MT_wrapper->cellFunc = func; + m_MT_wrapper->octree = this; + m_MT_wrapper->progressCb = progressCb; + m_MT_wrapper->userParams = additionalParameters; //progress notification if (progressCb) @@ -3251,18 +3265,21 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, progressCb->setMethodTitle(functionTitle); } char buffer[128]; - snprintf(buffer, 128, "Octree level %i\nCells: %i\nAverage population: %3.2f (+/-%3.2f)\nMax population: %u", - level, - static_cast(cells.size()), - m_averageCellPopulation[level], - m_stdDevCellPopulation[level], - m_maxCellPopulation[level] + snprintf( buffer, + 128, + "Octree level %i\nCells: %i\nAverage population: %3.2f (+/-%3.2f)\nMax population: %u", + level, + static_cast(cells.size()), + m_averageCellPopulation[level], + m_stdDevCellPopulation[level], + m_maxCellPopulation[level] ); progressCb->setInfo(buffer); } + progressCb->update(0); - m_MT_wrapper->normProgressCb = new NormalizedProgress(progressCb, m_theAssociatedCloud->size()); + m_MT_wrapper->normProgressCb.reset(new NormalizedProgress(progressCb, m_theAssociatedCloud->size())); progressCb->start(); #ifndef __APPLE__ QCoreApplication::processEvents(QEventLoop::EventLoopExec); // to allow the GUI to refresh itself @@ -3284,7 +3301,7 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, tbb::parallel_for(tbb::blocked_range(0, cells.size()), [&](tbb::blocked_range r) { - for (auto i = r.begin(); ilaunchOctreeCellFunc(cells[i]); } @@ -3305,27 +3322,19 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, } #endif - m_MT_wrapper->octree = nullptr; - m_MT_wrapper->cell_func = nullptr; - m_MT_wrapper->userParams = nullptr; - if (progressCb) { progressCb->stop(); - if (m_MT_wrapper->normProgressCb) - { - delete m_MT_wrapper->normProgressCb; - } - m_MT_wrapper->normProgressCb = nullptr; - m_MT_wrapper->progressCb = nullptr; } //if something went wrong, we clear everything and return 0! - if (!m_MT_wrapper->cellFunc_success) + if (!m_MT_wrapper->cellFuncSuccess) { cells.clear(); } + m_MT_wrapper->reset(); + return static_cast(cells.size()); } #endif @@ -3368,7 +3377,7 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star multiThread = false; } } -#endif +#endif // CC_CORE_LIB_USES_QT_CONCURRENT //cells that will be processed by QtConcurrent::map or tbb::parallel_for std::vector cells; @@ -3387,15 +3396,18 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star } if (!multiThread) -#endif +#endif // ENABLE_MT_OCTREE { //we get the maximum cell population for this level unsigned maxCellPopulation = m_maxCellPopulation[startingLevel]; //cell descriptor octreeCell cell(this); - if (!cell.points->reserve(maxCellPopulation)) //not enough memory + if (!cell.points->reserve(maxCellPopulation)) + { + //not enough memory return 0; + } cell.level = startingLevel; cell.index = 0; @@ -3409,12 +3421,14 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star progressCb->setMethodTitle(functionTitle); } char buffer[256]; - snprintf(buffer, 256, "Octree levels %i - %i\nCells: %i - %i\nAverage population: %3.2f (+/-%3.2f) - %3.2f (+/-%3.2f)\nMax population: %u - %u", - startingLevel, MAX_OCTREE_LEVEL, - getCellNumber(startingLevel), getCellNumber(MAX_OCTREE_LEVEL), - m_averageCellPopulation[startingLevel], m_stdDevCellPopulation[startingLevel], - m_averageCellPopulation[MAX_OCTREE_LEVEL], m_stdDevCellPopulation[MAX_OCTREE_LEVEL], - m_maxCellPopulation[startingLevel], m_maxCellPopulation[MAX_OCTREE_LEVEL]); + snprintf( buffer, + 256, + "Octree levels %i - %i\nCells: %i - %i\nAverage population: %3.2f (+/-%3.2f) - %3.2f (+/-%3.2f)\nMax population: %u - %u", + startingLevel, MAX_OCTREE_LEVEL, + getCellNumber(startingLevel), getCellNumber(MAX_OCTREE_LEVEL), + m_averageCellPopulation[startingLevel], m_stdDevCellPopulation[startingLevel], + m_averageCellPopulation[MAX_OCTREE_LEVEL], m_stdDevCellPopulation[MAX_OCTREE_LEVEL], + m_maxCellPopulation[startingLevel], m_maxCellPopulation[MAX_OCTREE_LEVEL]); progressCb->setInfo(buffer); } progressCb->update(0); @@ -3744,10 +3758,10 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star //we may have to go shallower ... as long as the parent cell is different assert(shallowSteps == 0); CellCode cellTruncatedCode = cellDesc.truncatedCode; - while (cellDesc.level > startingLevel+shallowSteps) + while (cellDesc.level > startingLevel + shallowSteps) { - cellTruncatedCode>>=3; - currentTruncatedCode>>=3; + cellTruncatedCode >>= 3; + currentTruncatedCode >>= 3; //this cell and the following share the same parent if (cellTruncatedCode == currentTruncatedCode) break; @@ -3756,7 +3770,7 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star //we must stop point collection here break; -#else +#else // NOT ENABLE_DOWN_TOP_TRAVERSAL_MT //we are at the end of the cell bool keepGoing = false; //can we continue collecting points? @@ -3782,7 +3796,7 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star //as this cell and the next one share the same parent, //the next cell won't be the first sub-cell! - firstSubCell=false; + firstSubCell = false; } else { @@ -3802,7 +3816,7 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star { break; } -#endif +#endif // NOT ENABLE_DOWN_TOP_TRAVERSAL_MT } } @@ -3829,24 +3843,20 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star currentBitShift += 3*shallowSteps; shallowSteps = 0; } -#endif +#endif // NOT ENABLE_DOWN_TOP_TRAVERSAL_MT } - //statistics - double mean = static_cast(popSum) / cells.size(); - double stddev = sqrt(static_cast(popSum2 - popSum*popSum)) / cells.size(); - - //static wrap - assert(m_MT_wrapper); - m_MT_wrapper->octree = this; - m_MT_wrapper->cell_func = func; - m_MT_wrapper->userParams = additionalParameters; - m_MT_wrapper->cellFunc_success = true; - if (m_MT_wrapper->normProgressCb) + //prepare the static wrapper + if (!m_MT_wrapper) { - delete m_MT_wrapper->normProgressCb; + assert(false); + return 0; } - m_MT_wrapper->normProgressCb = nullptr; + m_MT_wrapper->reset(); + m_MT_wrapper->cellFunc = func; + m_MT_wrapper->octree = this; + m_MT_wrapper->progressCb = progressCb; + m_MT_wrapper->userParams = additionalParameters; //progress notification if (progressCb) @@ -3857,16 +3867,25 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star { progressCb->setMethodTitle(functionTitle); } + + //statistics + double mean = static_cast(popSum) / cells.size(); + double stddev = sqrt(static_cast(popSum2 - popSum * popSum)) / cells.size(); + char buffer[256]; - snprintf(buffer, 256, "Octree levels %i - %i\nCells: %i\nAverage population: %3.2f (+/-%3.2f)\nMax population: %llu", startingLevel, MAX_OCTREE_LEVEL, static_cast(cells.size()), mean, stddev, maxPop); + snprintf( buffer, + 256, + "Octree levels %i - %i\nCells: %i\nAverage population: %3.2f (+/-%3.2f)\nMax population: %llu", + startingLevel, + MAX_OCTREE_LEVEL, + static_cast(cells.size()), + mean, + stddev, + maxPop); progressCb->setInfo(buffer); } - if (m_MT_wrapper->normProgressCb) - { - delete m_MT_wrapper->normProgressCb; - } - m_MT_wrapper->normProgressCb = new NormalizedProgress(progressCb, static_cast(cells.size())); progressCb->update(0); + m_MT_wrapper->normProgressCb.reset(new NormalizedProgress(progressCb, static_cast(cells.size()))); progressCb->start(); } @@ -3876,59 +3895,55 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star s_jumps = 0.0; s_binarySearchCount = 0.0; #endif + #ifdef CC_CORE_LIB_USES_QT_CONCURRENT // QtConcurrent takes precedence when both Qt and TBB are available QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount); QtConcurrent::blockingMap(cells, [this](const octreeCellDesc& desc) { m_MT_wrapper->launchOctreeCellFunc(desc); } ); #elif defined(CC_CORE_LIB_USES_TBB) + // Otherwise we use TBB if we can tbb::task_scheduler_init init(maxThreadCount != 0 ? maxThreadCount : tbb::task_scheduler_init::automatic); tbb::parallel_for(tbb::blocked_range(0, cells.size()), [&](tbb::blocked_range r) { - for (auto i = r.begin(); ilaunchOctreeCellFunc(cells[i]); } }); #endif + #ifdef COMPUTE_NN_SEARCH_STATISTICS - FILE* fp=fopen("octree_log.txt","at"); + FILE* fp = fopen("octree_log.txt", "at"); if (fp) { - fprintf(fp,"Function: %s\n",functionTitle ? functionTitle : "unknown"); - fprintf(fp,"Tested: %f (%3.1f %%)\n",s_testedPoints,100.0*s_testedPoints/std::max(1.0,s_testedPoints+s_skippedPoints)); - fprintf(fp,"skipped: %f (%3.1f %%)\n",s_skippedPoints,100.0*s_skippedPoints/std::max(1.0,s_testedPoints+s_skippedPoints)); - fprintf(fp,"Binary search count: %.0f\n",s_binarySearchCount); + fprintf(fp, "Function: %s\n", functionTitle ? functionTitle : "unknown"); + fprintf(fp, "Tested: %f (%3.1f %%)\n", s_testedPoints, 100.0*s_testedPoints / std::max(1.0, s_testedPoints + s_skippedPoints)); + fprintf(fp, "skipped: %f (%3.1f %%)\n", s_skippedPoints, 100.0*s_skippedPoints / std::max(1.0, s_testedPoints + s_skippedPoints)); + fprintf(fp, "Binary search count: %.0f\n", s_binarySearchCount); if (s_binarySearchCount > 0.0) - fprintf(fp,"Mean jumps: %f\n",s_jumps/s_binarySearchCount); - fprintf(fp,"\n"); + fprintf(fp, "Mean jumps: %f\n", s_jumps / s_binarySearchCount); + fprintf(fp, "\n"); fclose(fp); } #endif - m_MT_wrapper->octree = nullptr; - m_MT_wrapper->cell_func = nullptr; - m_MT_wrapper->userParams = nullptr; - if (progressCb) { progressCb->stop(); - if (m_MT_wrapper->normProgressCb) - { - delete m_MT_wrapper->normProgressCb; - } - m_MT_wrapper->normProgressCb = nullptr; } //if something went wrong, we clear everything and return 0! - if (!m_MT_wrapper->cellFunc_success) + if (!m_MT_wrapper->cellFuncSuccess) { cells.resize(0); } + m_MT_wrapper->reset(); + return static_cast(cells.size()); } -#endif +#endif // ENABLE_MT_OCTREE } bool DgmOctree::rayCast(const CCVector3& rayAxis,