/********************************************************************/
/* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
#include "MGCLStdAfx.h"
#include "mg/Vector.h"
#include "mg/Matrix.h"
#include "mg/Transf.h"
#include "mg/Geometry.h"
#include "mg/Point.h"
#include "topo/PVertex.h"
#include "topo/BVertex.h"
#include "topo/Edge.h"

#if defined(_DEBUG)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//
//Implements MGPVertex Class.
//MGPVertex is a parameter cell of the manifold dimension is 0,
//a boundary of an Edge(start or end).

/////// Constructor ///////

/////// operator overload///////

// Cellに平行移動を行ない自身のCellとする。
//Translation of the cell
MGPVertex& MGPVertex::operator+= (const MGVector& v){
	m_t+=v[0];
	return *this;
}

// Cellに逆方向の平行移動を行ない自身のCellとする。
//Translation of the cell
MGPVertex& MGPVertex::operator-= (const MGVector& v){
	m_t-=v[0];
	return *this;
}

//Cellのスケーリングを行い自身のCellとする。
//Scaling of the cell by a double.
MGPVertex& MGPVertex::operator*= (double s){
	m_t*=s;
	return *this;
}

// 与えられた変換でCellの変換を行い自身のCellとする。
//Transformation of the cell by a matrix.
MGPVertex& MGPVertex::operator*= (const MGMatrix& mat){
	m_t*=mat(0,0);
	return *this;
}

// 与えられた変換によってトランスフォームをおこない自身のCellにする。
//Transformation of the cell by a MGTransf.
MGPVertex& MGPVertex::operator*= (const MGTransf& tr){
	m_t*=tr.affine()(0,0)+tr.translation()(0);
	return *this;
}

//Assignment.
//does not change binder and partner relation.
//edge pointer will be cleared.
MGPVertex& MGPVertex::operator=(const MGPVertex& pv){
	if(this==&pv)
		return *this;

	MGCellBase::operator=(pv);
	m_t=pv.m_t;
	m_edge=0;
	return *this;
}
MGPVertex& MGPVertex::operator=(const MGGel& gel2){
	const MGPVertex* gel2_is_this=dynamic_cast<const MGPVertex*>(&gel2);
	if(gel2_is_this)
		operator=(*gel2_is_this);
	return *this;
}

//Comparison operator.
bool MGPVertex::operator< (const MGPVertex& cell2)const{
	const MGEdge* e1=edge();
	if(!e1)
		return true;
	const MGEdge* e2=cell2.edge();
	if(!e2)
		return false;
	MGBVertex* bv=binder_vertex();
	if(!bv)
		return true;
	const MGPVertex* pv0=bv->member_partner_vertex(0);
	const MGEdge* e0=pv0->edge();
	if(!e0)
		return true;

	MGVector v0=e0->eval(pv0->t(),1);
	if(!pv0->is_start_vertex())
		v0*=-1.;

	MGVector v1=e1->eval(t(),1);
	if(!is_start_vertex())
		v1*=-1.;
	MGVector v2=e2->eval(cell2.t(),1);
	if(!cell2.is_start_vertex())
		v2*=-1.;

	MGVector zAxis(0.,0.,-1.);
	return v0.angle2pai(v1,zAxis)<v0.angle2pai(v2,zAxis);
}
bool MGPVertex::operator<(const MGGel& gel2)const{
	const MGPVertex* gel2_is_this=dynamic_cast<const MGPVertex*>(&gel2);
	if(gel2_is_this)
		return operator<(*gel2_is_this);
	return false;
}

///////Member Function///////

//Get binder.
MGBVertex* MGPVertex::binder_vertex()const{
	return dynamic_cast<MGBVertex*>(binder());
}

//Make a clone of the cell.
MGPVertex* MGPVertex::clone() const{
	return new MGPVertex(*this);
}

//Test if this is the start vertex or end verstex on the edge.
bool MGPVertex::is_start_vertex()const{
	const MGEdge* e=edge();
	if(!e)
		return false;
	const MGPVertex* pv=edge()->vertex_start();
	return this==pv;
}

//Make a binder cell of this parameter cell.
//This is a parameter cell and the binder will be newed.
//Returned is the binder pointer generated.
//The binder has no geometry, only has binder and parameter cell relationship.
MGCellNB* MGPVertex::make_binder() const{
	MGCellNB* cell=binder();
	if(cell) return cell;
	MGBVertex* bv=new MGBVertex();
	set_binder(*bv);
	return bv;
}

//Make the binder cell's extent expression of this parameter cell.
//Returned is a MGGeometry pointer generated by new.
//When this cell does not have star cell, null pointer will be returned.
MGGeometry* MGPVertex::make_binder_extent() const{
	const MGCellNB* cell=star();
	if(!cell) return 0;
	const MGEdge* edge=dynamic_cast<const MGEdge*>(cell);
	return new MGPoint(edge->eval(t()));
}

// Output virtual function.
std::ostream& MGPVertex::out(std::ostream& ostrm) const{
	ostrm<<"<<PV="<<this;
	ostrm<<",m_t="<<m_t<<",m_edge="<<m_edge;
	MGCellBase::out(ostrm);
	ostrm<<"=PV>>";
	return ostrm;
}

//Obtain star cells.
const MGCellNB* MGPVertex::star() const{return m_edge;}
MGCellNB* MGPVertex::star(){return m_edge;}
