- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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

Go to the documentation of this file.

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