#ifndef _mgTL2parameter_HH_
#define _mgTL2parameter_HH_

#include <vector>
#include "mg/MGCL.h"
#include "mg/drawParam.h"
#include "topo/Face.h"

/****************************************************************/
/*   Copyright (c) 2019 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. Used in compute_max_edge_len().
#define NEAR_PARAM 0.002///< Parameter of the tessellation to avoid the same point division.
		///Data within parameter_span*NEAR_PARAM is regarded same point. Used in find_where().
#define MAX_DEVIATION_FROM_MIDDLE .333///<find_where() parameter to avoid extraneous edge split.
		///Used when split parameter value(u or v) is computed.
		///Split at the edge vertex value when the parameter value is 
		///within span_length*MAX_DEVIATION_FROM_MIDDLE from the middle.

///Angle data in radian.
#define LOOSE_ZERO_ANGLE  0.20		///= 11.45 degree
#define LOOSE_ZERO_ANGLE2 0.08726	///= 5.0 degree

///Concavity data of mgTLPLines' m_concavity.
#define STRICT_CONCAVITY 0.0603		/// = 1-cos(20 degree). Concavity of 20 degree.
#define LOOSE_FLAT_OR_CONCAVE -0.032/// = cos(X degree)-1, X=14.55
#define SIN_ZERO_ANGLE -0.03489		/// = sin(-2degree), to test if 2D angle is
	///concave angle or not. Means less than 2 degree's concavity not allowed.
#define COS_LOOSE_ZERO_ANGLE_M1 -.0000061/// = cos(.2 degree)-1.
#define COS_LOOSE_ZERO_ANGLE2_M1 -.003805/// = cos(5 degree)-1.
#define COS_SHARPANGLE_M1 -1.76446	/// = cos(140 degree)-1.


///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);

///Default Constructor.
mgTL2parameter():m_face(0),m_surface(0),m_Bpolylines(0){;};

///Constructor that specifies each parameter.
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.
);

///Constructor of MGDrawParam.
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);

const std::vector<SHLL_COM_EDGES>* Bpoly()const{return m_Bpolylines;};
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.
);

///test if concav is loosely concave or not. sideNum is the number of the sides.
inline
bool isLooselyFlatOrConcave(double concav){return concav>=COS_LOOSE_ZERO_ANGLE2_M1;};

///test if angle is loosely concave or not.
inline
bool isConcave(double concav){return concav>=COS_LOOSE_ZERO_ANGLE_M1;};

///test if angle is sharp or not.
inline
bool isSharp(double concav){return concav<COS_SHARPANGLE_M1;};

///Get the parallelism of two vectors. 
///Let para is the function's output, then smaller para is, dir1 and dir2 are
///more parallel. when para=0., both are completely parallel.
double parallelismTl(const MGVector& dir1, const MGVector& dir2);

///Compute the concavity of a closed polygon mgTL2LPlines's vertex V, given
///the line's direction at V.

///dir1 is the vector ending at V, and dir2 is the vector starting from V.
///Concavity is:
///when concave, 1 minus cangle, and when convex cangle minus 1.
///cangle is cosine angle around Z-axis of (U,V) 2D coordinates plane
///(when 3D, around Normal vector N axis)
///from pre-line's vector to aft-line's vector at the vertx i.
///m_concavity's value is from -2 to 2. 2 is most concave, and
/// -2 means 180 degree convex(most convex), -1:90 degree convex, 0:flat
/// 1:90 degree concave, 2:180 degree concave.
double concavityTl2D(const MGVector& dir1, const MGVector& dir2);

/** @} */ // end of UseTessellation group
#endif
