
/*------------------------------------------------------------------------------*/
/** 
 *  \file   GW_Parameterization.h
 *  \brief  Definition of class \c GW_Parameterization
 *  \author Gabriel Peyré
 *  \date   7-1-2003
 */ 
/*------------------------------------------------------------------------------*/

#ifndef _GW_PARAMETERIZATION_H_
#define _GW_PARAMETERIZATION_H_

#include "../gw_core/GW_Config.h"
#include "../gw_core/GW_ProgressBar.h"
#include "GW_GeodesicMesh.h"
#include "GW_VoronoiMesh.h"

namespace GW {

class GW_TrissectorInfo
{
public:
	GW_TrissectorInfo(GW_I32 interior = -1, GW_I32 exterior1 = -1, GW_I32 exterior2 = -1)
	{
		nInterior_ = interior;
		nExterior1_ = exterior1;
		nExterior2_ = exterior2;
	}

	virtual GW_TrissectorInfo& operator=(const GW_TrissectorInfo& v)
	{
		nInterior_ = v.nInterior_;
		nExterior1_ = v.nExterior1_;
		nExterior2_ = v.nExterior2_;
		Pos_ = v.Pos_;
		return *this;
	}
	GW_I32 GetInterior()
	{ 
		return nInterior_;
	}
	GW_I32 GetExterior(GW_U32 i)
	{ 
		GW_ASSERT(i<2);
		if( i==0 )
			return nExterior1_;
		if( i==1 )
			return nExterior2_;
		return -1;
	}
	void SetInterior(GW_U32 val)
	{ 
		nInterior_ = val;
	}
	void SetExterior(GW_U32 i, GW_U32 val)
	{ 
		GW_ASSERT(i<2);
		if( i==0 )
			nExterior1_ = val;
		if( i==1 )
			nExterior2_ = val;
	}
	GW_U32 GetId(GW_U32 i)
	{
		GW_ASSERT(i<3);
		if( i==0 )
			return nExterior1_;
		if( i==1 )
			return nExterior2_;
		if( i==2 )
			return nInterior_;
		return -1;
	}
	void SetId(GW_U32 i, GW_U32 val)
	{ 
		GW_ASSERT(i<3);
		if( i==0 )
			nExterior1_ = val;
		if( i==1 )
			nExterior2_ = val;
		if( i==2 )
			nInterior_ = val;
	}

	void SetPosition( GW_Vector2D& pos )
	{ Pos_ = pos; }
	GW_Vector2D& GetPosition()
	{ return Pos_; }

private:

	GW_I32 nInterior_;
	GW_I32 nExterior1_;
	GW_I32 nExterior2_;

	GW_Vector2D Pos_;
};


/*------------------------------------------------------------------------------*/
/** \name a map of GW_TrissectorInfo */
/*------------------------------------------------------------------------------*/
//@{
typedef std::map<GW_U32, GW_TrissectorInfo> T_TrissectorInfoMap;
typedef T_TrissectorInfoMap::iterator IT_TrissectorInfoMap;
typedef T_TrissectorInfoMap::reverse_iterator RIT_TrissectorInfoMap;
typedef T_TrissectorInfoMap::const_iterator CIT_TrissectorInfoMap;
typedef T_TrissectorInfoMap::const_reverse_iterator CRIT_TrissectorInfoMap;
//@}

/*------------------------------------------------------------------------------*/
/** \name a vector of GW_TrissectorInfo */
/*------------------------------------------------------------------------------*/
//@{
typedef std::vector<GW_TrissectorInfo> T_TrissectorInfoVector;
typedef T_TrissectorInfoVector::iterator IT_TrissectorInfoVector;
typedef T_TrissectorInfoVector::reverse_iterator RIT_TrissectorInfoVector;
typedef T_TrissectorInfoVector::const_iterator CIT_TrissectorInfoVector;
typedef T_TrissectorInfoVector::const_reverse_iterator CRIT_TrissectorInfoVector;
//@}



/*------------------------------------------------------------------------------*/
/** 
 *  \class  GW_Parameterization
 *  \brief  Build a parameterization of a mesh.
 *  \author Gabriel Peyré
 *  \date   7-1-2003
 *
 *  First segement the mesh using a Lloyd method.
 *	Then parameterize each region.
 */ 
/*------------------------------------------------------------------------------*/

class GW_Parameterization
{

public:

    /*------------------------------------------------------------------------------*/
    /** \name Constructor and destructor */
    /*------------------------------------------------------------------------------*/
    //@{
    GW_Parameterization();
    virtual ~GW_Parameterization();
    //@}

	//-------------------------------------------------------------------------
    /** \name Lloyd algorithm */
    //-------------------------------------------------------------------------
    //@{
	void PerformLloydAlgorithm( GW_GeodesicMesh& Mesh, T_GeodesicVertexList& VertList );
	GW_Bool PerformLloydIteration( GW_GeodesicMesh& Mesh, T_GeodesicVertexList& VertList );
	GW_GeodesicVertex& PerformCentering( GW_GeodesicVertex& Vert, GW_GeodesicMesh& Mesh );
	void PerformPseudoLloydIteration( GW_GeodesicMesh& Mesh, T_GeodesicVertexList& VertList );
    //@}

	//-------------------------------------------------------------------------
    /** \name Segementation. */
    //-------------------------------------------------------------------------
    //@{
	void SegmentRegion( GW_GeodesicMesh& Mesh, GW_GeodesicVertex& Vert, T_TrissectorInfoMap* pTrissectorInfoMap = NULL );
	void SegmentAllRegions( GW_GeodesicMesh& Mesh, T_GeodesicVertexList& VertList, T_TrissectorInfoMap* pTrissectorInfoMap = NULL );
    //@}

	//-------------------------------------------------------------------------
    /** \name Parameterization. */
    //-------------------------------------------------------------------------
    //@{
	enum T_ParameterizationType
	{
		kGeodesicConformal,
		kTutte,
		kGeodesicIsomap,
		kGeodesicLLE,
	};
	enum T_ResolutionType
	{
		kSpectral,
		kBoundaryFree,
		kBoundaryFixed
	};
	void ParameterizeMesh(	GW_GeodesicMesh& Mesh, GW_VoronoiMesh& VoronoiMesh, GW_GeodesicMesh& FlattenedMesh, 
							T_ParameterizationType ParamType = kGeodesicIsomap, T_ResolutionType ResolType = kSpectral,
							T_GeodesicVertexMap* pBoundaryVertPos = NULL );

	/* parameterization helpers **************************************************/
	static void BuildConformalMatrix( GW_Mesh& VoronoiMesh, GW_SparseMatrix& K, const GW_MatrixNxP* M = NULL);
	static void BuildTutteMatrix( GW_Mesh& VoronoiMesh, GW_SparseMatrix& K );
	static void ResolutionSpectral( GW_MatrixNxP& K, GW_MatrixNxP& L, GW_U32 EIG = 0 );
	static void ResolutionBoundaryFree( GW_Mesh& VoronoiMesh, GW_SparseMatrix& K, GW_MatrixNxP&  L, GW_MatrixNxP* M = NULL );
	static void ResolutionBoundaryFixed( GW_Mesh& Mesh, GW_SparseMatrix& K, GW_MatrixNxP&  L, 
			T_Vector2DMap* pInitialPos = NULL, T_TrissectorInfoMap* pTrissectorInfoMap = NULL, 
			T_TrissectorInfoVector* pCyclicPosition = NULL );

	void ParameterizeRegion( GW_GeodesicVertex& Seed, GW_GeodesicMesh& BaseDomain );
	void ParameterizeAllRegions( T_GeodesicVertexList& VertList );
    //@}

	static void ExtractSubMeshes( GW_GeodesicMesh& Mesh, T_GeodesicVertexList& VertList, 
								T_GeodesicMeshVector& MeshVector, T_U32Vector* pGlobal2LocalID = NULL );
	static void SplitMesh( GW_GeodesicMesh& Mesh );

	//-------------------------------------------------------------------------
	/** \name Pretty helper. */
	//-------------------------------------------------------------------------
	//@{
	static void ExplodeRegion( GW_GeodesicVertex& Vert, GW_Float intensity, GW_Float normal_contrib );
	static void ExplodeAllRegions( T_GeodesicVertexList& VertList, GW_Float intensity = 0.1, GW_Float normal_contrib=0.5 );
	//@}

	static void PerformFastMarching( GW_GeodesicMesh& Mesh, T_GeodesicVertexList& VertList );

private:


	/* Lloyd helpers *************************************************************************/
	GW_U32 nNbrMaxIterLloyd_;
	GW_U32 nNbrMaxIterLloydDescent_;
	static GW_GeodesicVertex* pCurVoronoiDiagram_;
	GW_Float ComputeCenteringEnergy( GW_GeodesicVertex& Vert, GW_GeodesicVertex& StartVert, GW_GeodesicMesh& Mesh );
	static GW_Bool FastMarchingCallbackFunction_Centering( GW_GeodesicVertex& CurVert, GW_Float rNewDist );

	/* pseudo Lloyd helpers ******************************************************************/
	static GW_Bool PerformPseudoLloydIteration_Insertion( GW_GeodesicVertex& CurVert, GW_Float rNewDist );
	static void PerformPseudoLloydIteration_NeswDead( GW_GeodesicVertex& Vert );

	/* segmentation helpers ******************************************************************/
	void CutFace( GW_Face& Face, GW_GeodesicVertex& BaseVert, GW_GeodesicMesh& Mesh, T_TrissectorInfoMap* pTrissectorInfoMap = NULL  );
	void CutEdge( GW_GeodesicVertex& Vert1, GW_GeodesicVertex& Vert2, 
				GW_GeodesicVertex* &pInter_1, GW_GeodesicVertex* &pInter_2, GW_GeodesicMesh& Mesh  );
	/** a table of synonym */
	T_U32Map VertexConnexion_;

	/* ExtractSubMesh helper ****************************************************************/
	static void ExtractSubMeshes_Callback( GW_Face& face );
	static T_U32Vector FaceVector;
	static T_U32Map FaceMap;
	static T_U32Vector VertexVector;
	static T_U32Map VertexMap;

	/* system resolution *********************************************************************/
	static void SolveSystem( GW_SparseMatrix& M, GW_VectorND& x, GW_VectorND& b );

	/** record information about a cut */
	class GW_EdgeCut
	{
	public:
		GW_EdgeCut()
		{
			pBaseVert_[0]	= NULL;
			pBaseVert_[1]	= NULL;
			pNewVert_[0]	= NULL;
			pNewVert_[1]	= NULL;
		}
		GW_EdgeCut( GW_GeodesicVertex& BaseVert1,	GW_GeodesicVertex& BaseVert2, 
						 GW_GeodesicVertex& NewVert1,	GW_GeodesicVertex& NewVert2 )
		{
			pBaseVert_[0]	= &BaseVert1;
			pBaseVert_[1]	= &BaseVert2;
			pNewVert_[0]	= &NewVert1;
			pNewVert_[1]	= &NewVert2;
		}
		GW_EdgeCut& operator = (const GW_EdgeCut& c)
		{
			pBaseVert_[0]	= c.pBaseVert_[0];
			pBaseVert_[1]	= c.pBaseVert_[1];
			pNewVert_[0]	= c.pNewVert_[0];
			pNewVert_[1]	= c.pNewVert_[1];
			return *this;
		}
		GW_GeodesicVertex* GetNewVertex( GW_GeodesicVertex& BaseVert )
		{
			if( &BaseVert == pBaseVert_[0] )
				return pNewVert_[0];
			if( &BaseVert == pBaseVert_[1] )
				return pNewVert_[1];
			return NULL;
		}
	private:

		GW_GeodesicVertex* pBaseVert_[2];
		GW_GeodesicVertex* pNewVert_[2];
	};

	typedef std::map<GW_U32, GW_EdgeCut> T_EdgeCutMap;

	/** record each edge split, with corresponding added vertices */
	T_EdgeCutMap CutEdgeMap_;

	/** record each parameterization */
	T_MeshVector MeshVector_;

};

} // End namespace GW

#ifdef GW_USE_INLINE
    #include "GW_Parameterization.inl"
#endif


#endif // _GW_PARAMETERIZATION_H_


///////////////////////////////////////////////////////////////////////////////
//  Copyright (c) Gabriel Peyré
///////////////////////////////////////////////////////////////////////////////
//                               END OF FILE                                 //
///////////////////////////////////////////////////////////////////////////////
