- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# Y:/msp/devkits/temp_geotrans/master/geotrans3.1/CCS/src/dtcc/CoordinateSystems/cyleqa/CylindricalEqualArea.cpp

Go to the documentation of this file.

    00001 // CLASSIFICATION: UNCLASSIFIED
    00002
    00003 /***************************************************************************/
    00004 /* RSC IDENTIFIER: CYLINDRICAL EQUAL AREA
    00005  *
    00006  * ABSTRACT
    00007  *
    00008  *    This component provides conversions between Geodetic coordinates
    00009  *    (latitude and longitude in radians) and Cylindrical Equal Area projection
    00010  *    coordinates (easting and northing in meters).
    00011  *
    00012  * ERROR HANDLING
    00013  *
    00014  *    This component checks parameters for valid values.  If an invalid value
    00015  *    is found, the error code is combined with the current error code using
    00016  *    the bitwise or.  This combining allows multiple error codes to be
    00017  *    returned. The possible error codes are:
    00018  *
    00019  *          CYEQ_NO_ERROR           : No errors occurred in function
    00020  *          CYEQ_LAT_ERROR          : Latitude outside of valid range
    00021  *                                      (-90 to 90 degrees)
    00022  *          CYEQ_LON_ERROR          : Longitude outside of valid range
    00023  *                                      (-180 to 360 degrees)
    00024  *          CYEQ_EASTING_ERROR      : Easting outside of valid range
    00025  *                                      (False_Easting +/- ~20,000,000 m,
    00026  *                                       depending on ellipsoid parameters
    00027  *                                       and Origin_Latitude)
    00028  *          CYEQ_NORTHING_ERROR     : Northing outside of valid range
    00029  *                                      (False_Northing +/- ~6,000,000 m,
    00030  *                                       depending on ellipsoid parameters
    00031  *                                       and Origin_Latitude)
    00032  *          CYEQ_ORIGIN_LAT_ERROR   : Origin latitude outside of valid range
    00033  *                                      (-90 to 90 degrees)
    00034  *          CYEQ_CENT_MER_ERROR     : Central meridian outside of valid range
    00035  *                                      (-180 to 360 degrees)
    00036  *          CYEQ_A_ERROR            : Semi-major axis less than or equal to zero
    00037  *          CYEQ_INV_F_ERROR        : Inverse flattening outside of valid range
    00038  *                                      (250 to 350)
    00039  *
    00040  * REUSE NOTES
    00041  *
    00042  *    CYLINDRICAL EQUAL AREA is intended for reuse by any application that performs a
    00043  *    Cylindrical Equal Area projection or its inverse.
    00044  *
    00045  * REFERENCES
    00046  *
    00047  *    Further information on CYLINDRICAL EQUAL AREA can be found in the Reuse Manual.
    00048  *
    00049  *    CYLINDRICAL EQUAL AREA originated from :
    00050  *                                U.S. Army Topographic Engineering Center
    00051  *                                Geospatial Information Division
    00052  *                                7701 Telegraph Road
    00053  *                                Alexandria, VA  22310-3864
    00054  *
    00055  * LICENSES
    00056  *
    00057  *    None apply to this component.
    00058  *
    00059  * RESTRICTIONS
    00060  *
    00061  *    CYLINDRICAL EQUAL AREA has no restrictions.
    00062  *
    00063  * ENVIRONMENT
    00064  *
    00065  *    CYLINDRICAL EQUAL AREA was tested and certified in the following environments:
    00066  *
    00067  *    1. Solaris 2.5 with GCC 2.8.1
    00068  *    2. MS Windows 95 with MS Visual C++ 6
    00069  *
    00070  * MODIFICATIONS
    00071  *
    00072  *    Date              Description
    00073  *    ----              -----------
    00074  *    04-16-99          Original Code
    00075  *    03-07-07          Original C++ Code
    00076  *
    00077  */
    00078
    00079
    00080 /***************************************************************************/
    00081 /*
    00082  *                               INCLUDES
    00083  */
    00084
    00085 #include <math.h>
    00086 #include "CylindricalEqualArea.h"
    00087 #include "MapProjection4Parameters.h"
    00088 #include "MapProjectionCoordinates.h"
    00089 #include "GeodeticCoordinates.h"
    00090 #include "CoordinateConversionException.h"
    00091 #include "ErrorMessages.h"
    00092
    00093 /*
    00094  *    math.h   - Standard C math library
    00095  *    CylindricalEqualArea.h - Is for prototype error checking
    00096  *    MapProjectionCoordinates.h   - defines map projection coordinates
    00097  *    GeodeticCoordinates.h   - defines geodetic coordinates
    00098  *    CoordinateConversionException.h - Exception handler
    00099  *    ErrorMessages.h  - Contains exception messages
    00100  */
    00101
    00102
    00103 using namespace MSP::CCS;
    00104
    00105
    00106 /***************************************************************************/
    00107 /*                               DEFINES
    00108  *
    00109  */
    00110
    00111 const double PI = 3.14159265358979323e0;  /* PI                            */
    00112 const double PI_OVER_2 = ( PI / 2.0);
    00113 const double TWO_PI = (2.0 * PI);
    00114 const double ONE = (1.0 * PI / 180);      /* 1 degree in radians           */
    00115
    00116
    00117 double cyeqCoeffTimesSine( double coeff, double c, double Beta )
    00118 {
    00119   return coeff * sin(c * Beta);
    00120 }
    00121
    00122
    00123 /************************************************************************/
    00124 /*                              FUNCTIONS
    00125  *
    00126  */
    00127
    00128 CylindricalEqualArea::CylindricalEqualArea( double ellipsoidSemiMajorAxis, double ellipsoidFlattening, double centralMeridian, double originLatitude, double falseEasting, double falseNorthing ) :
    00129   CoordinateSystem(),
    00130   es( .081819190842622 ),
    00131   es2( 0.0066943799901413800 ),
    00132   es4( 4.4814723452405e-005 ),
    00133   es6( 3.0000678794350e-007 ),
    00134   k0( 1.0 ),
    00135   Cyeq_a_k0( 6378137.0 ),
    00136   two_k0( 2.0 ),
    00137   c0( .0022392088624809 ),
    00138   c1( 2.8830839728915e-006 ),
    00139   c2( 5.0331826636906e-009 ),
    00140   Cyeq_Origin_Long( 0.0 ),
    00141   Cyeq_Origin_Lat( 0.0 ),
    00142   Cyeq_False_Easting( 0.0 ),
    00143   Cyeq_False_Northing( 0.0 ),
    00144   Cyeq_Max_Easting( 20037509.0 ),
    00145   Cyeq_Min_Easting( -20037509.0 ),
    00146   Cyeq_Delta_Northing( 6363886.0 )
    00147 {
    00148 /*
    00149  * The constructor receives the ellipsoid parameters and
    00150  * Cylindrical Equal Area projcetion parameters as inputs, and sets the corresponding
    00151  * state variables.  If any errors occur, an exception is thrown with a description
    00152  * of the error.
    00153  *
    00154  *    ellipsoidSemiMajorAxis  : Semi-major axis of ellipsoid, in meters   (input)
    00155  *    ellipsoidFlattening     : Flattening of ellipsoid                   (input)
    00156  *    centralMeridian         : Longitude in radians at the center of     (input)
    00157  *                              the projection
    00158  *    originLatitude          : Latitude in radians at which the          (input)
    00159  *                              point scale factor is 1.0
    00160  *    falseEasting            : A coordinate value in meters assigned to the
    00161  *                              central meridian of the projection.       (input)
    00162  *    falseNorthing           : A coordinate value in meters assigned to the
    00163  *                              origin latitude of the projection         (input)
    00164  */
    00165
    00166   double Sin_Cyeq_Origin_Lat;
    00167   double inv_f = 1 / ellipsoidFlattening;
    00168   char errorStatus[500] = "";
    00169
    00170   if (ellipsoidSemiMajorAxis <= 0.0)
    00171   { /* Semi-major axis must be greater than zero */
    00172     strcat( errorStatus, ErrorMessages::semiMajorAxis );
    00173   }
    00174   if ((inv_f < 250) || (inv_f > 350))
    00175   { /* Inverse flattening must be between 250 and 350 */
    00176     strcat( errorStatus, ErrorMessages::ellipsoidFlattening );
    00177   }
    00178   if ((originLatitude < -PI_OVER_2) || (originLatitude > PI_OVER_2))
    00179   { /* origin latitude out of range */
    00180     strcat( errorStatus, ErrorMessages::originLatitude );
    00181   }
    00182   if ((centralMeridian < -PI) || (centralMeridian > TWO_PI))
    00183   { /* origin longitude out of range */
    00184     strcat( errorStatus, ErrorMessages::centralMeridian );
    00185   }
    00186
    00187   if( strlen( errorStatus ) > 0)
    00188     throw CoordinateConversionException( errorStatus );
    00189
    00190   semiMajorAxis = ellipsoidSemiMajorAxis;
    00191   flattening = ellipsoidFlattening;
    00192
    00193   Cyeq_Origin_Lat = originLatitude;
    00194   if (centralMeridian > PI)
    00195     centralMeridian -= TWO_PI;
    00196   Cyeq_Origin_Long = centralMeridian;
    00197   Cyeq_False_Northing = falseNorthing;
    00198   Cyeq_False_Easting = falseEasting;
    00199   es2 = 2 * flattening - flattening * flattening;
    00200   es4 = es2 * es2;
    00201   es6 = es4 * es2;
    00202   es = sqrt(es2);
    00203   c0 = es2 / 3.0 + 31.0 * es4 / 180.0 + 517.0 * es6 / 5040.0;
    00204   c1 = 23.0 * es4 / 360.0 + 251.0 * es6 / 3780.0;
    00205   c2 = 761.0 * es6 / 45360.0;
    00206   Sin_Cyeq_Origin_Lat = sin(Cyeq_Origin_Lat);
    00207   k0 = cos(Cyeq_Origin_Lat) / sqrt(1.0 - es2 * Sin_Cyeq_Origin_Lat * Sin_Cyeq_Origin_Lat);
    00208   Cyeq_a_k0 = semiMajorAxis * k0;
    00209   two_k0 = 2.0 * k0;
    00210
    00211   if (Cyeq_Origin_Long > 0)
    00212   {
    00213     GeodeticCoordinates gcMax( CoordinateType::geodetic, Cyeq_Origin_Long - PI - ONE, PI_OVER_2 );
    00214     MapProjectionCoordinates* tempCoordinates = convertFromGeodetic( &gcMax );
    00215     Cyeq_Max_Easting = tempCoordinates->easting();
    00216     delete tempCoordinates;
    00217
    00218     GeodeticCoordinates gcMin( CoordinateType::geodetic, Cyeq_Origin_Long - PI, PI_OVER_2 );
    00219     tempCoordinates = convertFromGeodetic( &gcMin );
    00220     Cyeq_Min_Easting = tempCoordinates->easting();
    00221     delete tempCoordinates;
    00222
    00223     GeodeticCoordinates gcDelta( CoordinateType::geodetic, PI, PI_OVER_2 );
    00224     tempCoordinates = convertFromGeodetic( &gcDelta );
    00225     Cyeq_Delta_Northing = tempCoordinates->northing();
    00226     delete tempCoordinates;
    00227   }
    00228   else if (Cyeq_Origin_Long < 0)
    00229   {
    00230     GeodeticCoordinates gcMax( CoordinateType::geodetic, Cyeq_Origin_Long + PI, PI_OVER_2 );
    00231     MapProjectionCoordinates* tempCoordinates = convertFromGeodetic( &gcMax );
    00232     Cyeq_Max_Easting = tempCoordinates->easting();
    00233     delete tempCoordinates;
    00234
    00235     GeodeticCoordinates gcMin( CoordinateType::geodetic, Cyeq_Origin_Long + PI + ONE, PI_OVER_2 );
    00236     tempCoordinates = convertFromGeodetic( &gcMin );
    00237     Cyeq_Min_Easting = tempCoordinates->easting();
    00238     delete tempCoordinates;
    00239
    00240     GeodeticCoordinates gcDelta( CoordinateType::geodetic, PI, PI_OVER_2 );
    00241     tempCoordinates = convertFromGeodetic( &gcDelta );
    00242     Cyeq_Delta_Northing = tempCoordinates->northing();
    00243     delete tempCoordinates;
    00244   }
    00245   else
    00246   {
    00247     GeodeticCoordinates gcTemp( CoordinateType::geodetic, PI, PI_OVER_2 );
    00248     MapProjectionCoordinates* tempCoordinates = convertFromGeodetic( &gcTemp );
    00249     Cyeq_Max_Easting = tempCoordinates->easting();
    00250     Cyeq_Delta_Northing = tempCoordinates->northing();
    00251     delete tempCoordinates;
    00252     Cyeq_Min_Easting = -Cyeq_Max_Easting;
    00253   }
    00254
    00255   if(Cyeq_False_Northing)
    00256     Cyeq_Delta_Northing -= Cyeq_False_Northing;
    00257   if (Cyeq_Delta_Northing < 0)
    00258     Cyeq_Delta_Northing = -Cyeq_Delta_Northing;
    00259
    00260   if(Cyeq_False_Easting)
    00261   {
    00262     Cyeq_Min_Easting -= Cyeq_False_Easting;
    00263     Cyeq_Max_Easting -= Cyeq_False_Easting;
    00264   }
    00265 }
    00266
    00267
    00268 CylindricalEqualArea::CylindricalEqualArea( const CylindricalEqualArea &cea )
    00269 {
    00270   semiMajorAxis = cea.semiMajorAxis;
    00271   flattening = cea.flattening;
    00272   es = cea.es;
    00273   es2 = cea.es2;
    00274   es4 = cea.es4;
    00275   es6 = cea.es6;
    00276   k0 = cea.k0;
    00277   Cyeq_a_k0 = cea.Cyeq_a_k0;
    00278   two_k0 = cea.two_k0;
    00279   c0 = cea.c0;
    00280   c1 = cea.c1;
    00281   c2 = cea.c2;
    00282   Cyeq_Origin_Long = cea.Cyeq_Origin_Long;
    00283   Cyeq_Origin_Lat = cea.Cyeq_Origin_Lat;
    00284   Cyeq_False_Easting = cea.Cyeq_False_Easting;
    00285   Cyeq_False_Northing = cea.Cyeq_False_Northing;
    00286   Cyeq_Max_Easting = cea.Cyeq_Max_Easting;
    00287   Cyeq_Min_Easting = cea.Cyeq_Min_Easting;
    00288   Cyeq_Delta_Northing = cea.Cyeq_Delta_Northing;
    00289 }
    00290
    00291
    00292 CylindricalEqualArea::~CylindricalEqualArea()
    00293 {
    00294 }
    00295
    00296
    00297 CylindricalEqualArea& CylindricalEqualArea::operator=( const CylindricalEqualArea &cea )
    00298 {
    00299   if( this != &cea )
    00300   {
    00301     semiMajorAxis = cea.semiMajorAxis;
    00302     flattening = cea.flattening;
    00303     es = cea.es;
    00304     es2 = cea.es2;
    00305     es4 = cea.es4;
    00306     es6 = cea.es6;
    00307     k0 = cea.k0;
    00308     Cyeq_a_k0 = cea.Cyeq_a_k0;
    00309     two_k0 = cea.two_k0;
    00310     c0 = cea.c0;
    00311     c1 = cea.c1;
    00312     c2 = cea.c2;
    00313     Cyeq_Origin_Long = cea.Cyeq_Origin_Long;
    00314     Cyeq_Origin_Lat = cea.Cyeq_Origin_Lat;
    00315     Cyeq_False_Easting = cea.Cyeq_False_Easting;
    00316     Cyeq_False_Northing = cea.Cyeq_False_Northing;
    00317     Cyeq_Max_Easting = cea.Cyeq_Max_Easting;
    00318     Cyeq_Min_Easting = cea.Cyeq_Min_Easting;
    00319     Cyeq_Delta_Northing = cea.Cyeq_Delta_Northing;
    00320   }
    00321
    00322   return *this;
    00323 }
    00324
    00325
    00326 MapProjection4Parameters* CylindricalEqualArea::getParameters() const
    00327 {
    00328 /*
    00329  * The function getParameters returns the current ellipsoid
    00330  * parameters, and Cylindrical Equal Area projection parameters.
    00331  *
    00332  *    ellipsoidSemiMajorAxis  : Semi-major axis of ellipsoid, in meters   (output)
    00333  *    ellipsoidFlattening     : Flattening of ellipsoid                   (output)
    00334  *    centralMeridian         : Longitude in radians at the center of     (output)
    00335  *                              the projection
    00336  *    originLatitude          : Latitude in radians at which the          (output)
    00337  *                              point scale factor is 1.0
    00338  *    falseEasting            : A coordinate value in meters assigned to the
    00339  *                              central meridian of the projection.       (output)
    00340  *    falseNorthing           : A coordinate value in meters assigned to the
    00341  *                              origin latitude of the projection         (output)
    00342  */
    00343
    00344   return new MapProjection4Parameters( CoordinateType::cylindricalEqualArea, Cyeq_Origin_Long, Cyeq_Origin_Lat, Cyeq_False_Easting, Cyeq_False_Northing );
    00345 }
    00346
    00347
    00348 MSP::CCS::MapProjectionCoordinates* CylindricalEqualArea::convertFromGeodetic( MSP::CCS::GeodeticCoordinates* geodeticCoordinates )
    00349 {
    00350 /*
    00351  * The function convertFromGeodetic converts geodetic (latitude and
    00352  * longitude) coordinates to Cylindrical Equal Area projection (easting and northing)
    00353  * coordinates, according to the current ellipsoid and Cylindrical Equal Area projection
    00354  * parameters.  If any errors occur, an exception is thrown with a description
    00355  * of the error.
    00356  *
    00357  *    longitude         : Longitude (lambda) in radians       (input)
    00358  *    latitude          : Latitude (phi) in radians           (input)
    00359  *    easting           : Easting (X) in meters               (output)
    00360  *    northing          : Northing (Y) in meters              (output)
    00361  */
    00362
    00363   double dlam;                      /* Longitude - Central Meridan */
    00364   double qq;
    00365   double x;
    00366   char errorStatus[50] = "";
    00367
    00368   double longitude = geodeticCoordinates->longitude();
    00369   double latitude = geodeticCoordinates->latitude();
    00370   double sin_lat = sin(latitude);
    00371
    00372   if ((latitude < -PI_OVER_2) || (latitude > PI_OVER_2))
    00373   { /* Latitude out of range */
    00374     strcat( errorStatus, ErrorMessages::latitude );
    00375   }
    00376   if ((longitude < -PI) || (longitude > TWO_PI))
    00377   { /* Longitude out of range */
    00378     strcat( errorStatus, ErrorMessages::longitude );
    00379   }
    00380
    00381   if( strlen( errorStatus ) > 0)
    00382     throw CoordinateConversionException( errorStatus );
    00383
    00384   dlam = longitude - Cyeq_Origin_Long;
    00385   if (dlam > PI)
    00386   {
    00387     dlam -= TWO_PI;
    00388   }
    00389   if (dlam < -PI)
    00390   {
    00391     dlam += TWO_PI;
    00392   }
    00393   x = es * sin_lat;
    00394   qq = cyleqarQ( sin_lat, x );
    00395
    00396   double easting = Cyeq_a_k0 * dlam + Cyeq_False_Easting;
    00397   double northing = semiMajorAxis * qq / two_k0 + Cyeq_False_Northing;
    00398
    00399   return new MapProjectionCoordinates( CoordinateType::cylindricalEqualArea, easting, northing );
    00400 }
    00401
    00402
    00403 MSP::CCS::GeodeticCoordinates* CylindricalEqualArea::convertToGeodetic( MSP::CCS::MapProjectionCoordinates* mapProjectionCoordinates )
    00404 {
    00405 /*
    00406  * The function convertToGeodetic converts
    00407  * Cylindrical Equal Area projection (easting and northing) coordinates
    00408  * to geodetic (latitude and longitude) coordinates, according to the
    00409  * current ellipsoid and Cylindrical Equal Area projection
    00410  * coordinates.  If any errors occur, an exception is thrown with a description
    00411  * of the error.
    00412  *
    00413  *    easting           : Easting (X) in meters                  (input)
    00414  *    northing          : Northing (Y) in meters                 (input)
    00415  *    longitude         : Longitude (lambda) in radians          (output)
    00416  *    latitude          : Latitude (phi) in radians              (output)
    00417  */
    00418
    00419   double sin2beta, sin4beta, sin6beta;
    00420   double dx;     /* Delta easting - Difference in easting (easting-FE)      */
    00421   double dy;     /* Delta northing - Difference in northing (northing-FN)   */
    00422   double qp;
    00423   double beta;
    00424   double sin_lat = sin(PI_OVER_2);
    00425   double i;
    00426   double x;
    00427   char errorStatus[50] = "";
    00428
    00429   double easting = mapProjectionCoordinates->easting();
    00430   double northing = mapProjectionCoordinates->northing();
    00431
    00432   if ((easting < (Cyeq_False_Easting + Cyeq_Min_Easting))
    00433       || (easting > (Cyeq_False_Easting + Cyeq_Max_Easting)))
    00434   { /* Easting out of range */
    00435     strcat( errorStatus, ErrorMessages::easting );
    00436   }
    00437   if ((northing < (Cyeq_False_Northing - fabs(Cyeq_Delta_Northing)))
    00438       || (northing > (Cyeq_False_Northing + fabs(Cyeq_Delta_Northing))))
    00439   { /* Northing out of range */
    00440     strcat( errorStatus, ErrorMessages::northing );
    00441   }
    00442
    00443   if( strlen( errorStatus ) > 0)
    00444     throw CoordinateConversionException( errorStatus );
    00445
    00446   dy = northing - Cyeq_False_Northing;
    00447   dx = easting - Cyeq_False_Easting;
    00448   x = es * sin_lat;
    00449   qp = cyleqarQ( sin_lat, x );
    00450   i = two_k0 * dy / (semiMajorAxis * qp);
    00451   if (i > 1.0)
    00452     i = 1.0;
    00453   else if (i < -1.0)
    00454     i = -1.0;
    00455   beta = asin(i);
    00456   sin2beta = cyeqCoeffTimesSine(c0, 2.0, beta);
    00457   sin4beta = cyeqCoeffTimesSine(c1, 4.0, beta);
    00458   sin6beta = cyeqCoeffTimesSine(c2, 6.0, beta);
    00459
    00460   double latitude = beta + sin2beta + sin4beta + sin6beta;
    00461   double longitude = Cyeq_Origin_Long + dx / Cyeq_a_k0;
    00462
    00463   if (latitude > PI_OVER_2)  /* force distorted values to 90, -90 degrees */
    00464     latitude = PI_OVER_2;
    00465   else if (latitude < -PI_OVER_2)
    00466     latitude = -PI_OVER_2;
    00467
    00468   if (longitude > PI)
    00469     longitude -= TWO_PI;
    00470   if (longitude < -PI)
    00471     longitude += TWO_PI;
    00472
    00473   if (longitude > PI) /* force distorted values to 180, -180 degrees */
    00474     longitude = PI;
    00475   else if (longitude < -PI)
    00476     longitude = -PI;
    00477
    00478   return new GeodeticCoordinates( CoordinateType::geodetic, longitude, latitude );
    00479 }
    00480
    00481
    00482 double CylindricalEqualArea::cyleqarQ( double slat, double x )
    00483 {
    00484   return (1.0-es2)*(slat/(1.0-x*x)-(1.0/(2.0*es)) * log((1.0-x)/(1.0+x)));
    00485 }
    00486
    00487
    00488
    00489 // CLASSIFICATION: UNCLASSIFIED