#ifndef _mgTL2LPline_HH_
#define _mgTL2LPline_HH_

#include "Tl2/TL2Polyline.h"

/****************************************************************/
/*   Copyright (c) 2019 by System fugen G.K.                */
/*                       All rights reserved.                   */
/****************************************************************/

class MGPosition;

/** @addtogroup UseTessellation
 *  @{
 */

///mgTL2LPline is limitted subinterval of mgTL2Polyline.

///mgTL2LPline is a proprietry class for Face tessellation.
///mgTL2LPline is used to save copy of mgTL2Polyline.
///mgTL2LPline is limitted subinterval of mgTL2Polyline,
///holds the starting id of mgTL2Polyline, and the number of vertices.
class mgTL2LPline{

private:
	const mgTL2Polyline* m_polyline;//Original mgTL2Polyline pointer.
	int m_idS;//starting id. Not relative, but absolute value of m_polyline.
	int m_nV;	//Number of vertices.
				//When m_nv>0, this mgTL2LPline's direction is the same as m_polyline's.
				//When m_nv<0, this mgTL2LPline's direction is opposite to m_polyline's.
		
	///Let m_polyline' vertices are (V0, V1, ... , Vn-1),
	///then (Vm_idS, Vm_idS+1, ... , Vm_ids+m_nv-1) are mgTL2LPline's polyline.

///string stream function
friend std::ostream& operator<< (std::ostream& ot, const mgTL2LPline& poly){
	return poly.toString(ot);
};

public:

///Default constructor.
mgTL2LPline():m_polyline(0),m_idS(0),m_nV(0){;};

///Copy constructor.
mgTL2LPline(
	const mgTL2LPline& lpline
):m_polyline(lpline.m_polyline),m_idS(lpline.m_idS),m_nV(lpline.m_nV){;};

//Constructor of whole mgTL2Polyline.
mgTL2LPline(
	const mgTL2Polyline* polyline	//Original mgTL2Polyline pointer.
):m_polyline(polyline),m_idS(0),m_nV(polyline->bdim()){;};

mgTL2LPline(
	const mgTL2Polyline* polyline,	//Original mgTL2Polyline pointer.
	int idS, //starting id. Not relative, but absolute value of m_polyline.
	int nV
):m_polyline(polyline),m_idS(idS),m_nV(nV){;};

///Construct from subinterval of input lpline.
mgTL2LPline(
	const mgTL2LPline& lpline,
	int idS, //starting id of lpline
	int nV
);

//////////// Member Function ///////////////

//Change TL2Polyline's parameter t to this TL2LPline's point id.
//Midpoint value is changed to the nearest point id.
int changePolylineParameterToId(double t, bool fromIsBeforeMid)const;

//Change this TL2LPline's point id to TL2Polyline's parameter t.
double changeIdToPolylineParameter(int id)const;

//Test if id is the id of the end point.
bool isEndPoint(int id)const{ return id==number_of_points()-1;};

//Test if id is the id of mid points.
bool isMidPoint(int id)const{ return id>0 && id<number_of_points()-1;};

///Construct new curve object by copying to newed area.
///User must delete this copied object by "delete".
mgTL2LPline* clone()const;

//Evaluation of this with the normalized parameter value t from 0. to 1.
//is provided. t=0. for the start point, t=1. for the end point.
MGVector eval(double t, int nderi=0)const;

//Get id of m_Bpolylines of m_param of m_polyline from vertex id i.
//Function's return value is
//true if the point of t is a boundary point, false if not.
bool get_id_from_VertexID(int i, short id[3])const;

///Get concavity of this edge.
///The concavity is obtained from the differece of two vectors,
///at the start and at the end point point tangent of this.
//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 getConcavity()const;

///get the (u,v) parameter box.
MGBox getUvBox()const;

///Test if this is a null LPline.
bool is_null()const{return m_polyline==0;};
void setNull();

//Compute the intersections of sl and this mgTL2LPline.
//Function's return value is the (nearest) intersection vertex id of lp if >=0.
//If return value is minus, intersection not found.
int isectSlTl(
	const MGStraight& sl,
	bool fromIsBeforeMid//true is the from point is before midpoint.
)const;

//Update this by limiting the parameter range of the curve.
///Limitting is done at the knot parameter for both start and end.
void limit(
	int idS,	//start point id of this mgTL2LPline.
	int nV	//Number of vertices.
);

//Get the number of points of this closed polygon.
int number_of_points()const;

//Polygonize of the (u,v) space straight line from this->uv(id1V) to pline2.uv(id2V).
//The direction of the output is from id1V to id2V.
//polygonizeSL does ensure the deviation from the surface to be within the surface
//tolerance.
std::unique_ptr<mgTL2Polyline> polygonizeSL(
	const mgTL2LPline& pline2,
	int id1V,	//id of this vertex.
	int id2V	//id of pline2's vertex.
)const;

///Debug Function
std::ostream& toString(std::ostream& ostrm)const;

//Reverse the direction.
void reverse();

//Subdivide at the id.
void subdivide(
	int id,	//Relative one that start from 0 even for opposite direction.
	mgTL2LPline& lp1,	//devided 1st mgTL2LPline.
	mgTL2LPline& lp2	//devided 2nd mgTL2LPline.
)const;

//Obtain the mid point of this line.
void mid(MGPosition& uvmid);

const mgTL2Polyline* TL2Polyline()const{return m_polyline;};
const mgTL2parameter& TL2param()const{return m_polyline->TL2param();};

//Get i-th point surface parameter (u,v) of this polyline
MGPosition uv(int i)const;

//Get i-th point(x,y,z) of this polyline
MGPosition xyz(int i, bool need_normal=false)const;

};

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