예제 #1
0
//"PER-CELL" METHOD: FLAG DUPLICATE POINTS
//ADDITIONAL PARAMETERS (1):
// [0] -> (double*) maxSquareDistBetweenPoints: max square distance between points
bool GeometricalAnalysisTools::flagDuplicatePointsInACellAtLevel(	const DgmOctree::octreeCell& cell,
																	void** additionalParameters,
																	NormalizedProgress* nProgress/*=0*/)
{
	//parameter(s)
	double minDistBetweenPoints = *static_cast<double*>(additionalParameters[0]);

	//structure for nearest neighbors search
	DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
	nNSS.level = cell.level;
	nNSS.prepare(static_cast<PointCoordinateType>(minDistBetweenPoints),cell.parentOctree->getCellSize(nNSS.level));
	cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
	cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);

	unsigned n = cell.points->size(); //number of points in the current cell
	
	//for each point in the cell
	for (unsigned i=0; i<n; ++i)
	{
		//don't process points already flagged as 'duplicate'
		if (cell.points->getPointScalarValue(i) == 0)
		{
			cell.points->getPoint(i,nNSS.queryPoint);

			//look for neighbors in a sphere
			//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (neighborCount)!
			unsigned neighborCount = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,minDistBetweenPoints,false);
			if (neighborCount > 1) //the point itself lies in the neighborhood
			{
				unsigned iIndex = cell.points->getPointGlobalIndex(i);
				for (unsigned j=0; j<neighborCount; ++j)
				{
					if (nNSS.pointsInNeighbourhood[j].pointIndex != iIndex)
					{
						//flag this point as 'duplicate'
						cell.points->getAssociatedCloud()->setPointScalarValue(nNSS.pointsInNeighbourhood[j].pointIndex,static_cast<ScalarType>(1));
					}
				}
			}
		}

		if (nProgress && !nProgress->oneStep())
			return false;
	}

	return true;
}
예제 #2
0
//"PER-CELL" METHOD: LOCAL DENSITY
//ADDITIONNAL PARAMETERS (2):
// [0] -> (PointCoordinateType*) kernelRadius : spherical neighborhood radius
// [1] -> (ScalarType*) sphereVolume : spherical neighborhood volume
bool GeometricalAnalysisTools::computePointsDensityInACellAtLevel(	const DgmOctree::octreeCell& cell, 
																	void** additionalParameters,
																	NormalizedProgress* nProgress/*=0*/)
{
	//parameter(s)
	PointCoordinateType radius = *static_cast<PointCoordinateType*>(additionalParameters[0]);
	double dimensionalCoef = *static_cast<double*>(additionalParameters[1]);
	
	assert(dimensionalCoef > 0);

	//structure for nearest neighbors search
	DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
	nNSS.level = cell.level;
	nNSS.prepare(radius,cell.parentOctree->getCellSize(nNSS.level));
	cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
	cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);

	unsigned n = cell.points->size(); //number of points in the current cell
	
	//for each point in the cell
	for (unsigned i=0; i<n; ++i)
	{
		cell.points->getPoint(i,nNSS.queryPoint);

		//look for neighbors inside a sphere
		//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (neighborCount)!
		unsigned neighborCount = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,false);

		ScalarType density = static_cast<ScalarType>(neighborCount/dimensionalCoef);
		cell.points->setPointScalarValue(i,density);

		if (nProgress && !nProgress->oneStep())
			return false;
	}

	return true;
}
예제 #3
0
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;
}
예제 #4
0
bool CloudSamplingTools::applyNoiseFilterAtLevel(	const DgmOctree::octreeCell& cell,
													void** additionalParameters,
													NormalizedProgress* nProgress/*=0*/)
{
	ReferenceCloud* cloud				=  static_cast<ReferenceCloud*>(additionalParameters[0]);
	PointCoordinateType kernelRadius	= *static_cast<PointCoordinateType*>(additionalParameters[1]);
	double nSigma						= *static_cast<double*>(additionalParameters[2]);
	bool removeIsolatedPoints			= *static_cast<bool*>(additionalParameters[3]);
	bool useKnn							= *static_cast<bool*>(additionalParameters[4]);
	int knn								= *static_cast<int*>(additionalParameters[5]);
	bool useAbsoluteError				= *static_cast<bool*>(additionalParameters[6]);
	double absoluteError				= *static_cast<double*>(additionalParameters[7]);

	//structure for nearest neighbors search
	DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
	nNSS.level = cell.level;
	nNSS.prepare(kernelRadius,cell.parentOctree->getCellSize(nNSS.level));
	if (useKnn)
	{
		nNSS.minNumberOfNeighbors = knn;
	}
	cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
	cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);

	unsigned n = cell.points->size(); //number of points in the current cell

	//for each point in the cell
	for (unsigned i=0; i<n; ++i)
	{
		cell.points->getPoint(i,nNSS.queryPoint);

		//look for neighbors (either inside a sphere or the k nearest ones)
		//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (neighborCount)!
		unsigned neighborCount = 0;

		if (useKnn)
			neighborCount = cell.parentOctree->findNearestNeighborsStartingFromCell(nNSS);
		else
			neighborCount = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,kernelRadius,false);

		if (neighborCount > 3) //we want 3 points or more (other than the point itself!)
		{
			//find the query point in the nearest neighbors set and place it at the end
			const unsigned globalIndex = cell.points->getPointGlobalIndex(i);
			unsigned localIndex = 0;
			while (localIndex < neighborCount && nNSS.pointsInNeighbourhood[localIndex].pointIndex != globalIndex)
				++localIndex;
			//the query point should be in the nearest neighbors set!
			assert(localIndex < neighborCount);
			if (localIndex+1 < neighborCount) //no need to swap with another point if it's already at the end!
			{
				std::swap(nNSS.pointsInNeighbourhood[localIndex],nNSS.pointsInNeighbourhood[neighborCount-1]);
			}

			unsigned realNeighborCount = neighborCount-1;
			DgmOctreeReferenceCloud neighboursCloud(&nNSS.pointsInNeighbourhood,realNeighborCount); //we don't take the query point into account!
			Neighbourhood Z(&neighboursCloud);

			const PointCoordinateType* lsPlane = Z.getLSPlane();
			if (lsPlane)
			{
				double maxD = absoluteError;
				if (!useAbsoluteError)
				{
					//compute the std. dev. to this plane
					double sum_d = 0;
					double sum_d2 = 0;
					for (unsigned j=0; j<realNeighborCount; ++j)
					{
						const CCVector3* P = neighboursCloud.getPoint(j);
						double d = CCLib::DistanceComputationTools::computePoint2PlaneDistance(P,lsPlane);
						sum_d += d;
						sum_d2 += d*d;
					}

					double stddev = sqrt(fabs(sum_d2*realNeighborCount - sum_d*sum_d))/realNeighborCount;
					maxD = stddev * nSigma;
				}

				//distance from the query point to the plane
				double d = fabs(CCLib::DistanceComputationTools::computePoint2PlaneDistance(&nNSS.queryPoint,lsPlane));

				if (d <= maxD)
					cloud->addPointIndex(globalIndex);
			}
			else
			{
				//TODO: ???
			}
		}
		else
		{
			//not enough points to fit a plane AND compute distances to it
			if (!removeIsolatedPoints)
			{
				//we keep the point
				unsigned globalIndex = cell.points->getPointGlobalIndex(i);
				cloud->addPointIndex(globalIndex);
			}
		}

		if (nProgress && !nProgress->oneStep())
		{
			return false;
		}
	}

	return true;
}
예제 #5
0
//"PER-CELL" METHOD: CURVATURE ESTIMATION (WITH QUADRATIC FIT)
//ADDITIONAL PARAMETERS (2):
// [0] -> (CC_CURVATURE_TYPE*) cType : curvature type
// [1] -> (PointCoordinateType*) radius : sphere radius
bool GeometricalAnalysisTools::computeCellCurvatureAtLevel(	const DgmOctree::octreeCell& cell,
															void** additionalParameters,
															NormalizedProgress* nProgress/*=0*/)
{
	//parameters
	Neighbourhood::CC_CURVATURE_TYPE cType	= *static_cast<Neighbourhood::CC_CURVATURE_TYPE*>(additionalParameters[0]);
	PointCoordinateType radius				= *static_cast<PointCoordinateType*>(additionalParameters[1]);

	//structure for nearest neighbors search
	DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
	nNSS.level = cell.level;
	nNSS.prepare(radius,cell.parentOctree->getCellSize(nNSS.level));
	cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
	cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);

	unsigned n = cell.points->size(); //number of points in the current cell

	//we already know some of the neighbours: the points in the current cell!
	{
		try
		{
			nNSS.pointsInNeighbourhood.resize(n);
		}
		catch (.../*const std::bad_alloc&*/) //out of memory
		{
			return false;
		}

		DgmOctree::NeighboursSet::iterator it = nNSS.pointsInNeighbourhood.begin();
		for (unsigned i=0; i<n; ++i,++it)
		{
			it->point = cell.points->getPointPersistentPtr(i);
			it->pointIndex = cell.points->getPointGlobalIndex(i);
		}
	}
	nNSS.alreadyVisitedNeighbourhoodSize = 1;

	//for each point in the cell
	for (unsigned i=0; i<n; ++i)
	{
		ScalarType curv = NAN_VALUE;

		cell.points->getPoint(i,nNSS.queryPoint);

		//look for neighbors in a sphere
		//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (neighborCount)!
		unsigned neighborCount = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,false);
		//neighborCount = std::min(neighborCount,16);

		if (neighborCount > 5)
		{
			//current point index
			unsigned index = cell.points->getPointGlobalIndex(i);
			//current point index in neighbourhood (to compute curvature at the right position!)
			unsigned indexInNeighbourhood = 0;

			DgmOctreeReferenceCloud neighboursCloud(&nNSS.pointsInNeighbourhood,neighborCount);
			Neighbourhood Z(&neighboursCloud);

			//look for local index
			for (unsigned j=0;j<neighborCount;++j)
			{
				if (nNSS.pointsInNeighbourhood[j].pointIndex == index)
				{
					indexInNeighbourhood = j;
					break;
				}
			}

			curv = Z.computeCurvature(indexInNeighbourhood,cType);
		}

		cell.points->setPointScalarValue(i,curv);

		if (nProgress && !nProgress->oneStep())
			return false;
	}

	return true;
}
예제 #6
0
//"PER-CELL" METHOD: ROUGHNESS ESTIMATION (LEAST SQUARES PLANE FIT)
//ADDITIONNAL PARAMETERS (1):
// [0] -> (PointCoordinateType*) kernelRadius : neighbourhood radius
bool GeometricalAnalysisTools::computePointsRoughnessInACellAtLevel(const DgmOctree::octreeCell& cell, 
																	void** additionalParameters,
																	NormalizedProgress* nProgress/*=0*/)
{
	//parameter(s)
	PointCoordinateType radius = *static_cast<PointCoordinateType*>(additionalParameters[0]);

	//structure for nearest neighbors search
	DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
	nNSS.level = cell.level;
	nNSS.prepare(radius,cell.parentOctree->getCellSize(nNSS.level));
	cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
	cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);

	unsigned n = cell.points->size(); //number of points in the current cell
	
	//for each point in the cell
	for (unsigned i=0; i<n; ++i)
	{
		ScalarType d = NAN_VALUE;
		cell.points->getPoint(i,nNSS.queryPoint);

		//look for neighbors inside a sphere
		//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (= neighborCount)!
		unsigned neighborCount = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,false);
		if (neighborCount > 3)
		{
			//find the query point in the nearest neighbors set and place it at the end
			const unsigned globalIndex = cell.points->getPointGlobalIndex(i);
			unsigned localIndex = 0;
			while (localIndex < neighborCount && nNSS.pointsInNeighbourhood[localIndex].pointIndex != globalIndex)
				++localIndex;
			//the query point should be in the nearest neighbors set!
			assert(localIndex < neighborCount);
			if (localIndex+1 < neighborCount) //no need to swap with another point if it's already at the end!
			{
				std::swap(nNSS.pointsInNeighbourhood[localIndex],nNSS.pointsInNeighbourhood[neighborCount-1]);
			}

			DgmOctreeReferenceCloud neighboursCloud(&nNSS.pointsInNeighbourhood,neighborCount-1); //we don't take the query point into account!
			Neighbourhood Z(&neighboursCloud);

			const PointCoordinateType* lsPlane = Z.getLSPlane();
			if (lsPlane)
				d = fabs(DistanceComputationTools::computePoint2PlaneDistance(&nNSS.queryPoint,lsPlane));

			//swap the points back to their original position (DGM: not necessary)
			//if (localIndex+1 < neighborCount)
			//{
			//	std::swap(nNSS.pointsInNeighbourhood[localIndex],nNSS.pointsInNeighbourhood[neighborCount-1]);
			//}
		}

		cell.points->setPointScalarValue(i,d);

		if (nProgress && !nProgress->oneStep())
			return false;
	}

	return true;
}
예제 #7
0
//FONCTION "CELLULAIRE" DE CALCUL DU FILTRE GAUSSIEN (PAR PROJECTION SUR LE PLAN AUX MOINDRES CARRES)
//DETAIL DES PARAMETRES ADDITIONNELS (2) :
// [0] -> (PointCoordinateType*) sigma : gauss function sigma
// [1] -> (PointCoordinateType*) sigmaSF : used when in "bilateral modality" - if -1 pure gaussian filtering is performed
bool ScalarFieldTools::computeCellGaussianFilter(	const DgmOctree::octreeCell& cell,
													void** additionalParameters,
													NormalizedProgress* nProgress/*=0*/)
{
	//variables additionnelles
	PointCoordinateType sigma	= *((PointCoordinateType*)additionalParameters[0]);
    PointCoordinateType sigmaSF	= *((PointCoordinateType*)additionalParameters[1]);

    //we use only the squared value of sigma
	PointCoordinateType sigma2 = 2*sigma*sigma;
	PointCoordinateType radius = 3*sigma; //2.5 sigma > 99%

	//we use only the squared value of sigmaSF
    PointCoordinateType sigmaSF2 = 2*sigmaSF*sigmaSF;

	//number of points inside the current cell
	unsigned n = cell.points->size();

	//structures pour la recherche de voisinages SPECIFIQUES
	DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
	nNSS.level = cell.level;
	nNSS.prepare(radius,cell.parentOctree->getCellSize(nNSS.level));
	cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
	cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);

	//we already know the points lying in the first cell (this is the one we are treating :)
	try
	{
		nNSS.pointsInNeighbourhood.resize(n);
	}
	catch (.../*const std::bad_alloc&*/) //out of memory
	{
		return false;
	}
	
	DgmOctree::NeighboursSet::iterator it = nNSS.pointsInNeighbourhood.begin();
	{
		for (unsigned i=0; i<n; ++i,++it)
		{
			it->point = cell.points->getPointPersistentPtr(i);
			it->pointIndex = cell.points->getPointGlobalIndex(i);
		}
	}
	nNSS.alreadyVisitedNeighbourhoodSize = 1;

	const GenericIndexedCloudPersist* cloud = cell.points->getAssociatedCloud();

    //Pure Gaussian Filtering
    if (sigmaSF == -1)
    {
        for (unsigned i=0; i<n; ++i) //for each point in cell
        {
            //we get the points inside a spherical neighbourhood (radius: '3*sigma')
            cell.points->getPoint(i,nNSS.queryPoint);
			//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (k)!
            unsigned k = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,false);

            //each point adds a contribution weighted by its distance to the sphere center
            it = nNSS.pointsInNeighbourhood.begin();
            double meanValue = 0.0;
            double wSum = 0.0;
            for (unsigned j=0;j<k;++j,++it)
            {
                double weight = exp(-(it->squareDistd)/sigma2); //PDF: -exp(-(x-mu)^2/(2*sigma^2))
                ScalarType val = cloud->getPointScalarValue(it->pointIndex);
                //scalar value must be valid
				if (ScalarField::ValidValue(val))
                {
                    meanValue += static_cast<double>(val) * weight;
                    wSum += weight;
                }
            }

			ScalarType newValue = (wSum > 0.0 ? static_cast<ScalarType>(meanValue / wSum) : NAN_VALUE);

            cell.points->setPointScalarValue(i,newValue);

			if (nProgress && !nProgress->oneStep())
				return false;
        }
    }
    //Bilateral Filtering using the second sigma parameters on values (when given)
    else
    {
        for (unsigned i=0;i<n;++i) //for each point in cell
        {
            ScalarType queryValue = cell.points->getPointScalarValue(i); //scalar of the query point

            //we get the points inside a spherical neighbourhood (radius: '3*sigma')
            cell.points->getPoint(i,nNSS.queryPoint);
			//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (k)!
            unsigned k = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,false);

            //each point adds a contribution weighted by its distance to the sphere center
            it = nNSS.pointsInNeighbourhood.begin();
            double meanValue = 0.0;
            double wSum = 0.0;
            for (unsigned j=0;j<k;++j,++it)
            {
                ScalarType val = cloud->getPointScalarValue(it->pointIndex);
				ScalarType dSF = queryValue - val;
                double weight = exp(-(it->squareDistd)/sigma2) * exp(-(dSF*dSF)/sigmaSF2);
                //scalar value must be valid
				if (ScalarField::ValidValue(val))
                {
                    meanValue += (double)val * weight;
                    wSum += weight;
                }
            }

            cell.points->setPointScalarValue(i,wSum > 0.0 ? (ScalarType)(meanValue / wSum) : NAN_VALUE);

			if (nProgress && !nProgress->oneStep())
				return false;
        }
    }

	return true;
}
예제 #8
0
bool ScalarFieldTools::computeMeanGradientOnPatch(	const DgmOctree::octreeCell& cell,
													void** additionalParameters,
													NormalizedProgress* nProgress/*=0*/)
{
	//additional parameters
	bool euclideanDistances			= *reinterpret_cast<bool*>(additionalParameters[0]);
	PointCoordinateType radius		= *reinterpret_cast<PointCoordinateType*>(additionalParameters[1]);
	ScalarField* theGradientNorms	= reinterpret_cast<ScalarField*>(additionalParameters[2]);

	//number of points inside the current cell
	unsigned n = cell.points->size();

	//spherical neighborhood extraction structure
	DgmOctree::NearestNeighboursSphericalSearchStruct nNSS;
	nNSS.level = cell.level;
	nNSS.prepare(radius,cell.parentOctree->getCellSize(nNSS.level));
	cell.parentOctree->getCellPos(cell.truncatedCode,cell.level,nNSS.cellPos,true);
	cell.parentOctree->computeCellCenter(nNSS.cellPos,cell.level,nNSS.cellCenter);

	//we already know the points inside the current cell
	{
		try
		{
			nNSS.pointsInNeighbourhood.resize(n);
		}
		catch (.../*const std::bad_alloc&*/) //out of memory
		{
			return false;
		}
		DgmOctree::NeighboursSet::iterator it = nNSS.pointsInNeighbourhood.begin();
		for (unsigned j=0; j<n; ++j,++it)
		{
			it->point = cell.points->getPointPersistentPtr(j);
			it->pointIndex = cell.points->getPointGlobalIndex(j);
		}
		nNSS.alreadyVisitedNeighbourhoodSize = 1;
	}

	const GenericIndexedCloudPersist* cloud = cell.points->getAssociatedCloud();

	for (unsigned i=0; i<n; ++i)
	{
		ScalarType gN = NAN_VALUE;
		ScalarType d1 = cell.points->getPointScalarValue(i);

        if (ScalarField::ValidValue(d1))
		{
			 cell.points->getPoint(i,nNSS.queryPoint);

			//we extract the point's neighbors
			//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (k)!
			unsigned k = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,true);

            //if more than one neighbour (the query point itself)
			if (k > 1)
			{
				CCVector3d sum(0,0,0);
				unsigned counter = 0;

				//j = 1 because the first point is the query point itself --> contribution = 0
				for (unsigned j=1; j<k; ++j)
				{
					ScalarType d2 = cloud->getPointScalarValue(nNSS.pointsInNeighbourhood[j].pointIndex);
					if (ScalarField::ValidValue(d2))
					{
						CCVector3 u = *nNSS.pointsInNeighbourhood[j].point - nNSS.queryPoint;
						double norm2 = u.norm2d();

						if (norm2 > ZERO_TOLERANCE)
						{
                            double dd = d2 - d1;
							if (!euclideanDistances || dd*dd < 1.01 * norm2)
							{
								dd /= norm2;
								sum.x += u.x * dd; //warning: and here 'dd'=dd/norm2 ;)
								sum.y += u.y * dd;
								sum.z += u.z * dd;
								++counter;
							}
						}
					}
				}

				if (counter != 0)
					gN = static_cast<ScalarType>(sum.norm()/counter);
			}
		}

		if (theGradientNorms)
			//if "IN" and "OUT" SFs are the same
			theGradientNorms->setValue(cell.points->getPointGlobalIndex(i),gN);
		else
			//if "IN" and "OUT" SFs are different
			cell.points->setPointScalarValue(i,gN);

		if (nProgress && !nProgress->oneStep())
			return false;
	}

	return true;
}