GenericIndexedMesh* ManualSegmentationTools::segmentMesh(GenericIndexedMesh* theMesh, ReferenceCloud* pointIndexes, bool pointsWillBeInside, GenericProgressCallback* progressCb, GenericIndexedCloud* destCloud, unsigned indexShift) { if (!theMesh || !pointIndexes || !pointIndexes->getAssociatedCloud()) return 0; //by default we try a fast process (but with a higher memory consumption) unsigned numberOfPoints = pointIndexes->getAssociatedCloud()->size(); unsigned numberOfIndexes = pointIndexes->size(); //we determine for each point if it is used in the output mesh or not //(and we compute its new index by the way: 0 means that the point is not used, otherwise its index will be newPointIndexes-1) std::vector<unsigned> newPointIndexes; { try { newPointIndexes.resize(numberOfPoints,0); } catch (const std::bad_alloc&) { return 0; //not enough memory } for (unsigned i=0; i<numberOfIndexes; ++i) { assert(pointIndexes->getPointGlobalIndex(i) < numberOfPoints); newPointIndexes[pointIndexes->getPointGlobalIndex(i)] = i+1; } } //negative array for the case where input points are "outside" if (!pointsWillBeInside) { unsigned newIndex = 0; for (unsigned i=0;i<numberOfPoints;++i) newPointIndexes[i] = (newPointIndexes[i] == 0 ? ++newIndex : 0); } //create resulting mesh SimpleMesh* newMesh = 0; { unsigned numberOfTriangles = theMesh->size(); //progress notification NormalizedProgress* nprogress = 0; if (progressCb) { progressCb->reset(); progressCb->setMethodTitle("Extract mesh"); char buffer[256]; sprintf(buffer,"New vertex number: %u",numberOfIndexes); nprogress = new NormalizedProgress(progressCb,numberOfTriangles); progressCb->setInfo(buffer); progressCb->start(); } newMesh = new SimpleMesh(destCloud ? destCloud : pointIndexes->getAssociatedCloud()); unsigned count = 0; theMesh->placeIteratorAtBegining(); for (unsigned i=0; i<numberOfTriangles; ++i) { bool triangleIsOnTheRightSide = true; const VerticesIndexes* tsi = theMesh->getNextTriangleVertIndexes(); //DGM: getNextTriangleVertIndexes is faster for mesh groups! int newVertexIndexes[3]; //VERSION: WE KEEP THE TRIANGLE ONLY IF ITS 3 VERTICES ARE INSIDE for (uchar j=0;j <3; ++j) { const unsigned& currentVertexFlag = newPointIndexes[tsi->i[j]]; //if the vertex is rejected, we discard this triangle if (currentVertexFlag == 0) { triangleIsOnTheRightSide = false; break; } newVertexIndexes[j] = currentVertexFlag-1; } //if we keep the triangle if (triangleIsOnTheRightSide) { if (count == newMesh->size() && !newMesh->reserve(newMesh->size() + 1000)) //auto expand mesh size { //stop process delete newMesh; newMesh = 0; break; } ++count; newMesh->addTriangle( indexShift + newVertexIndexes[0], indexShift + newVertexIndexes[1], indexShift + newVertexIndexes[2] ); } if (nprogress && !nprogress->oneStep()) { //cancel process break; } } if (nprogress) { delete nprogress; nprogress = 0; } if (newMesh) { if (newMesh->size() == 0) { delete newMesh; newMesh = 0; } else if (count < newMesh->size()) { newMesh->resize(count); //should always be ok as count<maxNumberOfTriangles } } } return newMesh; }
GenericIndexedMesh* Neighbourhood::triangulateFromQuadric(unsigned nStepX, unsigned nStepY) { if (nStepX<2 || nStepY<2) return 0; //qaudric fit const PointCoordinateType* Q = getQuadric(); //Q: Z = a + b.X + c.Y + d.X^2 + e.X.Y + f.Y^2 if (!Q) return 0; const PointCoordinateType& a = Q[0]; const PointCoordinateType& b = Q[1]; const PointCoordinateType& c = Q[2]; const PointCoordinateType& d = Q[3]; const PointCoordinateType& e = Q[4]; const PointCoordinateType& f = Q[5]; const uchar X = m_quadricEquationDirections.x; const uchar Y = m_quadricEquationDirections.y; const uchar Z = m_quadricEquationDirections.z; //gravity center (should be ok if the quadric is ok) const CCVector3* G = getGravityCenter(); assert(G); //bounding box CCVector3 bbMin, bbMax; m_associatedCloud->getBoundingBox(bbMin,bbMax); CCVector3 bboxDiag = bbMax - bbMin; //Sample points on Quadric and triangulate them! PointCoordinateType spanX = bboxDiag.u[X]; PointCoordinateType spanY = bboxDiag.u[Y]; PointCoordinateType stepX = spanX/(nStepX-1); PointCoordinateType stepY = spanY/(nStepY-1); ChunkedPointCloud* vertices = new ChunkedPointCloud(); if (!vertices->reserve(nStepX*nStepY)) { delete vertices; return 0; } SimpleMesh* quadMesh = new SimpleMesh(vertices,true); if (!quadMesh->reserve((nStepX-1)*(nStepY-1)*2)) { delete quadMesh; return 0; } for (unsigned x=0; x<nStepX; ++x) { CCVector3 P; P.x = bbMin[X] + stepX * x - G->u[X]; for (unsigned y=0; y<nStepY; ++y) { P.y = bbMin[Y] + stepY * y - G->u[Y]; P.z = a+b*P.x+c*P.y+d*P.x*P.x+e*P.x*P.y+f*P.y*P.y; CCVector3 Pc; Pc.u[X] = P.x; Pc.u[Y] = P.y; Pc.u[Z] = P.z; Pc += *G; vertices->addPoint(Pc); if (x>0 && y>0) { unsigned iA = (x-1) * nStepY + y-1; unsigned iB = iA+1; unsigned iC = iA+nStepY; unsigned iD = iB+nStepY; quadMesh->addTriangle(iA,iC,iB); quadMesh->addTriangle(iB,iC,iD); } } } return quadMesh; }