- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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

Go to the documentation of this file.

    00001 // CLASSIFICATION: UNCLASSIFIED
    00002
    00003 /***************************************************************************/
    00004 /* RSC IDENTIFIER: VAN DER GRINTEN
    00005  *
    00006  * ABSTRACT
    00007  *
    00008  *    This component provides conversions between Geodetic coordinates
    00009  *    (latitude and longitude in radians) and Van Der Grinten projection
    00010  *    coordinates (easting and northing in meters).  The Van Der Grinten
    00011  *    projection employs a spherical Earth model.  The Spherical Radius
    00012  *    used is the the radius of the sphere having the same area as the
    00013  *    ellipsoid.
    00014  *
    00015  * ERROR HANDLING
    00016  *
    00017  *    This component checks parameters for valid values.  If an invalid value
    00018  *    is found, the error code is combined with the current error code using
    00019  *    the bitwise or.  This combining allows multiple error codes to be
    00020  *    returned. The possible error codes are:
    00021  *
    00022  *          GRIN_NO_ERROR           : No errors occurred in function
    00023  *          GRIN_LAT_ERROR          : Latitude outside of valid range
    00024  *                                      (-90 to 90 degrees)
    00025  *          GRIN_LON_ERROR          : Longitude outside of valid range
    00026  *                                      (-180 to 360 degrees)
    00027  *          GRIN_EASTING_ERROR      : Easting outside of valid range
    00028  *                                      (False_Easting +/- ~20,000,000 m,
    00029  *                                       depending on ellipsoid parameters)
    00030  *          GRIN_NORTHING_ERROR     : Northing outside of valid range
    00031  *                                      (False_Northing +/- ~20,000,000 m,
    00032  *                                       depending on ellipsoid parameters)
    00033  *          GRIN_RADIUS_ERROR       : Coordinates too far from pole,
    00034  *                                      depending on ellipsoid and
    00035  *                                      projection parameters
    00036  *          GRIN_CENT_MER_ERROR     : Central meridian outside of valid range
    00037  *                                      (-180 to 360 degrees)
    00038  *          GRIN_A_ERROR            : Semi-major axis less than or equal to zero
    00039  *          GRIN_INV_F_ERROR        : Inverse flattening outside of valid range
    00040  *                                      (250 to 350)
    00041  *
    00042  * REUSE NOTES
    00043  *
    00044  *    VAN DER GRINTEN is intended for reuse by any application that performs a
    00045  *    Van Der Grinten projection or its inverse.
    00046  *
    00047  * REFERENCES
    00048  *
    00049  *    Further information on VAN DER GRINTEN can be found in the Reuse Manual.
    00050  *
    00051  *    VAN DER GRINTEN originated from :  U.S. Army Topographic Engineering Center
    00052  *                                Geospatial Information Division
    00053  *                                7701 Telegraph Road
    00054  *                                Alexandria, VA  22310-3864
    00055  *
    00056  * LICENSES
    00057  *
    00058  *    None apply to this component.
    00059  *
    00060  * RESTRICTIONS
    00061  *
    00062  *    VAN DER GRINTEN has no restrictions.
    00063  *
    00064  * ENVIRONMENT
    00065  *
    00066  *    VAN DER GRINTEN was tested and certified in the following environments:
    00067  *
    00068  *    1. Solaris 2.5 with GCC, version 2.8.1
    00069  *    2. Windows 95 with MS Visual C++, version 6
    00070  *
    00071  * MODIFICATIONS
    00072  *
    00073  *    Date              Description
    00074  *    ----              -----------
    00075  *    3-1-07          Original Code
    00076  *
    00077  */
    00078
    00079
    00080 /***************************************************************************/
    00081 /*
    00082  *                               INCLUDES
    00083  */
    00084
    00085 #include <math.h>
    00086 #include "VanDerGrinten.h"
    00087 #include "MapProjection3Parameters.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  *    VanDerGrinten.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 MAX_LAT = ( 90 * (PI / 180.0) );  /* 90 degrees in radians   */
    00114 const double TWO_PI = (2.0 * PI);
    00115 const double TWO_OVER_PI = (2.0 / PI);
    00116 const double PI_OVER_3 = (PI / 3.0);
    00117 const double ONE_THIRD  = (1.0 / 3.0);
    00118
    00119
    00120
    00121 /************************************************************************/
    00122 /*                              FUNCTIONS
    00123  *
    00124  */
    00125
    00126 VanDerGrinten::VanDerGrinten( double ellipsoidSemiMajorAxis, double ellipsoidFlattening, double centralMeridian, double falseEasting, double falseNorthing ) :
    00127   CoordinateSystem(),
    00128   es2( 0.0066943799901413800 ),
    00129   es4( 4.4814723452405e-005 ),
    00130   es6( 3.0000678794350e-007 ),
    00131   Ra( 6371007.1810824 ),
    00132   PI_Ra( 20015109.356056 ),
    00133   Grin_Origin_Long( 0.0 ),
    00134   Grin_False_Easting( 0.0 ),
    00135   Grin_False_Northing( 0.0 )
    00136 {
    00137 /*
    00138  * The constructor receives the ellipsoid parameters and
    00139  * projection parameters as inputs, and sets the corresponding state
    00140  * variables.  If any errors occur, an exception is thrown with a description
    00141  * of the error.
    00142  *
    00143  *    ellipsoidSemiMajorAxis   : Semi-major axis of ellipsoid, in meters   (input)
    00144  *    ellipsoidFlattening      : Flattening of ellipsoid                   (input)
    00145  *    centralMeridian          : Longitude in radians at the center of     (input)
    00146  *                               the projection
    00147  *    falseEasting             : A coordinate value in meters assigned to the
    00148  *                               central meridian of the projection.       (input)
    00149  *    falseNorthing            : A coordinate value in meters assigned to the
    00150  *                               origin latitude of the projection         (input)
    00151  */
    00152
    00153   double inv_f = 1 / ellipsoidFlattening;
    00154   char errorStatus[500] = "";
    00155
    00156   if (ellipsoidSemiMajorAxis <= 0.0)
    00157   { /* Semi-major axis must be greater than zero */
    00158     strcat( errorStatus, ErrorMessages::semiMajorAxis );
    00159   }
    00160   if ((inv_f < 250) || (inv_f > 350))
    00161   { /* Inverse flattening must be between 250 and 350 */
    00162     strcat( errorStatus, ErrorMessages::ellipsoidFlattening );
    00163   }
    00164   if ((centralMeridian < -PI) || (centralMeridian > TWO_PI))
    00165   { /* origin longitude out of range */
    00166     strcat( errorStatus, ErrorMessages::centralMeridian );
    00167   }
    00168
    00169   if( strlen( errorStatus ) > 0)
    00170     throw CoordinateConversionException( errorStatus );
    00171
    00172   semiMajorAxis = ellipsoidSemiMajorAxis;
    00173   flattening = ellipsoidFlattening;
    00174
    00175   es2 = 2 * flattening - flattening * flattening;
    00176   es4 = es2 * es2;
    00177   es6 = es4 * es2;
    00178   /* spherical radius */
    00179   Ra = semiMajorAxis * (1.0 - es2 / 6.0 - 17.0 * es4 / 360.0 - 67.0 * es6 /3024.0);
    00180   PI_Ra = PI * Ra;
    00181   if (centralMeridian > PI)
    00182     centralMeridian -= TWO_PI;
    00183   Grin_Origin_Long = centralMeridian;
    00184   Grin_False_Easting = falseEasting;
    00185   Grin_False_Northing = falseNorthing;
    00186 }
    00187
    00188
    00189 VanDerGrinten::VanDerGrinten( const VanDerGrinten &v )
    00190 {
    00191   semiMajorAxis = v.semiMajorAxis;
    00192   flattening = v.flattening;
    00193   es2 = v.es2;
    00194   es4 = v.es4;
    00195   es6 = v.es6;
    00196   Ra = v.Ra;
    00197   PI_Ra = v.PI_Ra;
    00198   Grin_Origin_Long = v.Grin_Origin_Long;
    00199   Grin_False_Easting = v.Grin_False_Easting;
    00200   Grin_False_Northing = v.Grin_False_Northing;
    00201 }
    00202
    00203
    00204 VanDerGrinten::~VanDerGrinten()
    00205 {
    00206 }
    00207
    00208
    00209 VanDerGrinten& VanDerGrinten::operator=( const VanDerGrinten &v )
    00210 {
    00211   if( this != &v )
    00212   {
    00213     semiMajorAxis = v.semiMajorAxis;
    00214     flattening = v.flattening;
    00215     es2 = v.es2;
    00216     es4 = v.es4;
    00217     es6 = v.es6;
    00218     Ra = v.Ra;
    00219     PI_Ra = v.PI_Ra;
    00220     Grin_Origin_Long = v.Grin_Origin_Long;
    00221     Grin_False_Easting = v.Grin_False_Easting;
    00222     Grin_False_Northing = v.Grin_False_Northing;
    00223   }
    00224
    00225   return *this;
    00226 }
    00227
    00228
    00229 MapProjection3Parameters* VanDerGrinten::getParameters() const
    00230 {
    00231 /*
    00232  * The function getParameters returns the current ellipsoid
    00233  * parameters, and Van Der Grinten projection parameters.
    00234  *
    00235  *    ellipsoidSemiMajorAxis     : Semi-major axis of ellipsoid, in meters   (output)
    00236  *    ellipsoidFlattening        : Flattening of ellipsoid                   (output)
    00237  *    centralMeridian            : Longitude in radians at the center of     (output)
    00238  *                                 the projection
    00239  *    falseEasting               : A coordinate value in meters assigned to the
    00240  *                                 central meridian of the projection.       (output)
    00241  *    falseNorthing              : A coordinate value in meters assigned to the
    00242  *                                 origin latitude of the projection         (output)
    00243  */
    00244
    00245   return new MapProjection3Parameters( CoordinateType::vanDerGrinten, Grin_Origin_Long, Grin_False_Easting, Grin_False_Northing );
    00246 }
    00247
    00248
    00249 MSP::CCS::MapProjectionCoordinates* VanDerGrinten::convertFromGeodetic( MSP::CCS::GeodeticCoordinates* geodeticCoordinates )
    00250 {
    00251 /*
    00252  * The function convertFromGeodetic converts geodetic (latitude and
    00253  * longitude) coordinates to Van Der Grinten projection (easting and northing)
    00254  * coordinates, according to the current ellipsoid and Van Der Grinten projection
    00255  * parameters.  If any errors occur, an exception is thrown with a description
    00256  * of the error.
    00257  *
    00258  *    longitude         : Longitude (lambda) in radians       (input)
    00259  *    latitude          : Latitude (phi) in radians           (input)
    00260  *    easting           : Easting (X) in meters               (output)
    00261  *    northing          : Northing (Y) in meters              (output)
    00262  */
    00263
    00264   double dlam;                      /* Longitude - Central Meridan */
    00265   double aa, aasqr;
    00266   double gg;
    00267   double pp, ppsqr;
    00268   double gg_MINUS_ppsqr, ppsqr_PLUS_aasqr;
    00269   double in_theta;
    00270   double theta;
    00271   double sin_theta, cos_theta;
    00272   double qq;
    00273   double easting, northing;
    00274   char errorStatus[50] = "";
    00275
    00276   double longitude = geodeticCoordinates->longitude();
    00277   double latitude = geodeticCoordinates->latitude();
    00278
    00279   if ((latitude < -PI_OVER_2) || (latitude > PI_OVER_2))
    00280   {  /* Latitude out of range */
    00281     strcat( errorStatus, ErrorMessages::latitude );
    00282   }
    00283   if ((longitude < -PI) || (longitude > TWO_PI))
    00284   {  /* Longitude out of range */
    00285     strcat( errorStatus, ErrorMessages::longitude );
    00286   }
    00287
    00288   if( strlen( errorStatus ) > 0)
    00289     throw CoordinateConversionException( errorStatus );
    00290
    00291   dlam = longitude - Grin_Origin_Long;
    00292   if (dlam > PI)
    00293   {
    00294     dlam -= TWO_PI;
    00295   }
    00296   if (dlam < -PI)
    00297   {
    00298     dlam += TWO_PI;
    00299   }
    00300
    00301   if (latitude == 0.0)
    00302   {
    00303     easting = Ra * dlam + Grin_False_Easting;
    00304     northing = 0.0;
    00305   }
    00306   else if (dlam == 0.0 || floatEq(latitude,MAX_LAT,.00001)  || floatEq(latitude,-MAX_LAT,.00001))
    00307   {
    00308     in_theta = fabs(TWO_OVER_PI * latitude);
    00309
    00310     if (in_theta > 1.0)
    00311       in_theta = 1.0;
    00312     else if (in_theta < -1.0)
    00313       in_theta = -1.0;
    00314
    00315     theta = asin(in_theta);
    00316     easting = 0.0;
    00317     northing = PI_Ra * tan(theta / 2) + Grin_False_Northing;
    00318     if (latitude < 0.0)
    00319       northing *= -1.0;
    00320   }
    00321   else
    00322   {
    00323     aa = 0.5 * fabs(PI / dlam - dlam / PI);
    00324     in_theta = fabs(TWO_OVER_PI * latitude);
    00325
    00326     if (in_theta > 1.0)
    00327       in_theta = 1.0;
    00328     else if (in_theta < -1.0)
    00329       in_theta = -1.0;
    00330
    00331     theta = asin(in_theta);
    00332     sin_theta = sin(theta);
    00333     cos_theta = cos(theta);
    00334     gg = cos_theta / (sin_theta + cos_theta - 1);
    00335     pp = gg * (2 / sin_theta - 1);
    00336     aasqr = aa * aa;
    00337     ppsqr = pp * pp;
    00338     gg_MINUS_ppsqr = gg - ppsqr;
    00339     ppsqr_PLUS_aasqr = ppsqr + aasqr;
    00340     qq = aasqr + gg;
    00341     easting = PI_Ra * (aa * (gg_MINUS_ppsqr) +
    00342                         sqrt(aasqr * (gg_MINUS_ppsqr) * (gg_MINUS_ppsqr) -
    00343                              (ppsqr_PLUS_aasqr) * (gg * gg - ppsqr))) /
    00344                (ppsqr_PLUS_aasqr) + Grin_False_Easting;
    00345     if (dlam < 0.0)
    00346       easting *= -1.0;
    00347     northing = PI_Ra * (pp * qq - aa * sqrt ((aasqr + 1) * (ppsqr_PLUS_aasqr) - qq * qq)) /
    00348                 (ppsqr_PLUS_aasqr) + Grin_False_Northing;
    00349     if (latitude < 0.0)
    00350       northing *= -1.0;
    00351   }
    00352
    00353   return new MapProjectionCoordinates( CoordinateType::vanDerGrinten, easting, northing );
    00354 }
    00355
    00356
    00357 MSP::CCS::GeodeticCoordinates* VanDerGrinten::convertToGeodetic( MSP::CCS::MapProjectionCoordinates* mapProjectionCoordinates )
    00358 {
    00359 /*
    00360  * The function convertToGeodetic converts Grinten projection
    00361  * (easting and northing) coordinates to geodetic (latitude and longitude)
    00362  * coordinates, according to the current ellipsoid and Grinten projection
    00363  * coordinates.  If any errors occur, an exception is thrown with a description
    00364  * of the error.
    00365  *
    00366  *    easting           : Easting (X) in meters                  (input)
    00367  *    northing          : Northing (Y) in meters                 (input)
    00368  *    longitude         : Longitude (lambda) in radians          (output)
    00369  *    latitude          : Latitude (phi) in radians              (output)
    00370  */
    00371
    00372   double dx, dy;
    00373   double xx, xxsqr;
    00374   double yy, yysqr, two_yysqr;
    00375   double xxsqr_PLUS_yysqr;
    00376   double c1;
    00377   double c2;
    00378   double c3, c3sqr;
    00379   double c2_OVER_3c3;
    00380   double dd;
    00381   double a1;
    00382   double m1;
    00383   double i;
    00384   double theta1;
    00385   double temp;
    00386   const double epsilon = 1.0e-2;
    00387   double delta = PI_Ra + epsilon;
    00388   double longitude, latitude;
    00389   char errorStatus[50] = "";
    00390
    00391   double easting = mapProjectionCoordinates->easting();
    00392   double northing = mapProjectionCoordinates->northing();
    00393
    00394   if ((easting > (Grin_False_Easting + delta)) ||
    00395       (easting < (Grin_False_Easting - delta)))
    00396   { /* Easting out of range */
    00397     strcat( errorStatus, ErrorMessages::easting );
    00398   }
    00399   if ((northing > (Grin_False_Northing + delta)) ||
    00400       (northing < (Grin_False_Northing - delta)))
    00401   { /* Northing out of range */
    00402     strcat( errorStatus, ErrorMessages::northing );
    00403   }
    00404
    00405   if( strlen( errorStatus ) > 0)
    00406     throw CoordinateConversionException( errorStatus );
    00407
    00408   temp = sqrt(easting * easting + northing * northing);
    00409
    00410   if ((temp > (Grin_False_Easting + PI_Ra + epsilon)) ||
    00411       (temp > (Grin_False_Northing + PI_Ra + epsilon)) ||
    00412       (temp < (Grin_False_Easting - PI_Ra - epsilon)) ||
    00413       (temp < (Grin_False_Northing - PI_Ra - epsilon)))
    00414   { /* Point is outside of projection area */
    00415       throw CoordinateConversionException( ErrorMessages::radius );
    00416   }
    00417
    00418   dy = northing - Grin_False_Northing;
    00419   dx = easting - Grin_False_Easting;
    00420   xx = dx / PI_Ra;
    00421   yy = dy / PI_Ra;
    00422   xxsqr = xx * xx;
    00423   yysqr = yy * yy;
    00424   xxsqr_PLUS_yysqr = xxsqr + yysqr;
    00425   two_yysqr = 2 * yysqr;
    00426
    00427   if (northing == 0.0)
    00428     latitude = 0.0;
    00429   else
    00430   {
    00431     c1 = - fabs(yy) * (1 + xxsqr_PLUS_yysqr);
    00432     c2 = c1 - two_yysqr + xxsqr;
    00433     c3 = - 2 * c1 + 1 + two_yysqr + (xxsqr_PLUS_yysqr) * (xxsqr_PLUS_yysqr);
    00434     c2_OVER_3c3 = c2 / (3.0 * c3);
    00435     c3sqr = c3 * c3;
    00436     dd = yysqr / c3 + ((2 * c2 * c2 * c2) / (c3sqr * c3) - (9 * c1 * c2) / (c3sqr)) / 27;
    00437     a1 = (c1 - c2 * c2_OVER_3c3) /c3;
    00438     m1 = 2 * sqrt(-ONE_THIRD * a1);
    00439     i = 3 * dd/ (a1 * m1);
    00440     if ((i > 1.0)||(i < -1.0))
    00441       latitude = MAX_LAT;
    00442     else
    00443     {
    00444       theta1 = ONE_THIRD * acos(3 * dd / (a1 * m1));
    00445       latitude = PI * (-m1 * cos(theta1 + PI_OVER_3) - c2_OVER_3c3);
    00446     }
    00447   }
    00448   if (northing < 0.0)
    00449     latitude *= -1.0;
    00450
    00451   if (xx == 0.0)
    00452     longitude = Grin_Origin_Long;
    00453   else
    00454   {
    00455     longitude = PI * (xxsqr_PLUS_yysqr - 1 +
    00456                        sqrt(1 + (2 * xxsqr - two_yysqr) + (xxsqr_PLUS_yysqr) * (xxsqr_PLUS_yysqr))) /
    00457                  (2 * xx) + Grin_Origin_Long;
    00458   }
    00459   if (latitude > PI_OVER_2)  /* force distorted values to 90, -90 degrees */
    00460     latitude = PI_OVER_2;
    00461   else if (latitude < -PI_OVER_2)
    00462     latitude = -PI_OVER_2;
    00463
    00464   if (longitude > PI)
    00465     longitude -= TWO_PI;
    00466   if (longitude < -PI)
    00467     longitude += TWO_PI;
    00468
    00469   if (longitude > PI) /* force distorted values to 180, -180 degrees */
    00470     longitude = PI;
    00471   else if (longitude < -PI)
    00472     longitude = -PI;
    00473
    00474   return new GeodeticCoordinates( CoordinateType::geodetic, longitude, latitude );
    00475 }
    00476
    00477
    00478 double VanDerGrinten::floatEq( double x, double v, double epsilon )
    00479 {
    00480   return (((v - epsilon) < x) && (x < (v + epsilon)));
    00481 }
    00482
    00483
    00484 // CLASSIFICATION: UNCLASSIFIED