bool Cloud2CloudDist::Compute(	const Cloth& cloth,
								const wl::PointCloud& pc,
								double class_threshold,
								std::vector<int>& groundIndexes,
								std::vector<int>& offGroundIndexes,
								unsigned N/*=3*/)
{
	CCLib::SimpleCloud particlePoints;
	if (!particlePoints.reserve(static_cast<unsigned>(cloth.getSize())))
	{
		//not enough memory
		return false;
	}
	for (int i = 0; i < cloth.getSize(); i++)
	{
		const Particle& particle = cloth.getParticleByIndex(i);
		particlePoints.addPoint(CCVector3(static_cast<PointCoordinateType>(particle.pos.x), 0, static_cast<PointCoordinateType>(particle.pos.z)));
	}

	CCLib::SimpleCloud pcPoints;
	if (	!pcPoints.reserve(static_cast<unsigned>(pc.size()))
		||	!pcPoints.enableScalarField())
	{
		//not enough memory
		return false;
	}
	for (size_t i = 0; i < pc.size(); i++)
	{
		const wl::Point& P = pc[i];
		pcPoints.addPoint(CCVector3(P.x, 0, P.z));
	}

	try
	{
		//we spatially 'synchronize' the cloud and particles octrees
		CCLib::DgmOctree *cloudOctree = 0, *particleOctree = 0;
		CCLib::DistanceComputationTools::SOReturnCode soCode =
			CCLib::DistanceComputationTools::synchronizeOctrees
			(
			&particlePoints,
			&pcPoints,
			particleOctree,
			cloudOctree,
			0,
			0
			);

		if (soCode != CCLib::DistanceComputationTools::SYNCHRONIZED && soCode != CCLib::DistanceComputationTools::DISJOINT)
		{
			//not enough memory (or invalid input)
			return false;
		}

		//additional parameters
		void* additionalParameters[] = {(void*)(&cloth),
										(void*)(particleOctree),
										(void*)(&N)
		};

		int octreeLevel = particleOctree->findBestLevelForAGivenPopulationPerCell(std::max<unsigned>(2, N));

		int result = cloudOctree->executeFunctionForAllCellsAtLevel(
			octreeLevel,
			ComputeMeanNeighborAltitude,
			additionalParameters,
			true,
			0,
			"Rasterization",
			QThread::idealThreadCount());

		delete cloudOctree;
		cloudOctree = 0;

		delete particleOctree;
		particleOctree = 0;

		if (result == 0)
		{
			//something went wrong
			return false;
		}

		//now classify the points
		for (unsigned i = 0; i < pcPoints.size(); ++i)
		{
			if (std::fabs(pcPoints.getPointScalarValue(i) - pc[i].y) < class_threshold)
			{
				groundIndexes.push_back(i);
			}
			else
			{
				offGroundIndexes.push_back(i);
			}
		}

	}
	catch (const std::bad_alloc&)
	{
		//not enough memory
		return false;
	}

	return true;
}
bool ccMinimumSpanningTreeForNormsDirection::Process(	ccPointCloud* cloud,
														CCLib::GenericProgressCallback* progressCb/*=0*/,
														CCLib::DgmOctree* _octree/*=0*/)
{
	assert(cloud);
	if (!cloud->hasNormals())
	{
		ccLog::Warning(QString("Cloud '%1' has no normals!").arg(cloud->getName()));
		return false;
	}

	//ask for parameter
	bool ok;
#ifdef MST_USE_KNN
	unsigned kNN = static_cast<unsigned>(QInputDialog::getInt(0,"Neighborhood size", "Neighbors", 6, 1, 1000, 1, &ok));
	if (!ok)
		return false;
#else
	PointCoordinateType radius = static_cast<PointCoordinateType>(QInputDialog::getDouble(0,"Neighborhood radius", "radius", cloud->getOwnBB().getDiagNorm() * 0.01, 0, 1.0e9, 6, &ok));
	if (!ok)
		return false;
#endif

	//build octree if necessary
	CCLib::DgmOctree* octree = _octree;
	if (!octree)
	{
		octree = new CCLib::DgmOctree(cloud);
		if (octree->build(progressCb) <= 0)
		{
			ccLog::Warning(QString("Failed to compute octree on cloud '%1'").arg(cloud->getName()));
			delete octree;
			return false;
		}
	}
		
#ifdef MST_USE_KNN
	uchar level = octree->findBestLevelForAGivenPopulationPerCell(kNN*2);
#else
	uchar level = octree->findBestLevelForAGivenNeighbourhoodSizeExtraction(radius);
#endif

	bool result = true;
	try
	{
		Graph graph;
		if (!graph.reserve(cloud->size()))
		{
			//not enough memory!
			result = false;
		}

		//parameters
		void* additionalParameters[3] = {	reinterpret_cast<void*>(&graph),
											reinterpret_cast<void*>(cloud),
#ifdef MST_USE_KNN
											reinterpret_cast<void*>(&kNN)
#else
											reinterpret_cast<void*>(&radius)
#endif
										};

		if (octree->executeFunctionForAllCellsAtLevel(	level,
														&ComputeMSTGraphAtLevel,
														additionalParameters,
														false, //not compatible with parallel strategies!
														progressCb,
														"Build Spanning Tree") == 0)
		{
			//something went wrong
			ccLog::Warning(QString("Failed to compute Spanning Tree on cloud '%1'").arg(cloud->getName()));
			result = false;
		}
		else
		{
			if (!ResolveNormalsWithMST(cloud,graph,progressCb))
			{
				//something went wrong
				ccLog::Warning(QString("Failed to compute Minimum Spanning Tree on cloud '%1'").arg(cloud->getName()));
				result = false;
			}
		}
	}
	catch(...)
	{
		ccLog::Error(QString("Process failed on cloud '%1'").arg(cloud->getName()));
		result = false;
	}

	if (octree && !_octree)
	{
		delete octree;
		octree = 0;
	}

	return result;
}