//##########################################################################
//#                                                                        #
//#                              CLOUDCOMPARE                              #
//#                                                                        #
//#  This program is free software; you can redistribute it and/or modify  #
//#  it under the terms of the GNU General Public License as published by  #
//#  the Free Software Foundation; version 2 or later of the License.      #
//#                                                                        #
//#  This program is distributed in the hope that it will be useful,       #
//#  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          #
//#  GNU General Public License for more details.                          #
//#                                                                        #
//#          COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI)             #
//#                                                                        #
//##########################################################################

#ifndef CC_FAST_MARCHING_DIRECTION_HEADER
#define CC_FAST_MARCHING_DIRECTION_HEADER

//CCCoreLib
#include <DgmOctree.h>
#include <FastMarching.h>

//qCC_db
#include "ccAdvancedTypes.h"

//system
#include <vector>

class ccGenericPointCloud;
class ccPointCloud;
class ccOctree;
class ccProgressDialog;

//! Fast Marching algorithm for normals direction resolution
/** Extends the FastMarching class.
**/
class ccFastMarchingForNormsDirection : public CCCoreLib::FastMarching
{

public:

	//! Static entry point (helper)
	static int OrientNormals(	ccPointCloud* theCloud,
								unsigned char octreeLevel,
								ccProgressDialog* progressCb = nullptr);
	//! Default constructor
	ccFastMarchingForNormsDirection();

	//! Initializes the grid with a point cloud (and ist corresponding octree)
	/** The points should be associated to an (active) scalar field.
		The Fast Marching grid will have the same dimensions as
		the input octree considered at a given level of subdivision.
		\param cloud the point cloud
		\param theNorms the normals array
		\param theOctree the associated octree
		\param gridLevel the level of subdivision
		\return a negative value if something went wrong
	**/
	int init(	ccGenericPointCloud* cloud,
				NormsIndexesTableType* theNorms,
				ccOctree* theOctree,
				unsigned char gridLevel);

	//! Updates a list of point flags, indicating the points already processed
	/** \return the number of resolved points
	**/
	unsigned updateResolvedTable(	ccGenericPointCloud* theCloud,
									std::vector<unsigned char>& resolved,
									NormsIndexesTableType* theNorms);

	//inherited methods (see FastMarchingAlgorithm)
	int propagate() override;

protected:

	//! A Fast Marching grid cell for normals direction resolution
	class DirectionCell : public CCCoreLib::FastMarching::Cell
	{
	public:
		//! Default constructor
		DirectionCell()
			: Cell()
			, N(0,0,0)
			, C(0,0,0)
			, cellCode(0)
			, signConfidence(1)
#ifdef QT_DEBUG
			, scalar(0)
#endif
		{}

		///! Destructor
		~DirectionCell() override = default;

		//! The local cell normal
		CCVector3 N;
		//! The local cell center
		CCVector3 C;
		//! the code of the equivalent cell in the octree
		CCCoreLib::DgmOctree::CellCode cellCode;
		//! Confidence value
		float signConfidence;
#ifdef QT_DEBUG
		//! Undefined scalar for debug purposes
		float scalar;
#endif
	};

	//inherited methods (see FastMarchingAlgorithm)
	float computeTCoefApprox(CCCoreLib::FastMarching::Cell* currentCell, CCCoreLib::FastMarching::Cell* neighbourCell) const override;
	int step() override;
	void initTrialCells() override;
	bool instantiateGrid(unsigned size) override { return instantiateGridTpl<DirectionCell*>(size); }

	//! Computes relative 'confidence' between two cells (orientations)
	/** \return confidence between 0 and 1
	**/
	float computePropagationConfidence(DirectionCell* originCell, DirectionCell* destCell) const;

	//! Resolves the direction of a given cell (once and for all)
	void resolveCellOrientation(unsigned index);
};

#endif
