unsigned FastMarchingForFacetExtraction::updateFlagsTable( ccGenericPointCloud* theCloud, GenericChunkedArray<1,unsigned char> &flags, unsigned facetIndex) { if (!m_initialized || !m_currentFacetPoints) return 0; unsigned pointCount = m_currentFacetPoints->size(); for (unsigned k=0; k<pointCount; ++k) { unsigned index = m_currentFacetPoints->getPointGlobalIndex(k); flags.setValue(index,1); theCloud->setPointScalarValue(index,static_cast<ScalarType>(facetIndex)); } if (m_currentFacetPoints) m_currentFacetPoints->clear(false); /*for (size_t i=0; i<m_activeCells.size(); ++i) { //we remove the processed cell so as to be sure not to consider them again! CCLib::FastMarching::Cell* cell = m_theGrid[m_activeCells[i]]; m_theGrid[m_activeCells[i]] = 0; if (cell) delete cell; } //*/ //unsigned pointCount = 0; CCLib::ReferenceCloud Yk(m_octree->associatedCloud()); for (size_t i=0; i<m_activeCells.size(); ++i) { PlanarCell* aCell = static_cast<PlanarCell*>(m_theGrid[m_activeCells[i]]); if (!m_octree->getPointsInCell(aCell->cellCode,m_gridLevel,&Yk,true)) continue; for (unsigned k=0; k<Yk.size(); ++k) { unsigned index = Yk.getPointGlobalIndex(k); assert(flags.getValue(index) == 1); //flags.setValue(index,1); //++pointCount; } m_theGrid[m_activeCells[i]] = 0; delete aCell; } return pointCount; }
ccPointCloud* ccGenericMesh::samplePoints( bool densityBased, double samplingParameter, bool withNormals, bool withRGB, bool withTexture, CCLib::GenericProgressCallback* pDlg/*=0*/) { bool withFeatures = (withNormals || withRGB || withTexture); GenericChunkedArray<1,unsigned>* triIndices = (withFeatures ? new GenericChunkedArray<1,unsigned> : 0); CCLib::SimpleCloud* sampledCloud = 0; if (densityBased) { sampledCloud = CCLib::MeshSamplingTools::samplePointsOnMesh(this,samplingParameter,pDlg,triIndices); } else { sampledCloud = CCLib::MeshSamplingTools::samplePointsOnMesh(this,static_cast<unsigned>(samplingParameter),pDlg,triIndices); } //convert to real point cloud ccPointCloud* cloud = 0; if (sampledCloud) { cloud = ccPointCloud::From(sampledCloud); delete sampledCloud; sampledCloud = 0; } if (!cloud) { if (triIndices) triIndices->release(); ccLog::Warning("[ccGenericMesh::samplePoints] Not enough memory!"); return 0; } if (withFeatures && triIndices && triIndices->currentSize() >= cloud->size()) { //generate normals if (withNormals && hasNormals()) { if (cloud->reserveTheNormsTable()) { for (unsigned i=0; i<cloud->size(); ++i) { unsigned triIndex = triIndices->getValue(i); const CCVector3* P = cloud->getPoint(i); CCVector3 N(0,0,1); interpolateNormals(triIndex,*P,N); cloud->addNorm(N); } cloud->showNormals(true); } else { ccLog::Warning("[ccGenericMesh::samplePoints] Failed to interpolate normals (not enough memory?)"); } } //generate colors if (withTexture && hasMaterials()) { if (cloud->reserveTheRGBTable()) { for (unsigned i=0; i<cloud->size(); ++i) { unsigned triIndex = triIndices->getValue(i); const CCVector3* P = cloud->getPoint(i); colorType C[3]={MAX_COLOR_COMP,MAX_COLOR_COMP,MAX_COLOR_COMP}; getColorFromMaterial(triIndex,*P,C,withRGB); cloud->addRGBColor(C); } cloud->showColors(true); } else { ccLog::Warning("[ccGenericMesh::samplePoints] Failed to export texture colors (not enough memory?)"); } } else if (withRGB && hasColors()) { if (cloud->reserveTheRGBTable()) { for (unsigned i=0; i<cloud->size(); ++i) { unsigned triIndex = triIndices->getValue(i); const CCVector3* P = cloud->getPoint(i); colorType C[3] = { MAX_COLOR_COMP, MAX_COLOR_COMP, MAX_COLOR_COMP }; interpolateColors(triIndex,*P,C); cloud->addRGBColor(C); } cloud->showColors(true); } else { ccLog::Warning("[ccGenericMesh::samplePoints] Failed to interpolate colors (not enough memory?)"); } } } //we rename the resulting cloud cloud->setName(getName()+QString(".sampled")); cloud->setDisplay(getDisplay()); cloud->prepareDisplayForRefresh(); //copy 'shift on load' information if (getAssociatedCloud()) { const CCVector3d& shift = getAssociatedCloud()->getGlobalShift(); cloud->setGlobalShift(shift); double scale = getAssociatedCloud()->getGlobalScale(); cloud->setGlobalScale(scale); } if (triIndices) triIndices->release(); return cloud; }
int ccFastMarchingForNormsDirection::OrientNormals( ccPointCloud* cloud, unsigned char octreeLevel, ccProgressDialog* progressCb) { if (!cloud || !cloud->normals()) { ccLog::Warning(QString("[orientNormalsWithFM] Cloud '%1' is invalid (or cloud has no normals)").arg(cloud->getName())); assert(false); } NormsIndexesTableType* theNorms = cloud->normals(); unsigned numberOfPoints = cloud->size(); if (numberOfPoints == 0) return -1; //we need the octree if (!cloud->getOctree()) { if (!cloud->computeOctree(progressCb)) { ccLog::Warning(QString("[orientNormalsWithFM] Could not compute octree on cloud '%1'").arg(cloud->getName())); return false; } } ccOctree::Shared octree = cloud->getOctree(); assert(octree); //temporary SF bool sfWasDisplayed = cloud->sfShown(); int oldSfIdx = cloud->getCurrentDisplayedScalarFieldIndex(); int sfIdx = cloud->getScalarFieldIndexByName("FM_Propagation"); if (sfIdx < 0) sfIdx = cloud->addScalarField("FM_Propagation"); if (sfIdx >= 0) { cloud->setCurrentScalarField(sfIdx); } else { ccLog::Warning("[orientNormalsWithFM] Couldn't create temporary scalar field! Not enough memory?"); return -3; } if (!cloud->enableScalarField()) { ccLog::Warning("[orientNormalsWithFM] Couldn't enable temporary scalar field! Not enough memory?"); cloud->deleteScalarField(sfIdx); cloud->setCurrentScalarField(oldSfIdx); return -4; } //flags indicating if each point has been processed or not GenericChunkedArray<1,unsigned char>* resolved = new GenericChunkedArray<1,unsigned char>(); if (!resolved->resize(numberOfPoints,true,0)) //defaultResolvedValue = 0 { ccLog::Warning("[orientNormalsWithFM] Not enough memory!"); cloud->deleteScalarField(sfIdx); cloud->setCurrentScalarField(oldSfIdx); resolved->release(); return -5; } //Fast Marching propagation ccFastMarchingForNormsDirection fm; int result = fm.init(cloud, theNorms, octree.data(), octreeLevel); if (result < 0) { ccLog::Error("[orientNormalsWithFM] Something went wrong during initialization..."); cloud->deleteScalarField(sfIdx); cloud->setCurrentScalarField(oldSfIdx); resolved->release(); return -6; } //progress notification if (progressCb) { if (progressCb->textCanBeEdited()) { progressCb->setMethodTitle("Norms direction"); progressCb->setInfo(qPrintable(QString("Octree level: %1\nPoints: %2").arg(octreeLevel).arg(numberOfPoints))); } progressCb->update(0); progressCb->start(); } const int octreeWidth = (1<<octreeLevel)-1; //enable 26-connectivity //fm.setExtendedConnectivity(true); //while non-processed points remain... unsigned resolvedPoints = 0; int lastProcessedPoint = -1; bool success = true; while (success) { //find the next non-processed point do { ++lastProcessedPoint; } while (lastProcessedPoint < static_cast<int>(numberOfPoints) && resolved->getValue(lastProcessedPoint) != 0); //all points have been processed? Then we can stop. if (lastProcessedPoint == static_cast<int>(numberOfPoints)) break; //we start the propagation from this point //its corresponding cell in fact ;) const CCVector3 *thePoint = cloud->getPoint(lastProcessedPoint); Tuple3i cellPos; octree->getTheCellPosWhichIncludesThePoint(thePoint, cellPos, octreeLevel); //clipping (in case the octree is not 'complete') cellPos.x = std::min(octreeWidth, cellPos.x); cellPos.y = std::min(octreeWidth, cellPos.y); cellPos.z = std::min(octreeWidth, cellPos.z); //set corresponding FM cell as 'seed' fm.setSeedCell(cellPos); //launch propagation int propagationResult = fm.propagate(); //if it's a success if (propagationResult >= 0) { //compute the number of points processed during this pass unsigned count = fm.updateResolvedTable(cloud,*resolved,theNorms); if (count != 0) { resolvedPoints += count; if (progressCb) progressCb->update(static_cast<float>(resolvedPoints)/static_cast<float>(numberOfPoints)*100.0f); } fm.cleanLastPropagation(); } else { ccLog::Error("An error occurred during front propagation! Process cancelled..."); success = false; } } if (progressCb) progressCb->stop(); resolved->release(); resolved = 0; cloud->showNormals(true); #ifdef QT_DEBUG cloud->setCurrentDisplayedScalarField(sfIdx); cloud->getCurrentDisplayedScalarField()->computeMinAndMax(); cloud->showSF(true); #else cloud->deleteScalarField(sfIdx); cloud->setCurrentScalarField(oldSfIdx); cloud->showSF(sfWasDisplayed); #endif return success; }
ccGBLSensor::ColorGrid* ccGBLSensor::projectColors( CCLib::GenericCloud* cloud, const ColorGrid& theColors) const { if (!cloud || !theColors.isAllocated()) return 0; unsigned gridSize = m_depthBuffer.height*m_depthBuffer.width; if (gridSize == 0) return 0; //depth buffer empty or not initialized! //number of points per cell of the depth map std::vector<size_t> pointPerDMCell; try { pointPerDMCell.resize(gridSize,0); } catch(std::bad_alloc) { //not enough memory return 0; } //temp. array for accumulation GenericChunkedArray<3,float>* colorAccumGrid = new GenericChunkedArray<3,float>; { float blackF[3] = {0,0,0}; if (!colorAccumGrid->resize(gridSize,true,blackF)) return 0; //not enough memory } //final array ColorsTableType* colorGrid = new ColorsTableType; { if (!colorGrid->resize(gridSize,true,ccColor::black.rgba)) { colorAccumGrid->release(); return 0; //not enough memory } } //project colors { unsigned pointCount = cloud->size(); cloud->placeIteratorAtBegining(); { for (unsigned i=0; i<pointCount; ++i) { const CCVector3 *P = cloud->getNextPoint(); CCVector2 Q; PointCoordinateType depth; projectPoint(*P,Q,depth,m_activeIndex); unsigned x,y; if (convertToDepthMapCoords(Q.x,Q.y,x,y)) { unsigned index = y*m_depthBuffer.width+x; //accumulate color const colorType* srcC = theColors.getValue(i); float* destC = colorAccumGrid->getValue(index); destC[0] += srcC[0]; destC[1] += srcC[1]; destC[2] += srcC[2]; ++pointPerDMCell[index]; } else { //shouldn't happen! assert(false); } } } } //normalize { for (unsigned i=0; i<gridSize; ++i) { if (pointPerDMCell[i] != 0) { const float* srcC = colorAccumGrid->getValue(i); colorType* destC = colorGrid->getValue(i); destC[0] = static_cast<colorType>( srcC[0] / pointPerDMCell[i] ); destC[1] = static_cast<colorType>( srcC[1] / pointPerDMCell[i] ); destC[2] = static_cast<colorType>( srcC[2] / pointPerDMCell[i] ); } } } colorAccumGrid->release(); return colorGrid; }
int ccFastMarchingForNormsDirection::ResolveNormsDirectionByFrontPropagation( ccPointCloud* theCloud, NormsIndexesTableType* theNorms, uchar octreeLevel, CCLib::GenericProgressCallback* progressCb, CCLib::DgmOctree* inputOctree) { assert(theCloud); unsigned numberOfPoints = theCloud->size(); if (numberOfPoints == 0) return -1; //we compute the octree if none is provided CCLib::DgmOctree* theOctree = inputOctree; if (!theOctree) { theOctree = new CCLib::DgmOctree(theCloud); if (theOctree->build(progressCb)<1) { delete theOctree; return -2; } } //temporary SF int oldSfIdx = theCloud->getCurrentDisplayedScalarFieldIndex(); int sfIdx = theCloud->getScalarFieldIndexByName("FM_Propagation"); if (sfIdx < 0) sfIdx = theCloud->addScalarField("FM_Propagation"); if (sfIdx >= 0) { theCloud->setCurrentScalarField(sfIdx); } else { ccLog::Warning("[ccFastMarchingForNormsDirection] Couldn't create temporary scalar field! Not enough memory?"); if (!inputOctree) delete theOctree; return -3; } if (!theCloud->enableScalarField()) { ccLog::Warning("[ccFastMarchingForNormsDirection] Couldn't enable temporary scalar field! Not enough memory?"); theCloud->deleteScalarField(sfIdx); theCloud->setCurrentScalarField(oldSfIdx); if (!inputOctree) delete theOctree; return -4; } //flags indicating if each point has been processed or not GenericChunkedArray<1,uchar>* resolved = new GenericChunkedArray<1,uchar>(); if (!resolved->resize(numberOfPoints,true,0)) //defaultResolvedValue = 0 { ccLog::Warning("[ccFastMarchingForNormsDirection] Not enough memory!"); theCloud->deleteScalarField(sfIdx); theCloud->setCurrentScalarField(oldSfIdx); if (!inputOctree) delete theOctree; resolved->release(); return -5; } //Fast Marching propagation ccFastMarchingForNormsDirection fm; int result = fm.init(theCloud,theNorms,theOctree,octreeLevel); if (result < 0) { ccLog::Error("[ccFastMarchingForNormsDirection] Something went wrong during initialization..."); theCloud->deleteScalarField(sfIdx); theCloud->setCurrentScalarField(oldSfIdx); resolved->release(); if (!inputOctree) delete theOctree; return -6; } //progress notification if (progressCb) { progressCb->reset(); progressCb->setMethodTitle("Norms direction"); progressCb->setInfo(qPrintable(QString("Octree level: %1\nPoints: %2").arg(octreeLevel).arg(numberOfPoints))); progressCb->start(); } const int octreeWidth = (1<<octreeLevel)-1; //enable 26-connectivity //fm.setExtendedConnectivity(true); //while non-processed points remain... unsigned resolvedPoints = 0; int lastProcessedPoint = -1; while (true) { //find the next non-processed point do { ++lastProcessedPoint; } while (lastProcessedPoint < static_cast<int>(numberOfPoints) && resolved->getValue(lastProcessedPoint) != 0); //all points have been processed? Then we can stop. if (lastProcessedPoint == static_cast<int>(numberOfPoints)) break; //we start the propagation from this point //its corresponding cell in fact ;) const CCVector3 *thePoint = theCloud->getPoint(lastProcessedPoint); int pos[3]; theOctree->getTheCellPosWhichIncludesThePoint(thePoint,pos,octreeLevel); //clipping (in case the octree is not 'complete') pos[0] = std::min(octreeWidth,pos[0]); pos[1] = std::min(octreeWidth,pos[1]); pos[2] = std::min(octreeWidth,pos[2]); //set corresponding FM cell as 'seed' fm.setSeedCell(pos); //launch propagation int propagationResult = fm.propagate(); //if it's a success if (propagationResult >= 0) { //compute the number of points processed during this pass unsigned count = fm.updateResolvedTable(theCloud,*resolved,theNorms); if (count != 0) { resolvedPoints += count; if (progressCb) progressCb->update(static_cast<float>(resolvedPoints)/static_cast<float>(numberOfPoints)*100.0f); } fm.cleanLastPropagation(); } else { ccLog::Error("An error occurred during front propagation! Process cancelled..."); break; } } if (progressCb) progressCb->stop(); resolved->release(); resolved = 0; if (!inputOctree) delete theOctree; theCloud->showNormals(true); #ifdef _DEBUG theCloud->setCurrentDisplayedScalarField(sfIdx); theCloud->getCurrentDisplayedScalarField()->computeMinAndMax(); theCloud->showSF(true); #else theCloud->deleteScalarField(sfIdx); theCloud->setCurrentScalarField(oldSfIdx); #endif return 0; }
bool ccGenericMesh::laplacianSmooth(unsigned nbIteration, float factor, CCLib::GenericProgressCallback* progressCb/*=0*/) { if (!m_associatedCloud) return false; //vertices unsigned vertCount = m_associatedCloud->size(); //triangles unsigned faceCount = size(); if (!vertCount || !faceCount) return false; GenericChunkedArray<3,PointCoordinateType>* verticesDisplacement = new GenericChunkedArray<3,PointCoordinateType>; if (!verticesDisplacement->resize(vertCount)) { //not enough memory verticesDisplacement->release(); return false; } //compute the number of edges to which belong each vertex unsigned* edgesCount = new unsigned[vertCount]; if (!edgesCount) { //not enough memory verticesDisplacement->release(); return false; } memset(edgesCount, 0, sizeof(unsigned)*vertCount); placeIteratorAtBegining(); for(unsigned j=0; j<faceCount; j++) { const CCLib::TriangleSummitsIndexes* tri = getNextTriangleIndexes(); edgesCount[tri->i1]+=2; edgesCount[tri->i2]+=2; edgesCount[tri->i3]+=2; } //progress dialog CCLib::NormalizedProgress* nProgress = 0; if (progressCb) { unsigned totalSteps = nbIteration; nProgress = new CCLib::NormalizedProgress(progressCb,totalSteps); progressCb->setMethodTitle("Laplacian smooth"); progressCb->setInfo(qPrintable(QString("Iterations: %1\nVertices: %2\nFaces: %3").arg(nbIteration).arg(vertCount).arg(faceCount))); progressCb->start(); } //repeat Laplacian smoothing iterations for(unsigned iter = 0; iter < nbIteration; iter++) { verticesDisplacement->fill(0); //for each triangle placeIteratorAtBegining(); for(unsigned j=0; j<faceCount; j++) { const CCLib::TriangleSummitsIndexes* tri = getNextTriangleIndexes(); const CCVector3* A = m_associatedCloud->getPoint(tri->i1); const CCVector3* B = m_associatedCloud->getPoint(tri->i2); const CCVector3* C = m_associatedCloud->getPoint(tri->i3); CCVector3 dAB = (*B-*A); CCVector3 dAC = (*C-*A); CCVector3 dBC = (*C-*B); CCVector3* dA = (CCVector3*)verticesDisplacement->getValue(tri->i1); (*dA) += dAB+dAC; CCVector3* dB = (CCVector3*)verticesDisplacement->getValue(tri->i2); (*dB) += dBC-dAB; CCVector3* dC = (CCVector3*)verticesDisplacement->getValue(tri->i3); (*dC) -= dAC+dBC; } if (nProgress && !nProgress->oneStep()) { //cancelled by user break; } //apply displacement verticesDisplacement->placeIteratorAtBegining(); for (unsigned i=0; i<vertCount; i++) { //this is a "persistent" pointer and we know what type of cloud is behind ;) CCVector3* P = const_cast<CCVector3*>(m_associatedCloud->getPointPersistentPtr(i)); const CCVector3* d = (const CCVector3*)verticesDisplacement->getValue(i); (*P) += (*d)*(factor/(PointCoordinateType)edgesCount[i]); } } m_associatedCloud->updateModificationTime(); if (hasNormals()) computeNormals(); if (verticesDisplacement) verticesDisplacement->release(); verticesDisplacement=0; if (edgesCount) delete[] edgesCount; edgesCount=0; if (nProgress) delete nProgress; nProgress=0; return true; }
ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPersist* theCloud, PointCoordinateType minDistance, DgmOctree* theOctree/*=0*/, GenericProgressCallback* progressCb/*=0*/) { assert(theCloud); unsigned cloudSize = theCloud->size(); DgmOctree *_theOctree=theOctree; if (!_theOctree) { _theOctree = new DgmOctree(theCloud); if (_theOctree->build()<(int)cloudSize) { delete _theOctree; return 0; } } ReferenceCloud* sampledCloud = new ReferenceCloud(theCloud); if (!sampledCloud->reserve(cloudSize)) { if (!theOctree) delete _theOctree; return 0; } GenericChunkedArray<1,bool>* markers = new GenericChunkedArray<1,bool>(); //DGM: upgraded from vector, as this can be quite huge! if (!markers->resize(cloudSize,true,true)) { markers->release(); if (!theOctree) delete _theOctree; delete sampledCloud; return 0; } NormalizedProgress* normProgress=0; if (progressCb) { progressCb->setInfo("Spatial resampling"); normProgress = new NormalizedProgress(progressCb,cloudSize); progressCb->reset(); progressCb->start(); } //for each point in the cloud that is still 'marked', we look //for its neighbors and remove their own marks DgmOctree::NearestNeighboursSphericalSearchStruct nss; nss.level = _theOctree->findBestLevelForAGivenNeighbourhoodSizeExtraction(minDistance); markers->placeIteratorAtBegining(); for (unsigned i=0; i<cloudSize; i++, markers->forwardIterator()) { //progress indicator if (normProgress && !normProgress->oneStep()) { //cancel process delete sampledCloud; sampledCloud = 0; break; } //no mark? we skip this point if (!markers->getCurrentValue()) continue; //init neighbor search structure theCloud->getPoint(i,nss.queryPoint); bool inbounds = false; _theOctree->getTheCellPosWhichIncludesThePoint(&nss.queryPoint, nss.cellPos, nss.level, inbounds); nss.truncatedCellCode = (inbounds ? _theOctree->generateTruncatedCellCode(nss.cellPos, nss.level) : DgmOctree::INVALID_CELL_CODE); _theOctree->computeCellCenter(nss.cellPos, nss.level, nss.cellCenter); //add the points that lie in the same cell (faster) { ReferenceCloud* Y = _theOctree->getPointsInCell(nss.truncatedCellCode, nss.level, true); unsigned count = Y->size(); try { nss.pointsInNeighbourhood.resize(count); } catch (std::bad_alloc) //out of memory { //stop process delete sampledCloud; sampledCloud = 0; break; } unsigned realCount = 0; DgmOctree::NeighboursSet::iterator it = nss.pointsInNeighbourhood.begin(); for (unsigned j=0; j<count; ++j) { unsigned index = Y->getPointGlobalIndex(j); if (index != i && markers->getValue(index)) //no need to add the point itself and those already flagged off { it->point = Y->getPointPersistentPtr(j); it->pointIndex = index; ++it; ++realCount; } } nss.pointsInNeighbourhood.resize(realCount); //should be ok as realCount<=count nss.alreadyVisitedNeighbourhoodSize = 1; } #ifdef TEST_CELLS_FOR_SPHERICAL_NN nss.pointsInSphericalNeighbourhood.clear(); #endif nss.prepare(minDistance,_theOctree->getCellSize(nss.level)); //look for neighbors and 'de-mark' them { unsigned nbNeighbors = _theOctree->findNeighborsInASphereStartingFromCell(nss, minDistance, false); DgmOctree::NeighboursSet::iterator it = nss.pointsInNeighbourhood.begin(); for (unsigned j=0; j<nbNeighbors; ++j, ++it) if (it->pointIndex != i) markers->setValue(it->pointIndex,false); } //At this stage, the ith point is the only one marked in a radius of <minDistance>. //Therefore it will necessarily be in the final cloud! if (!sampledCloud->addPointIndex(i)) //not enough memory { //stop process delete sampledCloud; sampledCloud = 0; break; } } if(normProgress) { delete normProgress; normProgress = 0; } if (!theOctree) delete _theOctree; markers->release(); return sampledCloud; }
int FastMarchingForFacetExtraction::ExtractPlanarFacets( ccPointCloud* theCloud, unsigned char octreeLevel, ScalarType maxError, CCLib::DistanceComputationTools::ERROR_MEASURES errorMeasure, bool useRetroProjectionError/*=true*/, CCLib::GenericProgressCallback* progressCb/*=0*/, CCLib::DgmOctree* _theOctree/*=0*/) { assert(theCloud); unsigned numberOfPoints = theCloud->size(); if (numberOfPoints == 0) return -1; if (!theCloud->getCurrentOutScalarField()) return -2; if (progressCb) { //just spawn the dialog so that we can see the //octree computation (in case the CPU charge prevents //the dialog from being shown) progressCb->start(); QApplication::processEvents(); } //we compute the octree if none is provided CCLib::DgmOctree* theOctree = _theOctree; if (!theOctree) { theOctree = new CCLib::DgmOctree(theCloud); if (theOctree->build(progressCb)<1) { delete theOctree; return -3; } } if (progressCb) { if (progressCb->textCanBeEdited()) { progressCb->setMethodTitle("Fast Marching for facets extraction"); progressCb->setInfo("Initializing..."); } progressCb->start(); QApplication::processEvents(); } if (!theCloud->enableScalarField()) { ccLog::Warning("[FastMarchingForFacetExtraction] Couldn't enable scalar field! Not enough memory?"); if (!_theOctree) delete theOctree; return -4; } //raz SF values { for (unsigned i=0; i!=theCloud->size(); ++i) theCloud->setPointScalarValue(i,0); } //flags indicating if each point has been processed or not GenericChunkedArray<1,unsigned char>* flags = new GenericChunkedArray<1,unsigned char>(); if (!flags->resize(numberOfPoints,true,0)) //defaultFlagValue = 0 { ccLog::Warning("[FastMarchingForFacetExtraction] Not enough memory!"); if (!_theOctree) delete theOctree; flags->release(); return -5; } //Fast Marching propagation FastMarchingForFacetExtraction fm; int result = fm.init( theCloud, theOctree, octreeLevel, maxError, errorMeasure, useRetroProjectionError, progressCb); if (result < 0) { ccLog::Error("[FastMarchingForFacetExtraction] Something went wrong during initialization..."); flags->release(); if (!_theOctree) delete theOctree; return -6; } //progress notification if (progressCb) { progressCb->update(0); if (progressCb->textCanBeEdited()) { progressCb->setMethodTitle("Facets extraction"); progressCb->setInfo(qPrintable(QString("Octree level: %1\nPoints: %2").arg(octreeLevel).arg(numberOfPoints))); } progressCb->start(); QApplication::processEvents(); } const int octreeWidth = (1<<octreeLevel)-1; //enable 26-connectivity mode //fm.setExtendedConnectivity(true); //while non-processed points remain... unsigned resolvedPoints = 0; int lastProcessedPoint = -1; unsigned facetIndex = 0; while (true) { //find the next non-processed point do { ++lastProcessedPoint; } while (lastProcessedPoint < static_cast<int>(numberOfPoints) && flags->getValue(lastProcessedPoint) != 0); //all points have been processed? Then we can stop. if (lastProcessedPoint == static_cast<int>(numberOfPoints)) break; //we start the propagation from this point //its corresponding cell in fact ;) const CCVector3 *thePoint = theCloud->getPoint(lastProcessedPoint); Tuple3i pos; theOctree->getTheCellPosWhichIncludesThePoint(thePoint, pos, octreeLevel); //clipping (in case the octree is not 'complete') pos.x = std::min(octreeWidth, pos.x); pos.y = std::min(octreeWidth, pos.y); pos.z = std::min(octreeWidth, pos.z); //set corresponding FM cell as 'seed' if (!fm.setSeedCell(pos)) { //an error occurred?! //result = -7; //break; continue; } //launch propagation int propagationResult = fm.propagate(); //compute the number of points processed during this pass unsigned count = fm.updateFlagsTable(theCloud,*flags,propagationResult >= 0 ? ++facetIndex : 0); //0 = invalid facet index if (count != 0) { resolvedPoints += count; if (progressCb) { if (progressCb->isCancelRequested()) { result = -7; break; } progressCb->update(static_cast<float>(resolvedPoints)/static_cast<float>(numberOfPoints)*100.0f); } } fm.cleanLastPropagation(); } if (progressCb) progressCb->stop(); flags->release(); flags = 0; if (!_theOctree) delete theOctree; return result; }