#ifndef _mgTL2parameter_HH_
#define _mgTL2parameter_HH_

#include <vector>
#include "mg/MGCL.h"
#include "mg/drawParam.h"
#include "topo/Face.h"

/****************************************************************/
/*   Copyright (c) 2017 by System fugen G.K.                */
/*                       All rights reserved.                   */
/****************************************************************/

class MGObject;
class MGFace;
class MGFSurface;
class MGSurface;
class MGDrawParam;

/** @file */
/** @addtogroup UseTessellation
 *  @{
 */

#define EDGE_LENGTH_DENOM 8. //Default edge length parameter, which is the denominator of
			//the face object box length.

#define NEAR_PARAM 0.002
#define STRICT_ZERO_ANGLE 0.00025	///0.0143 degree
#define LOOSE_ZERO_ANGLE  0.20		///= 11.45 degree
#define LOOSE_ZERO_ANGLE2 0.01		///= 0.5 degree
#define CONCAVEANGLE1	-0.7		///= -40 degree
#define CONCAVEANGLE2	-2.441		///=-140 degree
#define SHARPANGLE	2.441			///=140 degree
#define RIGHT_ANGLE STRICT_ZERO_ANGLE	///Right angle when cosine value is used.
#define MAX_DEVIATION_FROM_MIDDLE 4.	///Used when split u or v value is computed.
			/// Split value of a edge vertex is employed when it is 
			/// within span_length/MAX_DEVIATION_FROM_MIDDLE from the middle.
#define DEVIDE_RATIO 8

///Holds necessary parameter data for face tessellation.

///mgTL2parameter is a proprietry class for Face tessellation.
///In the constructor of mgTL2parameter(const MGFace&, double, double),
///all the parameters are initialized.
class mgTL2parameter{

public:

friend std::ostream& operator<< (std::ostream& out, const mgTL2parameter& para);

/////////Constructor///////////////
mgTL2parameter():m_face(0),m_surface(0),m_Bpolylines(0){;};

mgTL2parameter(
	const MGFSurface& obj,	///<テセレーションするフェイス
							///<Must be MGFace or MGSurface.
	double crvTol,	///<Tessellation curve tolerance.
	double surfTol,///<Tessellation surface tolerance.
	const std::vector<SHLL_COM_EDGES>* polylines=0,
		///< Input polygonized polylines for the face boundaries.
		///< polylines[i][j] is a j-th edge's polyline for face.loop(i),
		///< must be MGLBRep of order 2.
		///< polylines[i][j]=0 indicates loop i's edge j can be face's bounday and
		///< has any common edges.
		///< **polylines[i][j] must be the same direction as the faces's parameter edge.
	double max_edge_len=-1.///<Minimum edge length of the rectangles.
);

mgTL2parameter(
	const MGFSurface& obj,	///<テセレーションするフェイス
							///<Must be MGFace or MGSurface.
	const MGDrawParam& param,///<parameter for the tessellation.
	const std::vector<SHLL_COM_EDGES>* polylines=0
		///< Input polygonized polylines for the face boundaries.
		///< polylines[i][j] is a j-th edge's polyline for face.loop(i),
		///< must be MGLBRep of order 2.
		///< polylines[i][j]=0 indicates loop i's edge j can be face's bounday and
		///< has any common edges.
		///< **polylines[i][j] must be the same direction as the faces's parameter edge.
);
mgTL2parameter(const mgTL2parameter& param2);

////////////Destructor///////////////
//~mgTL2parameter();

const std::vector<SHLL_COM_EDGES>* Bpoly()const{return m_Bpolylines;};
int edgPerimLen()const;
const MGFace& get_face()const{return *m_face;};
const MGSurface& get_surface()const{return *m_surface;};
double get_max_edge_len()const{return m_max_edge_len;};
double get_max_edge_len_sqr()const{return m_max_edge_len_sqr;};
double get_tess_crvError()const {return m_tess_crvError;};
double get_tess_srfError()const {return m_tess_srfError;};
double get_UError()const {return m_puerror;};
double get_VError()const {return m_pverror;};
double get_UVError()const{return m_uverror;};
bool target_is_face()const{ return m_face!=0;};

/////////Operator oveload/////////

///Assignment.
mgTL2parameter& operator=(const mgTL2parameter&);

private:

	const MGFace* m_face;	///<Original face to tessellate.
	const MGSurface* m_surface;///<Original surface to tessellate.
							///<If m_face!=0, m_surface=m_face->surface();
	double m_puerror, m_pverror;///<Parameter error used for intersection computation.
	double m_uverror;///is sqrt(m_puerror*m_puerror+m_pverror*m_pverror);
	double m_tess_crvError;	///<Tessellation curve tolerance.
	double m_tess_srfError;	///<Tessellation surface tolerance.
	double m_max_edge_len;	///<Maximum edge length of the tessallated rectangles.
	double m_max_edge_len_sqr;	///<Square of m_max_edge_len.
	const std::vector<SHLL_COM_EDGES>* m_Bpolylines;
		///< Input polygonized polylines for the face boundaries.
		///< polylines[i][j] is a j-th edge's polyline for face.loop(i),
		///< must be MGLBRep of order 2.
		///< polylines[i][j]=0 indicates loop i's edge j can be face's bounday and
		///< has any common edges.
		///< **polylines[i][j] must be the same direction as the faces's parameter edge.

void build_parameter(
	const MGFSurface& srf,
	double crvTol,
	double surfTol,
	double max_edge_len
);

};

///Compute maximum edge length for the tessellation from an object, twoManifold.
///twoManifold must be MGFSurface or MGShell.
double compute_max_edge_len(const MGObject& twoManifold);

//Get the knotvector to guarantee the maximum line segment length square
//is less than maxElen2.
void getXYZline_ensuring_max_edge_length(
	double maxElen2,	//square of maximum edge length.
	const MGLBRep& xyzpolyline,//Input original LBRep of (x,y,z) of order 2.
	MGLBRep& xyzpolylineOut//Output LBRep of order 2 whose knot vector is:
			///t(i)=i-1 for i=1,...,n and t(0)=0 and t(n+1)=n-1.
);

///Construct polyline MGLBRep whose maximum edge length is para.get_max_edge_len_sqr().
void getUVline_ensuring_max_edge_length(
	const mgTL2parameter& para,///<Input parameter.
	const MGCurve& uvline,///<Input original (u,v) line of the surface.
	MGLBRep& xyzpolylineOut///<Output LBRep of order 2 whose knot vector is:
			///<t(i)=i-1 for i=1,...,n and t(0)=0 and t(n+1)=n-1.
);
/** @} */ // end of UseTessellation group
#endif
