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;
}
unsigned ccFastMarchingForNormsDirection::updateResolvedTable(	ccGenericPointCloud* cloud,
																GenericChunkedArray<1,unsigned char> &resolved,
																NormsIndexesTableType* theNorms)
{
	if (!m_initialized || !m_octree || m_gridLevel > CCLib::DgmOctree::MAX_OCTREE_LEVEL)
		return 0;

	CCLib::ReferenceCloud Yk(m_octree->associatedCloud());

	unsigned count = 0;
	for (size_t i=0; i<m_activeCells.size(); ++i)
	{
		DirectionCell* aCell = static_cast<DirectionCell*>(m_theGrid[m_activeCells[i]]);
		if (!m_octree->getPointsInCell(aCell->cellCode,m_gridLevel,&Yk,true))
		{
			//not enough memory
			return 0;
		}

		for (unsigned k=0; k<Yk.size(); ++k)
		{
			unsigned index = Yk.getPointGlobalIndex(k);
			resolved.setValue(index,1);

			const CompressedNormType& norm = theNorms->getValue(index);
			const CCVector3& N = ccNormalVectors::GetNormal(norm);

			//inverse point normal if necessary
			if (N.dot(aCell->N) < 0)
			{
				theNorms->setValue(index,ccNormalVectors::GetNormIndex(-N));
			}

#ifdef QT_DEBUG
			cloud->setPointScalarValue(index,aCell->T);
			//cloud->setPointScalarValue(index,aCell->signConfidence);
			//cloud->setPointScalarValue(index,aCell->scalar);
#endif
			
			++count;
		}
	}

	return count;
}
int ccFastMarchingForNormsDirection::updateResolvedTable(ccGenericPointCloud* theCloud,
                                                            GenericChunkedArray<1,uchar> &resolved,
                                                            NormsIndexesTableType* theNorms)
{
	if (!initialized)
		return -1;

	int count=0;
	for (unsigned i=0;i<activeCells.size();++i)
	{
		DirectionCell* aCell = (DirectionCell*)theGrid[activeCells[i]];
		CCLib::ReferenceCloud* Yk = theOctree->getPointsInCell(aCell->cellCode,gridLevel,true);
		if (!Yk)
			continue;

		Yk->placeIteratorAtBegining();
		
		for (unsigned k=0;k<Yk->size();++k)
		{
			unsigned index = Yk->getCurrentPointGlobalIndex();
			resolved.setValue(index,1); //resolvedValue=1

			const normsType& norm = theNorms->getValue(index);
			if (CCVector3::vdot(ccNormalVectors::GetNormal(norm),aCell->N)<0.0)
			{
				PointCoordinateType newN[3];
				const PointCoordinateType* N = ccNormalVectors::GetNormal(norm);
				newN[0]=-N[0];
				newN[1]=-N[1];
				newN[2]=-N[2];
				theNorms->setValue(index,ccNormalVectors::GetNormIndex(newN));
			}

			//norm = NormalVectors::getNormIndex(aCell->N);
			//theNorms->setValue(index,&norm);

			theCloud->setPointScalarValue(index,aCell->T);
			//theCloud->setPointScalarValue(index,aCell->v);
			Yk->forwardIterator();
			++count;
		}
	}

	return count;
}
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;
}
ReferenceCloud* CloudSamplingTools::resampleCloudSpatially(GenericIndexedCloudPersist* inputCloud,
															PointCoordinateType minDistance,
															const SFModulationParams& modParams,
															DgmOctree* inputOctree/*=0*/,
															GenericProgressCallback* progressCb/*=0*/)
{
	assert(inputCloud);
    unsigned cloudSize = inputCloud->size();

    DgmOctree* octree = inputOctree;
	if (!octree)
	{
		octree = new DgmOctree(inputCloud);
		if (octree->build() < static_cast<int>(cloudSize))
		{
			delete octree;
			return 0;
		}
	}
	assert(octree && octree->associatedCloud() == inputCloud);

	//output cloud
	ReferenceCloud* sampledCloud = new ReferenceCloud(inputCloud);
	const unsigned c_reserveStep = 65536;
	if (!sampledCloud->reserve(std::min(cloudSize,c_reserveStep)))
	{
		if (!inputOctree)
			delete octree;
		return 0;
	}

	GenericChunkedArray<1,char>* markers = new GenericChunkedArray<1,char>(); //DGM: upgraded from vector, as this can be quite huge!
	if (!markers->resize(cloudSize,true,1)) //true by default
	{
		markers->release();
		if (!inputOctree)
			delete octree;
		delete sampledCloud;
		return 0;
	}

	//best octree level (there may be several of them if we use parameter modulation)
	std::vector<unsigned char> bestOctreeLevel;
	bool modParamsEnabled = modParams.enabled;
	ScalarType sfMin = 0, sfMax = 0;
	try
	{
		if (modParams.enabled)
		{
			//compute min and max sf values
			ScalarFieldTools::computeScalarFieldExtremas(inputCloud,sfMin,sfMax);

			if (!ScalarField::ValidValue(sfMin))
			{
				//all SF values are NAN?!
				modParamsEnabled = false;
			}
			else
			{
				//compute min and max 'best' levels
				PointCoordinateType dist0 = static_cast<PointCoordinateType>(sfMin * modParams.a + modParams.b);
				PointCoordinateType dist1 = static_cast<PointCoordinateType>(sfMax * modParams.a + modParams.b);
				unsigned char level0 = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(dist0);
				unsigned char level1 = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(dist1);

				bestOctreeLevel.push_back(level0);
				if (level1 != level0)
				{
					//add intermediate levels if necessary
					size_t levelCount = (level1 < level0 ? level0-level1 : level1-level0) + 1;
					assert(levelCount != 0);
					
					for (size_t i=1; i<levelCount-1; ++i) //we already know level0 and level1!
					{
						ScalarType sfVal = sfMin + i*((sfMax-sfMin)/levelCount);
						PointCoordinateType dist = static_cast<PointCoordinateType>(sfVal * modParams.a + modParams.b);
						unsigned char level = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(dist);
						bestOctreeLevel.push_back(level);
					}
				}
				bestOctreeLevel.push_back(level1);
			}
		}
		else
		{
			unsigned char defaultLevel = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(minDistance);
			bestOctreeLevel.push_back(defaultLevel);
		}
	}
	catch (const std::bad_alloc&)
	{
		//not enough memory
		markers->release();
		if (!inputOctree)
		{
			delete octree;
		}
		delete sampledCloud;
		return 0;
	}

	//progress notification
	NormalizedProgress normProgress(progressCb, cloudSize);
	if (progressCb)
	{
		if (progressCb->textCanBeEdited())
		{
			progressCb->setMethodTitle("Spatial resampling");
			char buffer[256];
			sprintf(buffer, "Points: %u\nMin dist.: %f", cloudSize, minDistance);
			progressCb->setInfo(buffer);
		}
		progressCb->update(0);
		progressCb->start();
	}

	//for each point in the cloud that is still 'marked', we look
	//for its neighbors and remove their own marks
	markers->placeIteratorAtBegining();
	bool error = false;
	//default octree level
	assert(!bestOctreeLevel.empty());
	unsigned char octreeLevel = bestOctreeLevel.front();
	//default distance between points
	PointCoordinateType minDistBetweenPoints = minDistance;
	for (unsigned i=0; i<cloudSize; i++, markers->forwardIterator())
	{
		//no mark? we skip this point
		if (markers->getCurrentValue() != 0)
		{
			//init neighbor search structure
			const CCVector3* P = inputCloud->getPoint(i);

			//parameters modulation
			if (modParamsEnabled)
			{
				ScalarType sfVal = inputCloud->getPointScalarValue(i);
				if (ScalarField::ValidValue(sfVal))
				{
					//modulate minDistance
					minDistBetweenPoints = static_cast<PointCoordinateType>(sfVal * modParams.a + modParams.b);
					//get (approximate) best level
					size_t levelIndex = static_cast<size_t>(bestOctreeLevel.size() * (sfVal / (sfMax-sfMin)));
					if (levelIndex == bestOctreeLevel.size())
						--levelIndex;
					octreeLevel = bestOctreeLevel[levelIndex];
				}
				else
				{
					minDistBetweenPoints = minDistance;
					octreeLevel = bestOctreeLevel.front();
				}
			}

			//look for neighbors and 'de-mark' them
			{
				DgmOctree::NeighboursSet neighbours;
				octree->getPointsInSphericalNeighbourhood(*P,minDistBetweenPoints,neighbours,octreeLevel);
				for (DgmOctree::NeighboursSet::iterator it = neighbours.begin(); it != neighbours.end(); ++it)
					if (it->pointIndex != i)
						markers->setValue(it->pointIndex,0);
			}

			//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->size() == sampledCloud->capacity() && !sampledCloud->reserve(sampledCloud->capacity() + c_reserveStep))
			{
				//not enough memory
				error = true;
				break;
			}
			if (!sampledCloud->addPointIndex(i))
			{
				//not enough memory
				error = true;
				break;
			}
		}
			
		//progress indicator
		if (progressCb && !normProgress.oneStep())
		{
			//cancel process
			error = true;
			break;
		}
	}

	//remove unnecessarily allocated memory
	if (!error)
	{
		if (sampledCloud->capacity() > sampledCloud->size())
			sampledCloud->resize(sampledCloud->size());
	}
	else
	{
		delete sampledCloud;
		sampledCloud = 0;
	}

	if (progressCb)
	{
		progressCb->stop();
	}

	if (!inputOctree)
	{
		//locally computed octree
		delete octree;
		octree = 0;
	}

	markers->release();
	markers = 0;

	return sampledCloud;
}