/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "PmGeneralProjection.h"

//=================================================================
//
//  class PmGeneralProjection
//  ( a wrapper around Polar, Mercator and Cylindrical projections)
PmGeneralProjection :: PmGeneralProjection ( const MvRequest& reqst ):
	PmProjection ( reqst ),
	GPhemis    ( NORTH ),
	GPlat0     ( 0.    ),
	GPlon0     ( 0.    ),
	GPstlat1   ( 0.    ),
	GPstlat2   ( 0.    )
{
	// Empty
}

bool
PmGeneralProjection::CheckGeodeticCoordinates (Location& area)
{
    area = geodCoord_;
    return true;
}

// =============================================================
// class PmMercatorProjectionFactory - builds PmMercator projections
class PmMercatorProjectionFactory : public PmProjectionFactory 
{
	virtual PmProjection* Build( const MvRequest& reqst ) 
		{ return new PmMercator( reqst ); }

public:
	PmMercatorProjectionFactory() : PmProjectionFactory("MERCATOR") {}
};

// Instance which is loaded in the "factory"
static PmMercatorProjectionFactory mercatorProjectionFactoryInstance;

// ====================================================================
//
//  PmMercator projection
PmMercator::PmMercator ( const MvRequest& viewRequest ):
	PmGeneralProjection ( viewRequest )	//PmGeneralProjection ( "MERCATOR" )
{
	// Initialize vertical longitude
	GPlon0 = viewRequest ( "MAP_VERTICAL_LONGITUDE" ); 
//	GPlon0 *= DEG_TO_RAD;

	// Initialize standard parallel ( the other values are the default ones)
	GPstlat1 = (( geodCoord_.Top() + geodCoord_.Bottom() ) / 2. ) * DEG_TO_RAD;

	// Calculate the projection coordinates
	this->CalculateProjectionCoord();
}

// 		GEODETIC TO MERCATOR COORDINATES
Point
PmMercator :: LL2PC (Point& ptll)
{
	double	equad,			//Squared eccentricity
		aux1,			// Ancillary variables
		aux2,aux3,aux4,aux5,aux6,ptllx,ptlly;

	ptllx = ptll.X();		
	ptlly = ptll.Y();		

	equad = 2.*Pflt;		
	equad -= Pflt*Pflt;		
	double	a1,a2,a3;		

	a1 = tan(ptlly/(double)2);	
	a2 = 1.+a1;			
	a3 = 1.-a1;			
	aux1 = a2/a3;			

	a1 = equad*equad/4.;		
	a1 += equad;			
	a2 = equad*equad*equad/8.;	
	a3 = sin(ptlly);		
	aux2 = (a1+a2)*a3;		

	a1 = equad*equad/12.;		
	a2 = equad*equad*equad/16.;	
	a3 = sin((double)3*ptlly);	
	aux3 = (a1+a2)*a3;		

	a1 = equad*equad*equad/80.;	
	a2 = sin((double)5*ptlly);	
	aux4 = a1*a2;			
	aux5 = cos(GPstlat1);

	a1 = sin(GPstlat1);		
	a1 *= a1;			
	a1 *= equad;			
	a2 = sqrt((double)1-a1);	
	aux6 = 1./a2;			

	ptllx = Prd*(ptllx - GPlon0)*aux5*aux6;
	if (aux1 <= 0.0) ptlly = BIGFLOAT;
	else             ptlly = Prd*(log(aux1) - aux2 + aux3 - aux4)*aux5*aux6;

	return(Point(ptllx,ptlly));
}

//		MERCATOR TO GEODETIC COORDINATES
Point
PmMercator :: PC2LL (Point& ptpc)
{
	double	equad,			//Squared eccentricity 
	        pi,			// PII value
		t,			// Ancillary variables
		xx,aux1,aux2,aux3,aux4,aux5,ptpcx,ptpcy;

	ptpcx = ptpc.X();		
	ptpcy = ptpc.Y();		

	equad = 2.*Pflt;		
	equad -= Pflt*Pflt;		
	pi = 4.*atan((double)1);
	double	a1,a2;		
	aux1 = cos(GPstlat1);

	a1 = sin(GPstlat1);		
	a1 *= a1;			
	a1 *= equad;			
	a2 = sqrt((double)1-a1);	
	aux2 = 1./a2;			
	ptpcx = ptpcx/(aux1*aux2);
	ptpcy = ptpcy/(aux1*aux2);
	t = exp(-ptpcy/Prd);
	xx = pi/2. - 2.*atan(t);

	a1 = equad/2.;			
	a1 += 5.*equad*equad/24.;	
	a1 += equad*equad*equad/12.;	
	a2 = sin((double)4*atan(t));	
	aux3 = a1*a2;			

	a1 = 7.*equad*equad/48.;	
	a1 += 29.*equad*equad*equad/240.;	
	a2 = sin((double)8*atan(t));	
	aux4 = -a1*a2;			

	a1 = 7.*equad*equad*equad/120.;	
	a2 = sin((double)12*atan(t));	
	aux5 = a1*a2;			

	ptpcy = xx + aux3 + aux4 + aux5;
	ptpcx = ptpcx/Prd + GPlon0;

	return(Point(ptpcx,ptpcy));
}

double
PmMercator::CheckOriginLongitude ()
{
	double x0 = GPlon0 - 180.;
	if ( ( geodCoord_.Left() < x0 ) || ( geodCoord_.Right() > x0 + 360. ) )
		GPlon0 = geodCoord_.Left() +
			 ( ( geodCoord_.Right() - geodCoord_.Left() ) / 2. );

	return GPlon0;
}

bool
PmMercator::CheckGeodeticCoordinates (Location& area)
{
   bool flag = true;

   // Check if individual values are within the range
   // Magics now allows longitude coordinates to be greater than 360.
   double x1 = geodCoord_.Left();
   double x2 = geodCoord_.Right();
   double y2 = ( geodCoord_.Top()    >   89. ) ?   89 : geodCoord_.Top();
   double y1 = ( geodCoord_.Bottom() <  -89. ) ?  -89 : geodCoord_.Bottom();

   // Check if direction is ok (S -> N)
   if ( y2 <= y1 )
   {
      y1 = -90.;
      y2 = +90.;
   }

   // Special cases
   if ( x2 == x1 )
   {
      if ( x2 == 0. )         x2 =  360.;
      else if ( x1 == 180.  ) x1 = -180.;
      else if ( x2 == -180. ) x2 =  180.;
   }

   // Check if some values have been changed
   if ( ( geodCoord_.Left()   != x1 ) ||
        ( geodCoord_.Right()  != x2 ) ||
        ( geodCoord_.Bottom() != y1 ) ||
        ( geodCoord_.Top()    != y2 )   )
   {
      flag = false;
      geodCoord_ = Location ( y2, x1, y1, x2 );
   }

   area = geodCoord_;

   return flag;
}

// =============================================================
// class PmCylindProjectionFactory - builds PmCylindrical projections
class PmCylindProjectionFactory : public PmProjectionFactory 
{
	virtual PmProjection* Build( const MvRequest& reqst ) 
		{ return new PmCylindEquid ( reqst ); }

public:
	PmCylindProjectionFactory() : PmProjectionFactory("CYLINDRICAL") {}
};

// Instance which is loaded in the "factory"
static PmCylindProjectionFactory cylindProjectionFactoryInstance;


//==============================================================
// CYLINDRICAL Projection
//
PmCylindEquid::PmCylindEquid ( const MvRequest& viewRequest ):
	PmGeneralProjection ( viewRequest )
{
	GPlon0 = viewRequest ( "MAP_VERTICAL_LONGITUDE" ); 
//	GPlon0 *= DEG_TO_RAD;

	// Calculate the projection coordinates
	this->CalculateProjectionCoord();
}

//	GEODETIC TO EQUIDISTANT CYLINDRICAL COORDINATES
Point
PmCylindEquid :: LL2PC (Point& ptll)
{
	double ptllx = (double)ptll.X();
	double ptlly = (double)ptll.Y();

	ptllx = Prd*(ptllx - GPlon0)*cos(GPstlat1);
	ptlly = Prd*ptlly;

	return(Point(ptllx,ptlly));
}

//	EQUIDISTANT CYLINDRICAL TO GEODETIC COORDINATES
Point
PmCylindEquid :: PC2LL (Point& ptpc)
{
	double ptpcx = (double)ptpc.X();
	double ptpcy = (double)ptpc.Y();

	ptpcy = ptpcy/Prd;
	ptpcx = GPlon0 + ptpcx/(Prd*cos(GPstlat1));

	return (Point(ptpcx,ptpcy));
}
 
double
PmCylindEquid::CheckOriginLongitude ()
{
	double x0 = GPlon0 - 180.;
	if ( ( geodCoord_.Left() < x0 ) || ( geodCoord_.Right() > x0 + 360. ) )
		GPlon0 = geodCoord_.Left() +
			 ( ( geodCoord_.Right() - geodCoord_.Left() ) / 2. );

	return GPlon0;
}

bool
PmCylindEquid::CheckGeodeticCoordinates (Location& area)
{
   bool flag = true;

   // Check if individual values are within the range.
   // Magics now allows longitude coordinates to be greater than 360.
   double x1 = geodCoord_.Left();
   double x2 = geodCoord_.Right();
   double y2 = ( geodCoord_.Top()    >   90. ) ?   90 : geodCoord_.Top();
   double y1 = ( geodCoord_.Bottom() <  -90. ) ?  -90 : geodCoord_.Bottom();

   // Check if direction is ok (S -> N)
   if ( y2 < y1 )
   {
      double aux = y2;
      y2 = y1;
      y1 = aux;
   }
   else if ( y2 == y1)
   {
      y1 = -90.;
      y2 = +90.;
   }

   // Special cases
   if ( x2 == x1 )
   {
      if ( x2 == 0. )         x2 =  360.;
      else if ( x1 == 180.  ) x1 = -180.;
      else if ( x2 == -180. ) x2 =  180.;
   } 

   // Check if some values have been changed
   if ( ( geodCoord_.Left()   != x1 ) ||
        ( geodCoord_.Right()  != x2 ) ||
        ( geodCoord_.Bottom() != y1 ) ||
        ( geodCoord_.Top()    != y2 )   )
   {
      flag = false;
      geodCoord_ = Location ( y2, x1, y1, x2 );
   }

   area = geodCoord_;

   return flag;
}

// =============================================================
// class PmPolarProjectionFactory - builds Polar projections
//
class PmPolarProjectionFactory : public PmProjectionFactory 
{
	virtual PmProjection* Build( const MvRequest& reqst  ) 
		{ return new PmPolarStereo ( reqst ); }

public:
	PmPolarProjectionFactory() : PmProjectionFactory("POLAR_STEREOGRAPHIC") {}
};

// Instance which is loaded in the "factory"
static PmPolarProjectionFactory polarProjectionFactoryInstance;

//===============================================================
//  PmPolar Stereo projection
//
PmPolarStereo::PmPolarStereo ( const MvRequest& viewRequest ):
	PmGeneralProjection ( viewRequest )
{
	if ( viewRequest ( "MAP_HEMISPHERE" ) == Cached ( "SOUTH" ) )
		 GPhemis = SOUTH;
	else
	         GPhemis = NORTH;

	if ( GPhemis == NORTH )
		GPlat0 =  90. * DEG_TO_RAD;
	else
		GPlat0 = -90. * DEG_TO_RAD;

	GPlon0 = viewRequest ( "MAP_VERTICAL_LONGITUDE" ); 
//	GPlon0 *= DEG_TO_RAD;

	// Calculate the projection coordinates
	this->CalculateProjectionCoord();
}

//	GEODETIC TO POLAR STEREOGRAPHIC COORDINATES
//
Point
PmPolarStereo :: LL2PC (Point& ptll)
{
	double	k0,			// Scale factor
		e,			// Eccentricity
		pi,			// Ancillary variables
		lon0,			// auxilliary origin longitude
		t,ro,aux1,aux2,aux3,ptllx,ptlly;
	
	ptllx = (double)ptll.X();
	ptlly = (double)ptll.Y();

//	k0 = 0.994;	// Standard parallel 80.1 degrees 
	k0 = 0.933;	// Standard parallel 60 degrees 
	e = sqrt((double)2*Pflt - pow(Pflt,(double)2));
	pi = 4.*atan((double)1);

	ptlly *= GPhemis;
	ptllx *= GPhemis;
	lon0 = (GPhemis == 1) ? GPlon0 : -GPlon0;
	lon0 *= DEG_TO_RAD;

	aux1 = (1. - e*sin(ptlly))/(1. + e*sin(ptlly));
	t = tan((pi/4.) - (ptlly/2.))/pow(aux1,(e/(double)2));
	aux2 = pow(((double)1 + e),((double)1 + e));
	aux3 = pow(((double)1 - e),((double)1 - e));
	ro = 2.*Prd*k0*t/sqrt(aux2*aux3);

	aux1   = ro*sin(ptllx - lon0);
	ptlly = -ro*cos(ptllx - lon0);
	aux1 *= GPhemis;
	ptlly *= GPhemis;
	
	if (GPhemis == -1)
	{
		aux1 *= GPhemis;
		ptlly *= GPhemis;
	}

	return(Point(aux1,ptlly));
}

//	POLAR STEREOGRAPHIC TO GEODETIC COORDINATES
//
Point
PmPolarStereo :: PC2LL (Point& ptpc)
{
	double	k0,			// Scale factor

		equad,			// Squared eccentricity
		e,		        // Eccentricity
		pi,			// Ancillary variables
		lon0,			// auxilliary origin longitude
		ro,t,xx,aux1,aux2,aux3,aux4,aux5,ptpcx,ptpcy,px,py;

	px = (double)ptpc.X();
	py = (double)ptpc.Y();

//	k0 = 0.994;	// Standard parallel 80.1 degrees 
	k0 = 0.933;	// Standard parallel 60 degrees
	pi = 4.*atan((double)1);
	equad = 2.*Pflt - pow(Pflt,(double)2);
	e = sqrt(equad);

	if (GPhemis == -1)
	{
		px *= GPhemis;
		py *= GPhemis;
	}

	lon0 = (GPhemis == 1) ? GPlon0 : -GPlon0;
	lon0 *= DEG_TO_RAD;

	ro = sqrt(px*px + py*py);
	aux1 = pow(((double)1 + e),((double)1 + e));
	aux2 = pow(((double)1 - e),((double)1 - e));
	t = (ro*sqrt(aux1*aux2))/(2.*Prd*k0);
	xx = pi/2. - 2.*atan(t);
	aux3 = equad/2. + 5.*equad*equad/24. + equad*equad*equad/12.;
	aux4 = 7.*equad*equad/48. + 29.*equad*equad*equad/240.;
	aux5 = 7.*equad*equad*equad/120.;

	ptpcy = xx + aux3*sin((double)2*xx) + aux4*sin((double)4*xx) + aux5*sin((double)6*xx);

	if (py != 0.)
		ptpcx = lon0 + atan(px/(-py));

	if (GPhemis == 1)
	{
		if (px > 0. && py > 0.)
			ptpcx = ptpcx + pi;
		else if (px < 0. && py > 0.)
			ptpcx = ptpcx - pi;
		else if (px > 0. && py == 0.)
			ptpcx = lon0 + pi / 2.;
		else if (px < 0. && py == 0.)
			ptpcx = lon0 - pi / 2.;
		else if (px == 0. && py == 0.)
			ptpcx = lon0;
	}
	else
	{
		ptpcy *= GPhemis;
		ptpcx *= GPhemis;

		if (px > 0. && py < 0.)
			ptpcx = ptpcx + pi;
		else if (px < 0. && py < 0.)
			ptpcx = ptpcx - pi;
		else if (px > 0. && py == 0.)
			ptpcx = lon0 + pi / 2.;
		else if (px < 0. && py == 0.)
			ptpcx = lon0 - pi / 2.;
		else if (px == 0. && py == 0.)
			ptpcx = lon0;
	}

	if (ptpcx < (-pi)) ptpcx += 2.*pi;
	else if (ptpcx > pi)    ptpcx -= 2.*pi;

	return (Point(ptpcx,ptpcy));
}

bool
PmPolarStereo::CheckGeodeticCoordinates (Location& area)
{
	bool flag = true;

//	Remember: if GPhemis == NORTH, GPhemis =  1
//	          if GPhemis == SOUTH, GPhemis = -1
	if ( geodCoord_.Top()*GPhemis < -20. )
	{
		geodCoord_ = Location ( -20.*GPhemis, geodCoord_.Left(),
					geodCoord_.Bottom(), geodCoord_.Right() );
		flag = false;
	}

	if ( geodCoord_.Bottom()*GPhemis < -20. )
	{
		geodCoord_ = Location ( geodCoord_.Top(), geodCoord_.Left(),
					-20.*GPhemis, geodCoord_.Right() );
		flag = false;
	}

	Point llPointLL ( geodCoord_.Left() * DEG_TO_RAD, geodCoord_.Bottom() * DEG_TO_RAD );
	Point llPointPC = this->LL2PC ( llPointLL );

	Point urPointLL ( geodCoord_.Right() * DEG_TO_RAD, geodCoord_.Top() * DEG_TO_RAD );
	Point urPointPC = this->LL2PC ( urPointLL );

 	Point bmPointLL ( GPlon0 * DEG_TO_RAD, -1.*GPhemis * DEG_TO_RAD );
	Point bmPointPC = this->LL2PC ( bmPointLL );

	Point lmPointLL ( ( GPlon0 - 90.*GPhemis ) * DEG_TO_RAD, -1.*GPhemis * DEG_TO_RAD );
	Point lmPointPC = this->LL2PC ( lmPointLL );

	Point tmPointLL ( ( GPlon0 + 180. ) * DEG_TO_RAD, -1.*GPhemis * DEG_TO_RAD );
	Point tmPointPC = this->LL2PC ( tmPointLL );

	Point rmPointLL ( ( GPlon0 + 90.*GPhemis ) * DEG_TO_RAD, -1.*GPhemis * DEG_TO_RAD );
	Point rmPointPC = this->LL2PC ( rmPointLL );

	if ( ( urPointPC.Y() <= llPointPC.Y() ) ||
	     ( urPointPC.X() <= llPointPC.X() ) ||
	     ( llPointPC.Y()  < bmPointPC.Y() ) ||
	     ( llPointPC.X()  < lmPointPC.X() ) ||
	     ( urPointPC.Y()  > tmPointPC.Y() ) ||
	     ( urPointPC.X()  > rmPointPC.X() ) )
     	{
		geodCoord_ = Location ( -20. * GPhemis, -45. * GPhemis,
					-20. * GPhemis, 135. * GPhemis );
		GPlon0 = 0;
		flag   = false;
	}

	area = geodCoord_;
	return flag;
}

// =============================================================
// class PmLambertProjectionFactory - builds PmLambert projections
class PmLambertProjectionFactory : public PmProjectionFactory 
{
	virtual PmProjection* Build( const MvRequest& reqst ) 
		{ return new PmLambert( reqst ); }

public:
	PmLambertProjectionFactory() : PmProjectionFactory("LAMBERT") {}
};

// Instance which is loaded in the "factory"
static PmLambertProjectionFactory lambertProjectionFactoryInstance;

// ====================================================================
//
//  PmLambert projection
PmLambert::PmLambert ( const MvRequest& viewRequest ):
	PmGeneralProjection ( viewRequest )	//PmGeneralProjection ( "LAMBERT" )
{
	// Initialize some parameters
	GPlon0   = viewRequest("SUBPAGE_MAP_CENTRE_LONGITUDE");
	GPlat0   = (double)viewRequest("SUBPAGE_MAP_CENTRE_LATITUDE") * DEG_TO_RAD;
	GPstlat1 = (double)viewRequest("SUBPAGE_MAP_STANDARD_LATITUDE_1") * DEG_TO_RAD;
	GPstlat2 = (double)viewRequest("SUBPAGE_MAP_STANDARD_LATITUDE_2") * DEG_TO_RAD;
	LScale   = (double)viewRequest("SUBPAGE_MAP_SCALE");

	// Calculate the projection coordinates
	this->CalculateProjectionCoord();
}

// 		GEODETIC TO LAMBERT COORDINATES
Point
PmLambert :: LL2PC (Point& ) //ptll
{
#if 0
	double	equad,			// Squared eccentricity
		e,			// Ancillary variables
		m1,m2,aux1,aux2,aux0,t1,t2,t0,n,efe,ro0,aux,
		t,ro,teta,ptllx,ptlly;

	ptllx = (double)ptll.X();
	ptlly = (double)ptll.Y();

	equad = 2.*Pflt - pow(Pflt,(double)2);
	e = sqrt(equad);

	m1 = cos(GPstlat1)/sqrt((double)1-equad*pow(sin(GPstlat1),(double)2));
	m2 = cos(GPstlat2)/sqrt((double)1-equad*pow(sin(GPstlat2),(double)2));
	aux1 = sqrt(((double)1-e*sin(GPstlat1))/((double)1+e*sin(GPstlat1)));
	aux2 = sqrt(((double)1-e*sin(GPstlat2))/((double)1+e*sin(GPstlat2)));
	aux0 = sqrt(((double)1-e*sin(GPlat0))/((double)1+e*sin(GPlat0)));
	t1 = ((1.-tan(GPstlat1/(double)2))/(1.+tan(GPstlat1/(double)2)))/pow(aux1,e);
	t2 = ((1.-tan(GPstlat2/(double)2))/(1.+tan(GPstlat2/(double)2)))/pow(aux2,e);
	t0 = ((1.-tan(GPlat0/(double)2))/(1.+tan(GPlat0/(double)2)))/pow(aux0,e);

	if (GPstlat1 == GPstlat2)
		n = sin(GPstlat1);
	else
		n = (log(m1)-log(m2))/(log(t1)-log(t2));

	efe = m1/(n*pow(t1,n));
	ro0 = Prd*efe*pow(t0,n);

	aux = sqrt(((double)1-e*sin(ptlly))/((double)1+e*sin(ptlly)));
	t = ((1.-tan(ptlly/(double)2))/(1.+tan(ptlly/(double)2)))/pow(aux,e);
	ro = Prd*efe*pow(t,n);
	teta = n*(ptllx - GPlon0);
	ptllx = ro*sin(teta);
	ptlly = ro0 - ro*cos(teta);

	return(Point(ptllx,ptlly));
#endif
	return(Point(0.,0.));
}

//		LAMBERT TO GEODETIC COORDINATES
Point
PmLambert :: PC2LL (Point& ) //ptpc
{
#if 0
	double	equad,			// Squared eccentricity 
		pi,			// PI value
		e,m1,m2,aux1,aux2,aux0,t1,t2,t0,n,efe,ro0,ro,teta,
		t,xx,aux3,aux4,aux5,ptpcx,ptpcy;

	int	sinal;

	ptpcx = (double)ptpc.X();
	ptpcy = (double)ptpc.Y();

	equad = 2.*Pflt - pow(Pflt,(double)2);
	e = sqrt(equad);
	pi = 4.*atan((double)1);

	m1 = cos(GPstlat1)/sqrt((double)1-equad*pow(sin(GPstlat1),(double)2));
	m2 = cos(GPstlat2)/sqrt((double)1-equad*pow(sin(GPstlat2),(double)2));
	aux1 = sqrt(((double)1-e*sin(GPstlat1))/((double)1+e*sin(GPstlat1)));
	aux2 = sqrt(((double)1-e*sin(GPstlat2))/((double)1+e*sin(GPstlat2)));
	aux0 = sqrt(((double)1-e*sin(GPlat0))/((double)1+e*sin(GPlat0)));
	t1 = ((1.-tan(GPstlat1/(double)2))/(1.+tan(GPstlat1/(double)2)))/pow(aux1,e);
	t2 = ((1.-tan(GPstlat2/(double)2))/(1.+tan(GPstlat2/(double)2)))/pow(aux2,e);
	t0 = ((1.-tan(GPlat0/(double)2))/(1.+tan(GPlat0/(double)2)))/pow(aux0,e);

	if (GPstlat1 == GPstlat2)
		n = sin(GPstlat1);
	else
		n = (log(m1)-log(m2))/(log(t1)-log(t2));

	efe = m1/(n*pow(t1,n));
	ro0 = Prd*efe*pow(t0,n);

	sinal = (int)(n/fabs(n));
	ro = sqrt(ptpcx*ptpcx + (ro0-ptpcy)*(ro0-ptpcy));
	ro *= sinal;
	teta = atan(ptpcx/(ro0-ptpcy));
	t = pow((ro/(Prd*efe)),(double)1/n);
	xx = pi/2. - 2.*atan(t);
	aux3 = equad/2. + 5.*equad*equad/24. + equad*equad*equad/12.;
	aux4 = 7.*equad*equad/48. + 29.*equad*equad*equad/240.;
	aux5 = (7.*equad*equad*equad/120.)*sin(12.*atan(t));

	ptpcy = xx + aux3*sin(4.*atan(t)) - aux4*sin(8.*atan(t)) + aux5;
	ptpcx = teta/n + GPlon0;

	return (Point(ptpcx,ptpcy));
#endif
	return(Point(0.,0.));
}

double
PmLambert::CheckOriginLongitude ()
{
	//Add code later
	return 0.;
}

// =============================================================
// class PmOceanSectionProjectionFactory - builds PmOceanSection projections
class PmOceanSectionProjectionFactory : public PmProjectionFactory 
{
	virtual PmProjection* Build( const MvRequest& reqst ) 
		{ return new PmOceanSection( reqst ); }

public:
	PmOceanSectionProjectionFactory() : PmProjectionFactory("OCEAN_SECTION") {}
};

// Instance which is loaded in the "factory"
static PmOceanSectionProjectionFactory oceansectionProjectionFactoryInstance;

// ====================================================================
//
//  PmOceanSection projection
PmOceanSection::PmOceanSection ( const MvRequest& viewRequest ):
	PmGeneralProjection ( viewRequest )	//PmGeneralProjection ( "OCEAN_SECTION" )
{
	this->CalculateProjectionCoord();
}

// 		GEODETIC TO OCEAN_SECTION COORDINATES
Point
PmOceanSection :: LL2PC (Point& )
{
	//Add code later
	return(Point(0.,0.));
}

//		OCEAN_SECTION TO GEODETIC COORDINATES
Point
PmOceanSection :: PC2LL (Point& )
{
	//Add code later
	return(Point(0.,0.));
}

double
PmOceanSection::CheckOriginLongitude ()
{
	//Add code later
	return 0.;
}

// =============================================================
// class PmAitoffProjectionFactory - builds PmAitoff projections
class PmAitoffProjectionFactory : public PmProjectionFactory 
{
	virtual PmProjection* Build( const MvRequest& reqst ) 
		{ return new PmAitoff( reqst ); }

public:
	PmAitoffProjectionFactory() : PmProjectionFactory("AITOFF") {}
};

// Instance which is loaded in the "factory"
static PmAitoffProjectionFactory aitoffProjectionFactoryInstance;

// ====================================================================
//
//  PmAitoff projection
PmAitoff::PmAitoff ( const MvRequest& viewRequest ):
	PmGeneralProjection ( viewRequest )	//PmGeneralProjection ( "AITOFF" )
{
	// Initialize vertical longitude
	GPlon0 = viewRequest ( "MAP_VERTICAL_LONGITUDE" ); 

	// Calculate the projection coordinates
	this->CalculateProjectionCoord();
}

// 		GEODETIC TO AITOFF COORDINATES
Point
PmAitoff :: LL2PC (Point& )
{
	//Add code later
	return(Point(0.,0.));
}

//		AITOFF TO GEODETIC COORDINATES
Point
PmAitoff :: PC2LL (Point& )
{
	//Add code later
	return(Point(0.,0.));
}

