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;
}
Пример #2
0
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;
}