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; }