/****************************************************************************
 *   gproj.h : 
 *             This header file defines geographic referencing system class
 *
 *   Credit: 
 *	       The map projections in this file were implemented originaly by
 *	       EROS Data Center in the package GCTPC.  
 *	       (ftp://edcftp.cr.usgs.gov:pub/software/gctpc)
 *             This file and gproj.cpp merely provide a c++ wrap up of the
 *             projections. Each projection is implemented in an individual class.
 *
 *   Change Log :
 *		 Nov 23, 1997 Initial version,  Liujian Qian
 *
 *   $Id: gproj.h,v 1.23 1999/02/10 21:56:02 qian Exp $
 ***************************************************************************/
#ifndef _GEOREF_H_
#define _GEOREF_H_

#include "gobject.h"


#define  MAXLONG	2147483647.
#define  DBLLONG 	4.61168601e18
#define  EPSLN		1.0e-10

class ostream;
/**
 * identification code for the major projections;
 * not all projections listed here are supported by GFC.
 */ 
enum GProjCode {
    Geographic = 0,	//just plain longitude/latitude
    UTM,		//60 zones
    StatePlane,		//a grid coordinate system
    Albers,		//conical equal area
    Lambert,		//Lambert comformal conic
    Mercator,		//true local shapes
    Polyconic,		//many cones; 
    LambertAzimuthal,   //zenithal equal area
    Azimuthal,		//true distance & direction in center
    Robinson,		//or Orthophanic
    Polar,		//Polar Stereographic
    TransverseMercator  //
};



/**
 * @internal 
 * GUV is for storing intermediate coordinates during
 * projection transformation.
 */
struct GUV
{
    double u,v;
};

/**
 * Ellipsoid of the Earth
 */
struct GEllipsoid 
{
    double major, minor;  //Hemi-major and minor axis of Earth
};

extern GEllipsoid clarke66;
extern GEllipsoid new_international;


/**
 *    @short  defines basic variables/methods for map projections.
 *
 *     This class defines basic map projection parameters and routines;
 *     It serves as the base class for all concrete projections. 
 */
class GMapProj : public GObject 
{
protected:
    union	 
    {
	GEllipsoid ellip;	//treat Earth as an ellipsoid
	double	   radius;	//treat Earth as a sphere
    };
    
    union {
	double     lon_center;  //central longitude (meridian) 
	double     mer_center;  //central meridian
    };
    union {
 	double     lat_center;  //latitude at the center/origin of projection
	double     lat_origin;
    };

    double         false_easting;        //offset (in meters)
    double         false_northing;       //to avoid negative x,y coordinates 

    GProjCode	   proj_id;		 //identification code
    
    enum {MAX_VAL = 4};

    // scale_factor and es can be computed from other parameters
    // so they will not be part of the 	stored projection data.
    double	   scale_factor;         //determined by what?
    double	   es;			 //square of eccentricity (1-b^2/a^2)
    
public :
    friend  ostream&    operator<<(ostream& s, const GMapProj& a);
    virtual uint32   	getPSize() const;
    virtual Result  	input     (const char*  );
    virtual Result 	output    (char*& ) ;
    virtual Result	pack	  (DataPipe& );
    virtual Result      unpack    (DataPipe& );

public:
    /**
     * default constructor.
     */
    NOP			GMapProj();    
    /**
     * Forward conversion from (longitude,latitude) to projected coordinates
     * in meters.
     * @param (lon, lat) MUST be *radians* !!!
     */
    virtual Result	forward(double lon, double lat, double& x, double& y)=0;
    /**
     * Inverse conversion from projected coordinates to (longitude, latitude).
     * (x,y) must be in meters; and (lon, lat) will be in *radians*.
     */
    virtual Result	inverse(double x, double y, double& lon, double& lat)=0;


public:

    //routines commonly used during projection 
    /**
     * adjust a longitude angle to range from -180 to 180 radians
     */
    static  double	adjustLon(double);
    /**
     * Function to eliminate roundoff errors in asin
     */
    static double	asinZ(double x);
    /**
     * calculate constants e0, e1, e2, e3, which are used in
     * calculating true distance along meridian; x is squared eccentricity.
     */
    static double 	e0(double x);
    static double	e1(double x);
    static double	e2(double x);
    static double 	e3(double x);
    /**
     * calculate constant e4 from input of the eccentricity of the spheroid x
     */
    static double	e4(double);
    /**
     * Computes the constant small m for Oblique Equal Area.
     */
    static double	ms(double e, double s, double c);
    /**
     * compute constant small q which is the radius of a 
     * parallel of latitude, phi, divided by the semimajor axis
     */
    static double	qs(double e, double s, double c);
    /**
     * compute the constant small t for use in the forward
     * computations in the Lambert Conformal Conic and the Polar
     * Stereographic projections.
     */
    static double	ts(double e, double phi, double sinphi);
    /**
     * compute phi1, the latitude for the inverse of the
     * Albers Conical Equal-Area projection.
     */
    static double	phi1z(double e, double qs, Result& res);
    /**
     * compute the latitude angle, phi2, for the inverse of the
     * Lambert Conformal Conic and Polar Stereographic projections.
     */
    static double	phi2z(double e, double ts, Result& res);
    /**
     * compute latitude, phi3, for the inverse of the Equidistant
     * Conic projection.
     */
    static double 	phi3z(double ml,double e0,double e1,
			      double e2, double e3, Result& res);
    /**
     * compute phi4, the latitude for the inverse of the
     * Polyconic projection.
     */
    static Result	phi4z(double, double, double, double, double,
			      double, double, double*, double*);
    /**
     * calculate a UTM zone number.
     * Longitude should be in degrees!
     */
    static int		getUTMZone(double lon);
    /**
     * convert Degree/Minute/Second to decimal degree.
     */
    static double	DMS2DD(int d, int m, int s);
    /**
     * convert a Decimal Degree (DD) coordinate into degree/minute/second
     */
    static void		DD2DMS(double dd, int& d, int& m, int& s);
    /**
     * calculate the distance along a meridian from 
     * the Equator to latitude (phi)
     */
    double	        distML(double phi, double e0=0, double e1=0, 
			       double e2=0, double e3=0) const;
    /**
     * test if the ellipsoid is Clarke66.
     */
    bool                isClarke66() const;
    /**
     * test if Earth is treated as a shpere (if eccentricty < c)
     */
    bool                isSphere(const double c = 0.00001) const;
};



/**
 * @short class for UTM projection.
 *
 * UTM projection divides the Earth between lats. 84N and 80S 
 *     into 60 zones. The scal along central meridian is reduced to 0.9996.
 *     In the northern Hemisphere, the Equator at the central meridian is 
 *     considered the origin, with an x coordinate of 500,000 m and a y of
 *     0. For the southern Hemisphere the same point is the origin, but while
 *     x remains same 500,000m, the y is 10,000000. IN each case numbers 
 *     increase toward east and north thus to avoid negative values. For each
 *     point on the Earth, its position is uniquely determined by the (x,y) 
 *     coordinates plus the zone number.
 */
class  GProjUTM : public GMapProj
{
    double      indicator;	//sphereical indicator: 1 if sphere
    double      ml0;		//small value m
    double	_e0, _e1, _e2, _e3, _e, _esp; //eccentricty constants
protected:
    int		zone;		//for southern Hemisphere use negative values

public:    // common methods of GObject.
    friend  ostream&    operator<<(ostream& s, const GProjUTM& a);
    virtual uint32   	getPSize() const;
    virtual Result  	input     (const char*  );
    virtual Result 	output    (char*& ) ;
    virtual Result	pack	  (DataPipe& );
    virtual Result      unpack    (DataPipe& );

public:
    /**
     * Default constructor; must call init() before any conversion.
     */
    NOP	       	GProjUTM();
    /**	
     * construct a UTM projection with major/minor axis and  zone number.
     * If the projection is applied to Southern Hemishpere then the
     * value of _zone should be negative (ie -55 instead of 55 for part
     * of Australia).
     */
    NOP		GProjUTM(double r_maj, double r_min, int _zone);
    /**
     * same as previous constructor; uses a handy form of parameter.
     */
    NOP		GProjUTM(const GEllipsoid& e, int _zone);
    /**
     * initialize for the UTM projection. Must be called before
     * any foward/inverse conversion can happen.
     */
    Result	init(double r_maj, double r_min, int _zone);
    /**
     * Forward conversion from (longitude,latitude) to UTM coordinates
     * in meters.
     * @param (lon, lat) MUST be *radians* !!!
     */
    Result	forward(double lon, double lat, double& x, double& y);
    /**
     * Inverse conversion from UTM coordinates to (longitude, latitude).
     * (x,y) must be in meters; and (lon, lat) will be in *radians*.
     */
    Result	inverse(double x, double y, double& lon, double& lat);
};



/**
 * @short Class for Lambert Conformal Conic projection.
 *
 * A conic conformal projections where parallels are unequally spaced 
 * arcs of concentric circles, more closely spaced near the center 
 * of the map. Meridians are equally spaced radii of the same circles,
 * thereby cutting parallels at right angles. Scale is true along two
 * standard parallels, normally, or along just one. Used for maps of
 * countries and regions with predominant east-west expanse.
 * -- (J. Snyder, "Map Projections - A working manual").
 */
class GProjLambert : public GMapProj
{
    double 	ns;	//ratio of angle between meridian
    double	f0;     //flattening of ellipsoid
    double	rh;	//height above ellipsoid
    double	e;	//eccentricity
    
protected:
    double	std_par1, std_par2;
    
public :
    friend  ostream&    operator<<(ostream& s, const GProjLambert& a);
    virtual uint32   	getPSize() const;
    virtual Result  	input     (const char*  );
    virtual Result 	output    (char*& ) ;
    virtual Result	pack	  (DataPipe& );
    virtual Result      unpack    (DataPipe& );
public:
    /**
     * Default constructor; must call init() before any conversion.
     */
    NOP	       	GProjLambert();
    /**	
     * construct a Lambert (CC) projection. 
     * @param major/minor axis; 
     *	lat1/lat2 first and second standard parallel; both are radians 
     *  c_lon/c_lat central longitude and latitude;   both are radians
     *  x_false/y_false false easting and northing.   both are radians
     */
    NOP		GProjLambert(double r_maj, double r_min, 
			     double lat1, double lat2, 
			     double c_lon, double c_lat,
			     double x_false, double y_false);
    /**
     * initialize for the Lambert projection. Must be called before
     * any foward/inverse conversion can happen.
     * @param uses same parameter as in second constructor. longitudes/lattitudes
     *        are all radians.
     */
    Result	init(double r_maj, double r_min, 
		     double lat1, double lat2, 
		     double c_lon, double c_lat,
		     double x_false, double y_false);
    /**
     * Forward conversion from (longitude,latitude) to Lambert coordinates
     * in meters.
     * @param (lon, lat) MUST be radians!!!
     */
    Result	forward(double lon, double lat, double& x, double& y);
    /**
     * Inverse conversion from Lambert coordinates to (longitude, latitude).
     * (x,y) must be in meters; and (lon, lat) will be in radians.
     */
    Result	inverse(double x, double y, double& lon, double& lat);
};    


/**
 * @short  Mercator projection class
 *
 */
class GProjMercator : public GMapProj
{
protected:
    double e, m1;		// small value m

public:
    /**
     */
    NOP  	GProjMercator();
    /**
     * constructor
     * @param  c_lon/c_lat central longitude/latitude (must be radians).
     */
    NOP		GProjMercator(double r_maj, double r_min, double c_lon, double c_lat,
			      double false_east, double false_north);
    /**
     * initialize for the Mercator projection. Must be called before
     * any foward/inverse conversion can happen, if the object is created
     * using the constructor with no parameters.
     * @param uses same parameter as in second constructor. 
     */
    Result	init(double r_maj, double r_min, 
		     double c_lon, double c_lat,
		     double x_false, double y_false);
    /**
     * Forward conversion from (longitude,latitude) to Mercator coordinates
     * in meters.
     * @param (lon, lat) MUST be radians!!!
     */
    Result	forward(double lon, double lat, double& x, double& y);
    /**
     * Inverse conversion from Mercator coordinates to (longitude, latitude).
     * (x,y) must be in meters; and (lon, lat) will be in radians.
     */
    Result	inverse(double x, double y, double& lon, double& lat);
};



/**
 * @short Albers Conical equal-area projection class.
 * One of the most commonly used projection for maps of theconterminous 
 * United States. It uses two standard parallels.
 */
class GProjAlbers : public GMapProj
{
    double	c;	//constant c
    double	e3;	//eccentricity
    double	rh;	//height above elipsoid
    double	ns0;	//ratio between meridians

protected:
    double	std_par1, std_par2;
    
public:
    friend  ostream&    operator<<(ostream& s, const GProjAlbers& a);	

public:
    /**
     * this constructor has no parameters. You mush call init() before
     * any projection can take place using this object.
     */
    NOP		GProjAlbers();
    
    /**
     * create an Albers map projection object with the given parameters.
     * @param  	r_maj, r_min  is the major/minor axis of the earth
     *		lat1/lat2 is the first and second standard parallel (in radians)
     *		lon0/lat0 is the central longitude and origin latitude (in radians)
     *		fs_east/fs_north is the false easting/norhting.
     */
    NOP		GProjAlbers(double r_maj, double r_min, 
			    double lat1,  double lat2,
			    double lon0,  double lat0,
			    double fs_east=0, double fs_north=0);
    /**
     * setup the parameters for the Albers projection. This is called
     * by the constructor with the same set of parameters.
     */
    Result	init(double r_maj, double r_min, 
		     double lat1,  double lat2,
		     double lon0,  double lat0,
		     double fs_east=0, double fs_north=0);
    /**
     * Forward conversion from (longitude,latitude) to Albers coordinates
     * in meters.
     * @param (lon, lat) MUST be radians!!!
     */
    Result	forward(double lon, double lat, double& x, double& y);
    /**
     * Inverse conversion from Albers coordinates to (longitude, latitude).
     * (x,y) must be in *meters*; and (lon, lat) will be in *radians*.
     */
    Result	inverse(double x, double y, double& lon, double& lat);
};    
    
#endif

Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999