- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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

Go to the documentation of this file.

    00001 // CLASSIFICATION: UNCLASSIFIED
    00002
    00003 /***************************************************************************/
    00004 /* RSC IDENTIFIER:  MGRS
    00005  *
    00006  * ABSTRACT
    00007  *
    00008  *    This component converts between geodetic coordinates (latitude and
    00009  *    longitude) and Military Grid Reference System (MGRS) coordinates.
    00010  *
    00011  * ERROR HANDLING
    00012  *
    00013  *    This component checks parameters for valid values.  If an invalid value
    00014  *    is found, the error code is combined with the current error code using
    00015  *    the bitwise or.  This combining allows multiple error codes to be
    00016  *    returned. The possible error codes are:
    00017  *
    00018  *          MGRS_NO_ERROR          : No errors occurred in function
    00019  *          MGRS_LAT_ERROR         : Latitude outside of valid range
    00020  *                                    (-90 to 90 degrees)
    00021  *          MGRS_LON_ERROR         : Longitude outside of valid range
    00022  *                                    (-180 to 360 degrees)
    00023  *          MGRS_STR_ERROR         : An MGRS string error: string too long,
    00024  *                                    too short, or badly formed
    00025  *          MGRS_PRECISION_ERROR   : The precision must be between 0 and 5
    00026  *                                    inclusive.
    00027  *          MGRS_A_ERROR           : Semi-major axis less than or equal to zero
    00028  *          MGRS_INV_F_ERROR       : Inverse flattening outside of valid range
    00029  *                                    (250 to 350)
    00030  *          MGRS_EASTING_ERROR     : Easting outside of valid range
    00031  *                                    (100,000 to 900,000 meters for UTM)
    00032  *                                    (0 to 4,000,000 meters for UPS)
    00033  *          MGRS_NORTHING_ERROR    : Northing outside of valid range
    00034  *                                    (0 to 10,000,000 meters for UTM)
    00035  *                                    (0 to 4,000,000 meters for UPS)
    00036  *          MGRS_ZONE_ERROR        : Zone outside of valid range (1 to 60)
    00037  *          MGRS_HEMISPHERE_ERROR  : Invalid hemisphere ('N' or 'S')
    00038  *
    00039  * REUSE NOTES
    00040  *
    00041  *    MGRS is intended for reuse by any application that does conversions
    00042  *    between geodetic coordinates and MGRS coordinates.
    00043  *
    00044  * REFERENCES
    00045  *
    00046  *    Further information on MGRS can be found in the Reuse Manual.
    00047  *
    00048  *    MGRS originated from : U.S. Army Topographic Engineering Center
    00049  *                           Geospatial Information Division
    00050  *                           7701 Telegraph Road
    00051  *                           Alexandria, VA  22310-3864
    00052  *
    00053  * LICENSES
    00054  *
    00055  *    None apply to this component.
    00056  *
    00057  * RESTRICTIONS
    00058  *
    00059  *
    00060  * ENVIRONMENT
    00061  *
    00062  *    MGRS was tested and certified in the following environments:
    00063  *
    00064  *    1. Solaris 2.5 with GCC version 2.8.1
    00065  *    2. Windows 95 with MS Visual C++ version 6
    00066  *
    00067  * MODIFICATIONS
    00068  *
    00069  *    Date              Description
    00070  *    ----              -----------
    00071  *    2-27-07          Original Code
    00072  */
    00073
    00074
    00075 /***************************************************************************/
    00076 /*
    00077  *                               INCLUDES
    00078  */
    00079
    00080 #include <ctype.h>
    00081 #include <math.h>
    00082 #include <string.h>
    00083 #include "UPS.h"
    00084 #include "UTM.h"
    00085 #include "MGRS.h"
    00086 #include "EllipsoidParameters.h"
    00087 #include "MGRSorUSNGCoordinates.h"
    00088 #include "GeodeticCoordinates.h"
    00089 #include "UPSCoordinates.h"
    00090 #include "UTMCoordinates.h"
    00091 #include "CoordinateConversionException.h"
    00092 #include "ErrorMessages.h"
    00093 #include "WarningMessages.h"
    00094
    00095 /*
    00096  *      ctype.h     - Standard C character handling library
    00097  *      math.h      - Standard C math library
    00098  *      stdio.h     - Standard C input/output library
    00099  *      string.h    - Standard C string handling library
    00100  *      UPS.h       - Universal Polar Stereographic (UPS) projection
    00101  *      UTM.h       - Universal Transverse Mercator (UTM) projection
    00102  *      MGRS.h      - function prototype error checking
    00103  *      MGRSorUSNGCoordinates.h   - defines mgrs coordinates
    00104  *      GeodeticCoordinates.h   - defines geodetic coordinates
    00105  *      UPSCoordinates.h   - defines ups coordinates
    00106  *      UTMCoordinates.h   - defines utm coordinates
    00107  *      CoordinateConversionException.h - Exception handler
    00108  *      ErrorMessages.h  - Contains exception messages
    00109  *      WarningMessages.h  - Contains warning messages
    00110  */
    00111
    00112
    00113 using namespace MSP::CCS;
    00114
    00115
    00116 /************************************************************************/
    00117 /*                               DEFINES
    00118  *
    00119  */
    00120
    00121 #define EPSILON 1.75e-7   /* approx 1.0e-5 degrees (~1 meter) in radians */
    00122
    00123 const int LETTER_A = 0;   /* ARRAY INDEX FOR LETTER A               */
    00124 const int LETTER_B = 1;   /* ARRAY INDEX FOR LETTER B               */
    00125 const int LETTER_C = 2;   /* ARRAY INDEX FOR LETTER C               */
    00126 const int LETTER_D = 3;   /* ARRAY INDEX FOR LETTER D               */
    00127 const int LETTER_E = 4;   /* ARRAY INDEX FOR LETTER E               */
    00128 const int LETTER_F = 5;   /* ARRAY INDEX FOR LETTER F               */
    00129 const int LETTER_G = 6;   /* ARRAY INDEX FOR LETTER G               */
    00130 const int LETTER_H = 7;   /* ARRAY INDEX FOR LETTER H               */
    00131 const int LETTER_I = 8;   /* ARRAY INDEX FOR LETTER I               */
    00132 const int LETTER_J = 9;   /* ARRAY INDEX FOR LETTER J               */
    00133 const int LETTER_K = 10;   /* ARRAY INDEX FOR LETTER K               */
    00134 const int LETTER_L = 11;   /* ARRAY INDEX FOR LETTER L               */
    00135 const int LETTER_M = 12;   /* ARRAY INDEX FOR LETTER M               */
    00136 const int LETTER_N = 13;   /* ARRAY INDEX FOR LETTER N               */
    00137 const int LETTER_O = 14;   /* ARRAY INDEX FOR LETTER O               */
    00138 const int LETTER_P = 15;   /* ARRAY INDEX FOR LETTER P               */
    00139 const int LETTER_Q = 16;   /* ARRAY INDEX FOR LETTER Q               */
    00140 const int LETTER_R = 17;   /* ARRAY INDEX FOR LETTER R               */
    00141 const int LETTER_S = 18;   /* ARRAY INDEX FOR LETTER S               */
    00142 const int LETTER_T = 19;   /* ARRAY INDEX FOR LETTER T               */
    00143 const int LETTER_U = 20;   /* ARRAY INDEX FOR LETTER U               */
    00144 const int LETTER_V = 21;   /* ARRAY INDEX FOR LETTER V               */
    00145 const int LETTER_W = 22;   /* ARRAY INDEX FOR LETTER W               */
    00146 const int LETTER_X = 23;   /* ARRAY INDEX FOR LETTER X               */
    00147 const int LETTER_Y = 24;   /* ARRAY INDEX FOR LETTER Y               */
    00148 const int LETTER_Z = 25;   /* ARRAY INDEX FOR LETTER Z               */
    00149 const double ONEHT = 100000.e0;      /* ONE HUNDRED THOUSAND                  */
    00150 const double TWOMIL = 2000000.e0;    /* TWO MILLION                           */
    00151 const int TRUE = 1;  /* CONSTANT VALUE FOR TRUE VALUE  */
    00152 const int FALSE = 0;  /* CONSTANT VALUE FOR FALSE VALUE */
    00153 const double PI = 3.14159265358979323e0;  /* PI                             */
    00154 const double PI_OVER_2 = (PI / 2.0e0);
    00155 const double PI_OVER_180 = (PI / 180.0e0);
    00156
    00157 const double MIN_EASTING = 100000.0;
    00158 const double MAX_EASTING = 900000.0;
    00159 const double MIN_NORTHING = 0.0;
    00160 const double MAX_NORTHING = 10000000.0;
    00161 const int MAX_PRECISION = 5;   /* Maximum precision of easting & northing */
    00162 const double MIN_MGRS_NON_POLAR_LAT = -80.0 * ( PI / 180.0 ); /* -80 degrees in radians    */
    00163 const double MAX_MGRS_NON_POLAR_LAT = 84.0 * ( PI / 180.0 );  /* 84 degrees in radians     */
    00164
    00165 const double MIN_EAST_NORTH = 0.0;
    00166 const double MAX_EAST_NORTH = 3999999.0;
    00167
    00168 const double _6 = (6.0 * (PI / 180.0));
    00169 const double _8 = (8.0 * (PI / 180.0));
    00170 const double _72 = (72.0 * (PI / 180.0));
    00171 const double _80 = (80.0 * (PI / 180.0));
    00172 const double _80_5 = (80.5 * (PI / 180.0));
    00173 const double _84_5 = (84.5 * (PI / 180.0));
    00174
    00175 #define _500000  500000.0
    00176
    00177 /*
    00178  *    CLARKE_1866 : Ellipsoid code for CLARKE_1866
    00179  *    CLARKE_1880 : Ellipsoid code for CLARKE_1880
    00180  *    BESSEL_1841 : Ellipsoid code for BESSEL_1841
    00181  *    BESSEL_1841_NAMIBIA : Ellipsoid code for BESSEL 1841 (NAMIBIA)
    00182  */
    00183 const char* CLARKE_1866 = "CC";
    00184 const char* CLARKE_1880 = "CD";
    00185 const char* BESSEL_1841 = "BR";
    00186 const char* BESSEL_1841_NAMIBIA = "BN";
    00187
    00188 struct Latitude_Band
    00189 {
    00190   long letter;            /* letter representing latitude band  */
    00191   double min_northing;    /* minimum northing for latitude band */
    00192   double north;           /* upper latitude for latitude band   */
    00193   double south;           /* lower latitude for latitude band   */
    00194   double northing_offset; /* latitude band northing offset      */
    00195 };
    00196
    00197 const Latitude_Band Latitude_Band_Table[20] =
    00198   {{LETTER_C, 1100000.0, -72.0, -80.5, 0.0},
    00199   {LETTER_D, 2000000.0, -64.0, -72.0, 2000000.0},
    00200   {LETTER_E, 2800000.0, -56.0, -64.0, 2000000.0},
    00201   {LETTER_F, 3700000.0, -48.0, -56.0, 2000000.0},
    00202   {LETTER_G, 4600000.0, -40.0, -48.0, 4000000.0},
    00203   {LETTER_H, 5500000.0, -32.0, -40.0, 4000000.0},
    00204   {LETTER_J, 6400000.0, -24.0, -32.0, 6000000.0},
    00205   {LETTER_K, 7300000.0, -16.0, -24.0, 6000000.0},
    00206   {LETTER_L, 8200000.0, -8.0, -16.0, 8000000.0},
    00207   {LETTER_M, 9100000.0, 0.0, -8.0, 8000000.0},
    00208   {LETTER_N, 0.0, 8.0, 0.0, 0.0},
    00209   {LETTER_P, 800000.0, 16.0, 8.0, 0.0},
    00210   {LETTER_Q, 1700000.0, 24.0, 16.0, 0.0},
    00211   {LETTER_R, 2600000.0, 32.0, 24.0, 2000000.0},
    00212   {LETTER_S, 3500000.0, 40.0, 32.0, 2000000.0},
    00213   {LETTER_T, 4400000.0, 48.0, 40.0, 4000000.0},
    00214   {LETTER_U, 5300000.0, 56.0, 48.0, 4000000.0},
    00215   {LETTER_V, 6200000.0, 64.0, 56.0, 6000000.0},
    00216   {LETTER_W, 7000000.0, 72.0, 64.0, 6000000.0},
    00217   {LETTER_X, 7900000.0, 84.5, 72.0, 6000000.0}};
    00218
    00219
    00220 struct UPS_Constant
    00221 {
    00222   long letter;            /* letter representing latitude band      */
    00223   long ltr2_low_value;    /* 2nd letter range - low number         */
    00224   long ltr2_high_value;   /* 2nd letter range - high number          */
    00225   long ltr3_high_value;   /* 3rd letter range - high number (UPS)   */
    00226   double false_easting;   /* False easting based on 2nd letter      */
    00227   double false_northing;  /* False northing based on 3rd letter     */
    00228 };
    00229
    00230 const UPS_Constant UPS_Constant_Table[4] =
    00231   {{LETTER_A, LETTER_J, LETTER_Z, LETTER_Z, 800000.0, 800000.0},
    00232   {LETTER_B, LETTER_A, LETTER_R, LETTER_Z, 2000000.0, 800000.0},
    00233   {LETTER_Y, LETTER_J, LETTER_Z, LETTER_P, 800000.0, 1300000.0},
    00234   {LETTER_Z, LETTER_A, LETTER_J, LETTER_P, 2000000.0, 1300000.0}};
    00235
    00236
    00237 /************************************************************************/
    00238 /*                              LOCAL FUNCTIONS
    00239  *
    00240  */
    00241
    00242 long roundMGRS( double value )
    00243 {
    00244 /*
    00245  * The function roundMGRS rounds the input value to the
    00246  * nearest integer, using the standard engineering rule.
    00247  * The rounded integer value is then returned.
    00248  *
    00249  *   value           : Value to be rounded  (input)
    00250  */
    00251
    00252   double ivalue;
    00253   long ival;
    00254   double fraction = modf (value, &ivalue);
    00255   ival = (long)(ivalue);
    00256   if ((fraction > 0.5) || ((fraction == 0.5) && (ival%2 == 1)))
    00257     ival++;
    00258   return (ival);
    00259 }
    00260
    00261
    00262 void makeMGRSString( char* MGRSString, long zone, int letters[MGRS_LETTERS], double easting, double northing, long precision )
    00263 {
    00264 /*
    00265  * The function makeMGRSString constructs an MGRS string
    00266  * from its component parts.
    00267  *
    00268  *   MGRSString     : MGRS coordinate string          (output)
    00269  *   zone           : UTM Zone                        (input)
    00270  *   letters        : MGRS coordinate string letters  (input)
    00271  *   easting        : Easting value                   (input)
    00272  *   northing       : Northing value                  (input)
    00273  *   precision      : Precision level of MGRS string  (input)
    00274  */
    00275
    00276   long i;
    00277   long j;
    00278   double divisor;
    00279   long east;
    00280   long north;
    00281   char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    00282
    00283   i = 0;
    00284   if (zone)
    00285     i = sprintf (MGRSString+i,"%2.2ld",zone);
    00286   else
    00287     strncpy(MGRSString, "  ", 2);  // 2 spaces
    00288
    00289   for (j=0;j<3;j++)
    00290     MGRSString[i++] = alphabet[letters[j]];
    00291   divisor = pow (10.0, (5.0 - precision));
    00292   easting = fmod (easting, 100000.0);
    00293   if (easting >= 99999.5)
    00294     easting = 99999.0;
    00295   east = (long)(easting/divisor);
    00296   i += sprintf (MGRSString+i, "%*.*ld", precision, precision, east);
    00297   northing = fmod (northing, 100000.0);
    00298   if (northing >= 99999.5)
    00299     northing = 99999.0;
    00300   north = (long)(northing/divisor);
    00301   i += sprintf (MGRSString+i, "%*.*ld", precision, precision, north);
    00302 }
    00303
    00304
    00305 void breakMGRSString( char* MGRSString, long* zone, long letters[MGRS_LETTERS], double* easting, double* northing, long* precision )
    00306 {
    00307 /*
    00308  * The function breakMGRSString breaks down an MGRS
    00309  * coordinate string into its component parts.
    00310  *
    00311  *   MGRS           : MGRS coordinate string          (input)
    00312  *   zone           : UTM Zone                        (output)
    00313  *   letters        : MGRS coordinate string letters  (output)
    00314  *   easting        : Easting value                   (output)
    00315  *   northing       : Northing value                  (output)
    00316  *   precision      : Precision level of MGRS string  (output)
    00317  */
    00318
    00319   long num_digits;
    00320   long num_letters;
    00321   long i = 0;
    00322   long j = 0;
    00323
    00324   while (MGRSString[i] == ' ')
    00325     i++;  /* skip any leading blanks */
    00326   j = i;
    00327   while (isdigit(MGRSString[i]))
    00328     i++;
    00329   num_digits = i - j;
    00330   if (num_digits <= 2)
    00331     if (num_digits > 0)
    00332     {
    00333       char zone_string[3];
    00334       /* get zone */
    00335       strncpy (zone_string, MGRSString+j, 2);
    00336       zone_string[2] = 0;
    00337       sscanf (zone_string, "%ld", zone);
    00338       if ((*zone < 1) || (*zone > 60))
    00339         throw CoordinateConversionException( ErrorMessages::mgrsString );
    00340     }
    00341     else
    00342       *zone = 0;
    00343   else
    00344     throw CoordinateConversionException( ErrorMessages::mgrsString );
    00345   j = i;
    00346
    00347   while (isalpha(MGRSString[i]))
    00348     i++;
    00349   num_letters = i - j;
    00350   if (num_letters == 3)
    00351   {
    00352     /* get letters */
    00353     letters[0] = (toupper(MGRSString[j]) - (long)'A');
    00354     if ((letters[0] == LETTER_I) || (letters[0] == LETTER_O))
    00355       throw CoordinateConversionException( ErrorMessages::mgrsString );
    00356     letters[1] = (toupper(MGRSString[j+1]) - (long)'A');
    00357     if ((letters[1] == LETTER_I) || (letters[1] == LETTER_O))
    00358       throw CoordinateConversionException( ErrorMessages::mgrsString );
    00359     letters[2] = (toupper(MGRSString[j+2]) - (long)'A');
    00360     if ((letters[2] == LETTER_I) || (letters[2] == LETTER_O))
    00361       throw CoordinateConversionException( ErrorMessages::mgrsString );
    00362   }
    00363   else
    00364     throw CoordinateConversionException( ErrorMessages::mgrsString );
    00365   j = i;
    00366   while (isdigit(MGRSString[i]))
    00367     i++;
    00368   num_digits = i - j;
    00369   if ((num_digits <= 10) && (num_digits%2 == 0))
    00370   {
    00371     long n;
    00372     char east_string[6];
    00373     char north_string[6];
    00374     long east;
    00375     long north;
    00376     double multiplier;
    00377     /* get easting & northing */
    00378     n = num_digits/2;
    00379     *precision = n;
    00380     if (n > 0)
    00381     {
    00382       strncpy (east_string, MGRSString+j, n);
    00383       east_string[n] = 0;
    00384       sscanf (east_string, "%ld", &east);
    00385       strncpy (north_string, MGRSString+j+n, n);
    00386       north_string[n] = 0;
    00387       sscanf (north_string, "%ld", &north);
    00388       multiplier = pow (10.0, 5.0 - n);
    00389       *easting = east * multiplier;
    00390       *northing = north * multiplier;
    00391     }
    00392     else
    00393     {
    00394       *easting = 0.0;
    00395       *northing = 0.0;
    00396     }
    00397   }
    00398   else
    00399     throw CoordinateConversionException( ErrorMessages::mgrsString );
    00400 }
    00401
    00402
    00403 /************************************************************************/
    00404 /*                              FUNCTIONS
    00405  *
    00406  */
    00407
    00408 MGRS::MGRS( double ellipsoidSemiMajorAxis, double ellipsoidFlattening, char* ellipsoidCode ) :
    00409   CoordinateSystem(),
    00410   ups( 0 ),
    00411   utm( 0 )
    00412 {
    00413 /*
    00414  * The constructor receives the ellipsoid parameters and sets
    00415  * the corresponding state variables. If any errors occur, an
    00416  * exception is thrown with a description of the error.
    00417  *
    00418  *   ellipsoidSemiMajorAxis     : Semi-major axis of ellipsoid in meters  (input)
    00419  *   ellipsoidFlattening        : Flattening of ellipsoid                 (input)
    00420  *   ellipsoid_Code             : 2-letter code for ellipsoid             (input)
    00421  */
    00422
    00423   double inv_f = 1 / ellipsoidFlattening;
    00424   char errorStatus[500] = "";
    00425
    00426   if (ellipsoidSemiMajorAxis <= 0.0)
    00427   { /* Semi-major axis must be greater than zero */
    00428     strcat( errorStatus, ErrorMessages::semiMajorAxis );
    00429   }
    00430   if ((inv_f < 250) || (inv_f > 350))
    00431   { /* Inverse flattening must be between 250 and 350 */
    00432     strcat( errorStatus, ErrorMessages::ellipsoidFlattening );
    00433   }
    00434
    00435   if( strlen( errorStatus ) > 0)
    00436     throw CoordinateConversionException( errorStatus );
    00437
    00438   semiMajorAxis = ellipsoidSemiMajorAxis;
    00439   flattening = ellipsoidFlattening;
    00440
    00441   strncpy (MGRSEllipsoidCode, ellipsoidCode, 2);
    00442   MGRSEllipsoidCode[2] = '\0';
    00443
    00444   ups = new UPS( semiMajorAxis, flattening );
    00445
    00446   utm = new UTM( semiMajorAxis, flattening, 0 );
    00447 }
    00448
    00449
    00450 MGRS::MGRS( const MGRS &m )
    00451 {
    00452   ups = new UPS( *( m.ups ) );
    00453   utm = new UTM( *( m.utm ) );
    00454
    00455   semiMajorAxis = m.semiMajorAxis;
    00456   flattening = m.flattening;
    00457   strcpy( MGRSEllipsoidCode, m.MGRSEllipsoidCode );
    00458 }
    00459
    00460
    00461 MGRS::~MGRS()
    00462 {
    00463   delete ups;
    00464   ups = 0;
    00465
    00466   delete utm;
    00467   utm = 0;
    00468 }
    00469
    00470
    00471 MGRS& MGRS::operator=( const MGRS &m )
    00472 {
    00473   if( this != &m )
    00474   {
    00475     ups->operator=( *m.ups );
    00476     utm->operator=( *m.utm );
    00477
    00478     semiMajorAxis = m.semiMajorAxis;
    00479     flattening = m.flattening;
    00480     strcpy( MGRSEllipsoidCode, m.MGRSEllipsoidCode );
    00481   }
    00482
    00483   return *this;
    00484 }
    00485
    00486
    00487 EllipsoidParameters* MGRS::getParameters() const
    00488 {
    00489 /*
    00490  * The function getParameters returns the current ellipsoid
    00491  * parameters.
    00492  *
    00493  *  ellipsoidSemiMajorAxis     : Semi-major axis of ellipsoid, in meters (output)
    00494  *  ellipsoidFlattening        : Flattening of ellipsoid                 (output)
    00495  *  ellipsoidCode              : 2-letter code for ellipsoid             (output)
    00496  */
    00497
    00498   return new EllipsoidParameters( semiMajorAxis, flattening, (char*)MGRSEllipsoidCode );
    00499 }
    00500
    00501
    00502 MSP::CCS::MGRSorUSNGCoordinates* MGRS::convertFromGeodetic( MSP::CCS::GeodeticCoordinates* geodeticCoordinates, long precision )
    00503 {
    00504 /*
    00505  * The function convertFromGeodetic converts Geodetic (latitude and
    00506  * longitude) coordinates to an MGRS coordinate string, according to the
    00507  * current ellipsoid parameters.  If any errors occur, an exception
    00508  * is thrown with a description of the error.
    00509  *
    00510  *    latitude      : Latitude in radians              (input)
    00511  *    longitude     : Longitude in radians             (input)
    00512  *    precision     : Precision level of MGRS string   (input)
    00513  *    MGRSString    : MGRS coordinate string           (output)
    00514  *
    00515  */
    00516
    00517   MGRSorUSNGCoordinates* mgrsorUSNGCoordinates = 0;
    00518   char errorStatus[50] = "";
    00519
    00520   double latitude = geodeticCoordinates->latitude();
    00521   double longitude = geodeticCoordinates->longitude();
    00522
    00523   if ((latitude < -PI_OVER_2) || (latitude > PI_OVER_2))
    00524   { /* latitude out of range */
    00525     strcat( errorStatus, ErrorMessages::latitude );
    00526   }
    00527   if ((longitude < -PI) || (longitude > (2*PI)))
    00528   { /* longitude out of range */
    00529     strcat( errorStatus, ErrorMessages::longitude );
    00530   }
    00531   if ((precision < 0) || (precision > MAX_PRECISION))
    00532     strcat( errorStatus, ErrorMessages::precision );
    00533
    00534   if( strlen( errorStatus ) > 0)
    00535     throw CoordinateConversionException( errorStatus );
    00536
    00537   // If the latitude is within the valid mgrs non polar range [-80, 84),
    00538   // convert to mgrs using the utm path, otherwise convert to mgrs using the ups path
    00539   if ((latitude >= MIN_MGRS_NON_POLAR_LAT) && (latitude < MAX_MGRS_NON_POLAR_LAT))
    00540   {
    00541     UTMCoordinates* utmCoordinates = utm->convertFromGeodetic( geodeticCoordinates );
    00542     mgrsorUSNGCoordinates = fromUTM( utmCoordinates, longitude, latitude, precision );
    00543     delete utmCoordinates;
    00544     utmCoordinates = 0;
    00545   }
    00546   else
    00547   {
    00548     UPSCoordinates* upsCoordinates = ups->convertFromGeodetic( geodeticCoordinates );
    00549     mgrsorUSNGCoordinates = fromUPS( upsCoordinates, precision );
    00550     delete upsCoordinates;
    00551     upsCoordinates = 0;
    00552   }
    00553
    00554   return mgrsorUSNGCoordinates;
    00555 }
    00556
    00557
    00558 MSP::CCS::GeodeticCoordinates* MGRS::convertToGeodetic( MSP::CCS::MGRSorUSNGCoordinates* mgrsorUSNGCoordinates )
    00559 {
    00560 /*
    00561  * The function convertToGeodetic converts an MGRS coordinate string
    00562  * to Geodetic (latitude and longitude) coordinates
    00563  * according to the current ellipsoid parameters.  If any errors occur,
    00564  * an exception is thrown with a description of the error.
    00565  *
    00566  *    MGRS       : MGRS coordinate string           (input)
    00567  *    latitude   : Latitude in radians              (output)
    00568  *    longitude  : Longitude in radians             (output)
    00569  *
    00570  */
    00571
    00572   long zone;
    00573   long letters[MGRS_LETTERS];
    00574   double mgrs_easting;
    00575   double mgrs_northing;
    00576   long precision;
    00577   GeodeticCoordinates* geodeticCoordinates = 0;
    00578
    00579   breakMGRSString( mgrsorUSNGCoordinates->MGRSString(), &zone, letters, &mgrs_easting, &mgrs_northing, &precision );
    00580
    00581   if( zone )
    00582   {
    00583     UTMCoordinates* utmCoordinates = toUTM( zone, letters, mgrs_easting, mgrs_northing, precision );
    00584     geodeticCoordinates = utm->convertToGeodetic( utmCoordinates );
    00585     delete utmCoordinates;
    00586     utmCoordinates = 0;
    00587   }
    00588   else
    00589   {
    00590     UPSCoordinates* upsCoordinates = toUPS( letters, mgrs_easting, mgrs_northing );
    00591     geodeticCoordinates = ups->convertToGeodetic( upsCoordinates );
    00592     delete upsCoordinates;
    00593     upsCoordinates = 0;
    00594   }
    00595
    00596   return geodeticCoordinates;
    00597 }
    00598
    00599
    00600 MSP::CCS::MGRSorUSNGCoordinates* MGRS::convertFromUTM( UTMCoordinates* utmCoordinates, long precision )
    00601 {
    00602 /*
    00603  * The function convertFromUTM converts UTM (zone, easting, and
    00604  * northing) coordinates to an MGRS coordinate string, according to the
    00605  * current ellipsoid parameters.  If any errors occur, an exception is
    00606  * thrown with a description of the error.
    00607  *
    00608  *    zone       : UTM zone                         (input)
    00609  *    hemisphere : North or South hemisphere        (input)
    00610  *    easting    : Easting (X) in meters            (input)
    00611  *    northing   : Northing (Y) in meters           (input)
    00612  *    precision  : Precision level of MGRS string   (input)
    00613  *    MGRSString : MGRS coordinate string           (output)
    00614  */
    00615
    00616   char errorStatus[50] = "";
    00617
    00618   long zone = utmCoordinates->zone();
    00619   char hemisphere = utmCoordinates->hemisphere();
    00620   double easting = utmCoordinates->easting();
    00621   double northing = utmCoordinates->northing();
    00622
    00623   if ((zone < 1) || (zone > 60))
    00624     strcat( errorStatus, ErrorMessages::zone );
    00625   if ((hemisphere != 'S') && (hemisphere != 'N'))
    00626     strcat( errorStatus, ErrorMessages::hemisphere );
    00627   if ((easting < MIN_EASTING) || (easting > MAX_EASTING))
    00628     strcat( errorStatus, ErrorMessages::easting );
    00629   if ((northing < MIN_NORTHING) || (northing > MAX_NORTHING))
    00630     strcat( errorStatus, ErrorMessages::northing );
    00631   if ((precision < 0) || (precision > MAX_PRECISION))
    00632     strcat( errorStatus, ErrorMessages::precision );
    00633
    00634   if( strlen( errorStatus ) > 0)
    00635     throw CoordinateConversionException( errorStatus );
    00636
    00637   GeodeticCoordinates* geodeticCoordinates = utm->convertToGeodetic( utmCoordinates );
    00638
    00639   // If the latitude is within the valid mgrs non polar range [-80, 84),
    00640   // convert to mgrs using the utm path, otherwise convert to mgrs using the ups path
    00641   MGRSorUSNGCoordinates* mgrsorUSNGCoordinates = 0;
    00642   double latitude = geodeticCoordinates->latitude();
    00643
    00644   if ((latitude >= (MIN_MGRS_NON_POLAR_LAT - EPSILON)) && (latitude < (MAX_MGRS_NON_POLAR_LAT + EPSILON)))
    00645     mgrsorUSNGCoordinates = fromUTM( utmCoordinates, geodeticCoordinates->longitude(), latitude, precision );
    00646   else
    00647   {
    00648     UPSCoordinates* upsCoordinates = ups->convertFromGeodetic( geodeticCoordinates );
    00649     mgrsorUSNGCoordinates = fromUPS( upsCoordinates, precision );
    00650     delete upsCoordinates;
    00651     upsCoordinates = 0;
    00652   }
    00653
    00654   delete geodeticCoordinates;
    00655   geodeticCoordinates = 0;
    00656
    00657   return mgrsorUSNGCoordinates;
    00658 }
    00659
    00660
    00661 MSP::CCS::UTMCoordinates* MGRS::convertToUTM( MSP::CCS::MGRSorUSNGCoordinates* mgrsorUSNGCoordinates )
    00662 {
    00663 /*
    00664  * The function convertToUTM converts an MGRS coordinate string
    00665  * to UTM projection (zone, hemisphere, easting and northing) coordinates
    00666  * according to the current ellipsoid parameters.  If any errors occur,
    00667  * an exception is thrown with a description of the error.
    00668  *
    00669  *    MGRSString : MGRS coordinate string           (input)
    00670  *    zone       : UTM zone                         (output)
    00671  *    hemisphere : North or South hemisphere        (output)
    00672  *    easting    : Easting (X) in meters            (output)
    00673  *    northing   : Northing (Y) in meters           (output)
    00674  */
    00675
    00676   long zone;
    00677   long letters[MGRS_LETTERS];
    00678   double mgrs_easting, mgrs_northing;
    00679   long precision;
    00680   UTMCoordinates* utmCoordinates = 0;
    00681   GeodeticCoordinates* geodeticCoordinates = 0;
    00682   char errorStatus[50] = "";
    00683
    00684   breakMGRSString( mgrsorUSNGCoordinates->MGRSString(), &zone, letters, &mgrs_easting, &mgrs_northing, &precision );
    00685   if (zone)
    00686   {
    00687     utmCoordinates = toUTM( zone, letters, mgrs_easting, mgrs_northing, precision );
    00688     // Convert to geodetic to make sure the coordinates are in the valid utm range
    00689     geodeticCoordinates = utm->convertToGeodetic( utmCoordinates );
    00690   }
    00691   else
    00692   {
    00693     UPSCoordinates* upsCoordinates = toUPS( letters, mgrs_easting, mgrs_northing );
    00694     geodeticCoordinates = ups->convertToGeodetic( upsCoordinates );
    00695     delete upsCoordinates;
    00696     upsCoordinates = 0;
    00697     utmCoordinates = utm->convertFromGeodetic( geodeticCoordinates );
    00698   }
    00699
    00700   delete geodeticCoordinates;
    00701   geodeticCoordinates = 0;
    00702
    00703   return utmCoordinates;
    00704 }
    00705
    00706
    00707 MSP::CCS::MGRSorUSNGCoordinates* MGRS::convertFromUPS( MSP::CCS::UPSCoordinates* upsCoordinates, long precision )
    00708 {
    00709 /*
    00710  * The function convertFromUPS converts UPS (hemisphere, easting,
    00711  * and northing) coordinates to an MGRS coordinate string according to
    00712  * the current ellipsoid parameters.  If any errors occur, an
    00713  * exception is thrown with a description of the error.
    00714  *
    00715  *    hemisphere    : Hemisphere either 'N' or 'S'     (input)
    00716  *    easting       : Easting/X in meters              (input)
    00717  *    northing      : Northing/Y in meters             (input)
    00718  *    precision     : Precision level of MGRS string   (input)
    00719  *    MGRSString    : MGRS coordinate string           (output)
    00720  */
    00721
    00722   int index = 0;
    00723   char errorStatus[50] = "";
    00724
    00725   char hemisphere = upsCoordinates->hemisphere();
    00726   double easting = upsCoordinates->easting();
    00727   double northing = upsCoordinates->northing();
    00728
    00729   if ((hemisphere != 'N') && (hemisphere != 'S'))
    00730     strcat( errorStatus, ErrorMessages::hemisphere );
    00731   if ((easting < MIN_EAST_NORTH) || (easting > MAX_EAST_NORTH))
    00732     strcat( errorStatus, ErrorMessages::easting );
    00733   if ((northing < MIN_EAST_NORTH) || (northing > MAX_EAST_NORTH))
    00734     strcat( errorStatus, ErrorMessages::northing );
    00735   if ((precision < 0) || (precision > MAX_PRECISION))
    00736     strcat( errorStatus, ErrorMessages::precision );
    00737
    00738   if( strlen( errorStatus ) > 0)
    00739     throw CoordinateConversionException( errorStatus );
    00740
    00741   GeodeticCoordinates* geodeticCoordinates = ups->convertToGeodetic( upsCoordinates );
    00742
    00743   // If the latitude is within the valid mgrs polar range [-90, -80) or [84, 90],
    00744   // convert to mgrs using the ups path, otherwise convert to mgrs using the utm path
    00745   MGRSorUSNGCoordinates* mgrsorUSNGCoordinates = 0;
    00746   double latitude = geodeticCoordinates->latitude();
    00747
    00748   if ((latitude < (MIN_MGRS_NON_POLAR_LAT + EPSILON)) || (latitude >= (MAX_MGRS_NON_POLAR_LAT - EPSILON)))
    00749     mgrsorUSNGCoordinates = fromUPS( upsCoordinates, precision );
    00750   else
    00751   {
    00752     UTMCoordinates* utmCoordinates = utm->convertFromGeodetic( geodeticCoordinates );
    00753
    00754     double longitude = geodeticCoordinates->longitude();
    00755     mgrsorUSNGCoordinates = fromUTM( utmCoordinates, longitude, latitude, precision );
    00756     delete utmCoordinates;
    00757     utmCoordinates = 0;
    00758   }
    00759
    00760   delete geodeticCoordinates;
    00761   geodeticCoordinates = 0;
    00762
    00763   return mgrsorUSNGCoordinates;
    00764 }
    00765
    00766
    00767 MSP::CCS::UPSCoordinates* MGRS::convertToUPS( MSP::CCS::MGRSorUSNGCoordinates* mgrsorUSNGCoordinates )
    00768 {
    00769 /*
    00770  * The function convertToUPS converts an MGRS coordinate string
    00771  * to UPS (hemisphere, easting, and northing) coordinates, according
    00772  * to the current ellipsoid parameters. If any errors occur, an
    00773  * exception is thrown with a description of the error.
    00774  *
    00775  *    MGRSString    : MGRS coordinate string           (input)
    00776  *    hemisphere    : Hemisphere either 'N' or 'S'     (output)
    00777  *    easting       : Easting/X in meters              (output)
    00778  *    northing      : Northing/Y in meters             (output)
    00779  */
    00780
    00781   long zone;
    00782   long letters[MGRS_LETTERS];
    00783   long precision;
    00784   double mgrs_easting;
    00785   double mgrs_northing;
    00786   int index = 0;
    00787   UPSCoordinates* upsCoordinates = 0;
    00788   GeodeticCoordinates* geodeticCoordinates = 0;
    00789
    00790   breakMGRSString( mgrsorUSNGCoordinates->MGRSString(), &zone, letters, &mgrs_easting, &mgrs_northing, &precision );
    00791   if( !zone )
    00792   {
    00793     upsCoordinates = toUPS( letters, mgrs_easting, mgrs_northing );
    00794     geodeticCoordinates = ups->convertToGeodetic( upsCoordinates );
    00795   }
    00796   else
    00797   {
    00798     UTMCoordinates* utmCoordinates = toUTM( zone, letters, mgrs_easting, mgrs_northing, precision );
    00799     geodeticCoordinates = utm->convertToGeodetic( utmCoordinates );
    00800     delete utmCoordinates;
    00801     utmCoordinates = 0;
    00802     upsCoordinates = ups->convertFromGeodetic( geodeticCoordinates );
    00803   }
    00804
    00805   delete geodeticCoordinates;
    00806   geodeticCoordinates = 0;
    00807
    00808   return upsCoordinates;
    00809 }
    00810
    00811
    00812 MSP::CCS::MGRSorUSNGCoordinates* MGRS::fromUTM( MSP::CCS::UTMCoordinates* utmCoordinates, double longitude, double latitude, long precision )
    00813 {
    00814 /*
    00815  * The function fromUTM calculates an MGRS coordinate string
    00816  * based on the zone, latitude, easting and northing.
    00817  *
    00818  *    zone       : Zone number             (input)
    00819  *    hemisphere : Hemisphere              (input)
    00820  *    longitude  : Longitude in radians    (input)
    00821  *    latitude   : Latitude in radians     (input)
    00822  *    easting    : Easting                 (input)
    00823  *    northing   : Northing                (input)
    00824  *    precision  : Precision               (input)
    00825  *    MGRSString : MGRS coordinate string  (output)
    00826  */
    00827
    00828   double pattern_offset;      /* Pattern offset for 3rd letter               */
    00829   double grid_northing;       /* Northing used to derive 3rd letter of MGRS  */
    00830   long ltr2_low_value;        /* 2nd letter range - low number               */
    00831   long ltr2_high_value;       /* 2nd letter range - high number              */
    00832   int letters[MGRS_LETTERS];  /* Number location of 3 letters in alphabet    */
    00833   char MGRSString[21];
    00834   long override = 0;
    00835   long natural_zone;
    00836
    00837   long zone = utmCoordinates->zone();
    00838   char hemisphere = utmCoordinates->hemisphere();
    00839   double easting = utmCoordinates->easting();
    00840   double northing = utmCoordinates->northing();
    00841
    00842   getLatitudeLetter( latitude, &letters[0] );
    00843
    00844   easting = roundMGRS(easting);
    00845
    00846   // Check if the point is within it's natural zone
    00847   // If it is not, put it there
    00848   if (longitude < PI)
    00849     natural_zone = (long)(31 + ((longitude) / _6));
    00850   else
    00851     natural_zone = (long)(((longitude) / _6) - 29);
    00852
    00853   if (natural_zone > 60)
    00854       natural_zone = 1;
    00855   if (zone != natural_zone)
    00856   { // reconvert to override zone
    00857     UTM utmOverride( semiMajorAxis, flattening, natural_zone );
    00858     GeodeticCoordinates geodeticCoordinates( CoordinateType::geodetic, longitude, latitude );
    00859     UTMCoordinates* utmCoordinatesOverride = utmOverride.convertFromGeodetic( &geodeticCoordinates );
    00860
    00861     zone = utmCoordinatesOverride->zone();
    00862     hemisphere = utmCoordinatesOverride->hemisphere();
    00863     easting = utmCoordinatesOverride->easting();
    00864     northing = utmCoordinatesOverride->northing();
    00865
    00866     delete utmCoordinatesOverride;
    00867     utmCoordinatesOverride = 0;
    00868   }
    00869
    00870   easting = roundMGRS(easting);
    00871
    00872   /* UTM special cases */
    00873   if (letters[0] == LETTER_V) // V latitude band
    00874   {
    00875     if ((zone == 31) && (easting >= _500000))
    00876       override = 32;  // extension of zone 32V
    00877   }
    00878   else if (letters[0] == LETTER_X)
    00879   {
    00880     if ((zone == 32) && (easting < _500000)) // extension of zone 31X
    00881       override = 31;
    00882     else if (((zone == 32) && (easting >= _500000)) || // western extension of zone 33X
    00883              ((zone == 34) && (easting < _500000))) // eastern extension of zone 33X
    00884       override = 33;
    00885     else if (((zone == 34) && (easting >= _500000)) || // western extension of zone 35X
    00886              ((zone == 36) && (easting < _500000))) // eastern extension of zone 35X
    00887       override = 35;
    00888     else if ((zone == 36) && (easting >= _500000)) // western extension of zone 37X
    00889       override = 37;
    00890   }
    00891
    00892   if (override)
    00893   { // reconvert to override zone
    00894     UTM utmOverride( semiMajorAxis, flattening, override );
    00895     GeodeticCoordinates geodeticCoordinates( CoordinateType::geodetic, longitude, latitude );
    00896     UTMCoordinates* utmCoordinatesOverride = utmOverride.convertFromGeodetic( &geodeticCoordinates );
    00897
    00898     zone = utmCoordinatesOverride->zone();
    00899     hemisphere = utmCoordinatesOverride->hemisphere();
    00900     easting = utmCoordinatesOverride->easting();
    00901     northing = utmCoordinatesOverride->northing();
    00902
    00903     delete utmCoordinatesOverride;
    00904     utmCoordinatesOverride = 0;
    00905   }
    00906
    00907   easting = roundMGRS(easting);
    00908   northing = roundMGRS(northing);
    00909   double divisor = pow (10.0, (5.0 - precision));
    00910   easting = ( long )( easting/divisor ) * divisor;
    00911   northing = ( long )( northing/divisor ) * divisor;
    00912
    00913   if( latitude <= 0.0 && northing == 1.0e7 )
    00914   {
    00915     latitude = 0.0;
    00916     northing = 0.0;
    00917   }
    00918
    00919   getGridValues( zone, &ltr2_low_value, &ltr2_high_value, &pattern_offset );
    00920
    00921   grid_northing = northing;
    00922
    00923   while (grid_northing >= TWOMIL)
    00924   {
    00925     grid_northing = grid_northing - TWOMIL;
    00926   }
    00927   grid_northing = grid_northing + pattern_offset;
    00928   if(grid_northing >= TWOMIL)
    00929     grid_northing = grid_northing - TWOMIL;
    00930
    00931   letters[2] = (long)(grid_northing / ONEHT);
    00932   if (letters[2] > LETTER_H)
    00933     letters[2] = letters[2] + 1;
    00934
    00935   if (letters[2] > LETTER_N)
    00936     letters[2] = letters[2] + 1;
    00937
    00938   letters[1] = ltr2_low_value + ((long)(easting / ONEHT) - 1);
    00939   if ((ltr2_low_value == LETTER_J) && (letters[1] > LETTER_N))
    00940     letters[1] = letters[1] + 1;
    00941
    00942   makeMGRSString( MGRSString, zone, letters, easting, northing, precision );
    00943
    00944   return new MGRSorUSNGCoordinates( CoordinateType::militaryGridReferenceSystem, MGRSString );
    00945 }
    00946
    00947
    00948 MSP::CCS::UTMCoordinates* MGRS::toUTM( long zone, long letters[MGRS_LETTERS], double easting, double northing, long precision )
    00949 {
    00950 /*
    00951  * The function toUTM converts an MGRS coordinate string
    00952  * to UTM projection (zone, hemisphere, easting and northing) coordinates
    00953  * according to the current ellipsoid parameters.  If any errors occur,
    00954  * an exception is thrown with a description of the error.
    00955  *
    00956  *    MGRSString : MGRS coordinate string           (input)
    00957  *    zone       : UTM zone                         (output)
    00958  *    hemisphere : North or South hemisphere        (output)
    00959  *    easting    : Easting (X) in meters            (output)
    00960  *    northing   : Northing (Y) in meters           (output)
    00961  */
    00962
    00963   char hemisphere;
    00964   double min_northing;
    00965   double northing_offset;
    00966   long ltr2_low_value;
    00967   long ltr2_high_value;
    00968   double pattern_offset;
    00969   double upper_lat_limit;     /* North latitude limits based on 1st letter  */
    00970   double lower_lat_limit;     /* South latitude limits based on 1st letter  */
    00971   double grid_easting;        /* Easting for 100,000 meter grid square      */
    00972   double grid_northing;       /* Northing for 100,000 meter grid square     */
    00973   double temp_grid_northing = 0.0;
    00974   double fabs_grid_northing = 0.0;
    00975   double latitude = 0.0;
    00976   double longitude = 0.0;
    00977   double divisor = 1.0;
    00978   UTMCoordinates* utmCoordinates = 0;
    00979   char errorStatus[50] = "";
    00980
    00981   if ((letters[0] == LETTER_X) && ((zone == 32) || (zone == 34) || (zone == 36)))
    00982     throw CoordinateConversionException( ErrorMessages::mgrsString );
    00983   else if ((letters[0] == LETTER_V) && (zone == 31) && (letters[1] > LETTER_D))
    00984     throw CoordinateConversionException( ErrorMessages::mgrsString );
    00985   else
    00986   {
    00987     if (letters[0] < LETTER_N)
    00988       hemisphere = 'S';
    00989     else
    00990       hemisphere = 'N';
    00991
    00992     getGridValues(zone, &ltr2_low_value, &ltr2_high_value, &pattern_offset);
    00993
    00994     /* Check that the second letter of the MGRS string is within
    00995      * the range of valid second letter values
    00996      * Also check that the third letter is valid */
    00997     if ((letters[1] < ltr2_low_value) || (letters[1] > ltr2_high_value) || (letters[2] > LETTER_V))
    00998       throw CoordinateConversionException( ErrorMessages::mgrsString );
    00999
    01000     grid_easting = (double)((letters[1]) - ltr2_low_value + 1) * ONEHT;
    01001     if ((ltr2_low_value == LETTER_J) && (letters[1] > LETTER_O))
    01002       grid_easting = grid_easting - ONEHT;
    01003
    01004     double row_letter_northing = (double)(letters[2]) * ONEHT;
    01005     if (letters[2] > LETTER_O)
    01006       row_letter_northing = row_letter_northing - ONEHT;
    01007
    01008     if (letters[2] > LETTER_I)
    01009       row_letter_northing = row_letter_northing - ONEHT;
    01010
    01011     if (row_letter_northing >= TWOMIL)
    01012       row_letter_northing = row_letter_northing - TWOMIL;
    01013
    01014     getLatitudeBandMinNorthing(letters[0], &min_northing, &northing_offset);
    01015
    01016     grid_northing = row_letter_northing - pattern_offset;
    01017     if(grid_northing < 0)
    01018       grid_northing += TWOMIL;
    01019
    01020     grid_northing += northing_offset;
    01021
    01022     if(grid_northing < min_northing)
    01023       grid_northing += TWOMIL;
    01024
    01025     easting = grid_easting + easting;
    01026     northing = grid_northing + northing;
    01027
    01028     utmCoordinates = new UTMCoordinates( CoordinateType::universalTransverseMercator, zone, hemisphere, easting, northing );
    01029
    01030     /* check that point is within Zone Letter bounds */
    01031     GeodeticCoordinates* geodeticCoordinates = utm->convertToGeodetic( utmCoordinates );
    01032
    01033     divisor = pow (10.0, (double)precision);
    01034     getLatitudeRange(letters[0], &upper_lat_limit, &lower_lat_limit);
    01035
    01036     double latitude = geodeticCoordinates->latitude();
    01037
    01038     delete geodeticCoordinates;
    01039     geodeticCoordinates = 0;
    01040
    01041     if (!(((lower_lat_limit - PI_OVER_180/divisor) <= latitude) && (latitude <= (upper_lat_limit + PI_OVER_180/divisor))))
    01042       utmCoordinates->setWarningMessage( MSP::CCS::WarningMessages::latitude );
    01043   }
    01044
    01045   return utmCoordinates;
    01046 }
    01047
    01048
    01049 MSP::CCS::MGRSorUSNGCoordinates* MGRS::fromUPS( MSP::CCS::UPSCoordinates* upsCoordinates, long precision )
    01050 {
    01051 /*
    01052  * The function fromUPS converts UPS (hemisphere, easting,
    01053  * and northing) coordinates to an MGRS coordinate string according to
    01054  * the current ellipsoid parameters.
    01055  *
    01056  *    hemisphere    : Hemisphere either 'N' or 'S'     (input)
    01057  *    easting       : Easting/X in meters              (input)
    01058  *    northing      : Northing/Y in meters             (input)
    01059  *    precision     : Precision level of MGRS string   (input)
    01060  *    MGRSString    : MGRS coordinate string           (output)
    01061  */
    01062
    01063   double false_easting;       /* False easting for 2nd letter                 */
    01064   double false_northing;      /* False northing for 3rd letter                */
    01065   double grid_easting;        /* Easting used to derive 2nd letter of MGRS    */
    01066   double grid_northing;       /* Northing used to derive 3rd letter of MGRS   */
    01067   long ltr2_low_value;        /* 2nd letter range - low number                */
    01068   int letters[MGRS_LETTERS];  /* Number location of 3 letters in alphabet     */
    01069   double divisor;
    01070   int index = 0;
    01071   char MGRSString[21];
    01072
    01073   char hemisphere = upsCoordinates->hemisphere();
    01074   double easting = upsCoordinates->easting();
    01075   double northing = upsCoordinates->northing();
    01076
    01077   easting = roundMGRS(easting);
    01078   northing = roundMGRS(northing);
    01079   divisor = pow (10.0, (5.0 - precision));
    01080   easting = (long)(easting/divisor) * divisor;
    01081   northing = (long)(northing/divisor) * divisor;
    01082
    01083   if (hemisphere == 'N')
    01084   {
    01085     if (easting >= TWOMIL)
    01086       letters[0] = LETTER_Z;
    01087     else
    01088       letters[0] = LETTER_Y;
    01089
    01090     index = letters[0] - 22;
    01091     ltr2_low_value = UPS_Constant_Table[index].ltr2_low_value;
    01092     false_easting = UPS_Constant_Table[index].false_easting;
    01093     false_northing = UPS_Constant_Table[index].false_northing;
    01094   }
    01095   else
    01096   {
    01097     if (easting >= TWOMIL)
    01098       letters[0] = LETTER_B;
    01099     else
    01100       letters[0] = LETTER_A;
    01101
    01102     ltr2_low_value = UPS_Constant_Table[letters[0]].ltr2_low_value;
    01103     false_easting = UPS_Constant_Table[letters[0]].false_easting;
    01104     false_northing = UPS_Constant_Table[letters[0]].false_northing;
    01105   }
    01106
    01107   grid_northing = northing;
    01108   grid_northing = grid_northing - false_northing;
    01109   letters[2] = (long)(grid_northing / ONEHT);
    01110
    01111   if (letters[2] > LETTER_H)
    01112     letters[2] = letters[2] + 1;
    01113
    01114   if (letters[2] > LETTER_N)
    01115     letters[2] = letters[2] + 1;
    01116
    01117   grid_easting = easting;
    01118   grid_easting = grid_easting - false_easting;
    01119   letters[1] = ltr2_low_value + ((long)(grid_easting / ONEHT));
    01120
    01121   if (easting < TWOMIL)
    01122   {
    01123     if (letters[1] > LETTER_L)
    01124       letters[1] = letters[1] + 3;
    01125
    01126     if (letters[1] > LETTER_U)
    01127       letters[1] = letters[1] + 2;
    01128   }
    01129   else
    01130   {
    01131     if (letters[1] > LETTER_C)
    01132       letters[1] = letters[1] + 2;
    01133
    01134     if (letters[1] > LETTER_H)
    01135       letters[1] = letters[1] + 1;
    01136
    01137     if (letters[1] > LETTER_L)
    01138       letters[1] = letters[1] + 3;
    01139   }
    01140
    01141   makeMGRSString( MGRSString, 0, letters, easting, northing, precision );
    01142
    01143   return new MGRSorUSNGCoordinates( CoordinateType::militaryGridReferenceSystem, MGRSString );
    01144 }
    01145
    01146
    01147 MSP::CCS::UPSCoordinates* MGRS::toUPS( long letters[MGRS_LETTERS], double easting, double northing )
    01148 {
    01149 /*
    01150  * The function toUPS converts an MGRS coordinate string
    01151  * to UPS (hemisphere, easting, and northing) coordinates, according
    01152  * to the current ellipsoid parameters. If any errors occur, an
    01153  * exception is thrown with a description of the error.
    01154  *
    01155  *    MGRSString    : MGRS coordinate string           (input)
    01156  *    hemisphere    : Hemisphere either 'N' or 'S'     (output)
    01157  *    easting       : Easting/X in meters              (output)
    01158  *    northing      : Northing/Y in meters             (output)
    01159  */
    01160
    01161   long ltr2_high_value;       /* 2nd letter range - high number             */
    01162   long ltr3_high_value;       /* 3rd letter range - high number (UPS)       */
    01163   long ltr2_low_value;        /* 2nd letter range - low number              */
    01164   double false_easting;       /* False easting for 2nd letter               */
    01165   double false_northing;      /* False northing for 3rd letter              */
    01166   double grid_easting;        /* easting for 100,000 meter grid square      */
    01167   double grid_northing;       /* northing for 100,000 meter grid square     */
    01168   char hemisphere;
    01169   int index = 0;
    01170
    01171   if ((letters[0] == LETTER_Y) || (letters[0] == LETTER_Z))
    01172   {
    01173     hemisphere = 'N';
    01174
    01175     index = letters[0] - 22;
    01176     ltr2_low_value = UPS_Constant_Table[index].ltr2_low_value;
    01177     ltr2_high_value = UPS_Constant_Table[index].ltr2_high_value;
    01178     ltr3_high_value = UPS_Constant_Table[index].ltr3_high_value;
    01179     false_easting = UPS_Constant_Table[index].false_easting;
    01180     false_northing = UPS_Constant_Table[index].false_northing;
    01181   }
    01182   else if ((letters[0] == LETTER_A) || (letters[0] == LETTER_B))
    01183   {
    01184     hemisphere = 'S';
    01185
    01186     ltr2_low_value = UPS_Constant_Table[letters[0]].ltr2_low_value;
    01187     ltr2_high_value = UPS_Constant_Table[letters[0]].ltr2_high_value;
    01188     ltr3_high_value = UPS_Constant_Table[letters[0]].ltr3_high_value;
    01189     false_easting = UPS_Constant_Table[letters[0]].false_easting;
    01190     false_northing = UPS_Constant_Table[letters[0]].false_northing;
    01191   }
    01192   else
    01193     throw CoordinateConversionException( ErrorMessages::mgrsString );
    01194
    01195   /* Check that the second letter of the MGRS string is within
    01196    * the range of valid second letter values
    01197    * Also check that the third letter is valid */
    01198   if ((letters[1] < ltr2_low_value) || (letters[1] > ltr2_high_value) ||
    01199       ((letters[1] == LETTER_D) || (letters[1] == LETTER_E) ||
    01200       (letters[1] == LETTER_M) || (letters[1] == LETTER_N) ||
    01201       (letters[1] == LETTER_V) || (letters[1] == LETTER_W)) ||
    01202       (letters[2] > ltr3_high_value))
    01203     throw CoordinateConversionException( ErrorMessages::mgrsString );
    01204
    01205   grid_northing = (double)letters[2] * ONEHT + false_northing;
    01206   if (letters[2] > LETTER_I)
    01207     grid_northing = grid_northing - ONEHT;
    01208
    01209   if (letters[2] > LETTER_O)
    01210     grid_northing = grid_northing - ONEHT;
    01211
    01212   grid_easting = (double)((letters[1]) - ltr2_low_value) * ONEHT + false_easting;
    01213   if (ltr2_low_value != LETTER_A)
    01214   {
    01215     if (letters[1] > LETTER_L)
    01216       grid_easting = grid_easting - 300000.0;
    01217
    01218     if (letters[1] > LETTER_U)
    01219       grid_easting = grid_easting - 200000.0;
    01220   }
    01221   else
    01222   {
    01223     if (letters[1] > LETTER_C)
    01224       grid_easting = grid_easting - 200000.0;
    01225
    01226     if (letters[1] > LETTER_I)
    01227       grid_easting = grid_easting - ONEHT;
    01228
    01229     if (letters[1] > LETTER_L)
    01230       grid_easting = grid_easting - 300000.0;
    01231   }
    01232
    01233   easting = grid_easting + easting;
    01234   northing = grid_northing + northing;
    01235
    01236   return new UPSCoordinates( CoordinateType::universalPolarStereographic, hemisphere, easting, northing );
    01237 }
    01238
    01239
    01240 void MGRS::getGridValues ( long zone, long* ltr2_low_value, long* ltr2_high_value, double *pattern_offset )
    01241 {
    01242 /*
    01243  * The function getGridValues sets the letter range used for
    01244  * the 2nd letter in the MGRS coordinate string, based on the set
    01245  * number of the utm zone. It also sets the pattern offset using a
    01246  * value of A for the second letter of the grid square, based on
    01247  * the grid pattern and set number of the utm zone.
    01248  *
    01249  *    zone            : Zone number             (input)
    01250  *    ltr2_low_value  : 2nd letter low number   (output)
    01251  *    ltr2_high_value : 2nd letter high number  (output)
    01252  *    pattern_offset  : Pattern offset          (output)
    01253  */
    01254
    01255   long set_number;    /* Set number (1-6) based on UTM zone number */
    01256   long aa_pattern;    /* Pattern based on ellipsoid code */
    01257
    01258   set_number = zone % 6;
    01259
    01260   if (!set_number)
    01261     set_number = 6;
    01262
    01263   if (!strcmp(MGRSEllipsoidCode, CLARKE_1866) || !strcmp(MGRSEllipsoidCode, CLARKE_1880) ||
    01264       !strcmp(MGRSEllipsoidCode, BESSEL_1841) || !strcmp(MGRSEllipsoidCode, BESSEL_1841_NAMIBIA))
    01265     aa_pattern = FALSE;
    01266   else
    01267     aa_pattern = TRUE;
    01268
    01269   if ((set_number == 1) || (set_number == 4))
    01270   {
    01271     *ltr2_low_value = LETTER_A;
    01272     *ltr2_high_value = LETTER_H;
    01273   }
    01274   else if ((set_number == 2) || (set_number == 5))
    01275   {
    01276     *ltr2_low_value = LETTER_J;
    01277     *ltr2_high_value = LETTER_R;
    01278   }
    01279   else if ((set_number == 3) || (set_number == 6))
    01280   {
    01281     *ltr2_low_value = LETTER_S;
    01282     *ltr2_high_value = LETTER_Z;
    01283   }
    01284
    01285   /* False northing at A for second letter of grid square */
    01286   if (aa_pattern)
    01287   {
    01288     if ((set_number % 2) ==  0)
    01289       *pattern_offset = 500000.0;
    01290     else
    01291       *pattern_offset = 0.0;
    01292   }
    01293   else
    01294   {
    01295     if ((set_number % 2) == 0)
    01296       *pattern_offset =  1500000.0;
    01297     else
    01298       *pattern_offset = 1000000.00;
    01299   }
    01300 }
    01301
    01302
    01303 void MGRS::getLatitudeBandMinNorthing( long letter, double* min_northing, double* northing_offset )
    01304 {
    01305 /*
    01306  * The function getLatitudeBandMinNorthing receives a latitude band letter
    01307  * and uses the Latitude_Band_Table to determine the minimum northing and northing offset
    01308  * for that latitude band letter.
    01309  *
    01310  *   letter          : Latitude band letter             (input)
    01311  *   min_northing    : Minimum northing for that letter (output)
    01312  *   northing_offset : Latitude band northing offset    (output)
    01313  */
    01314
    01315   if ((letter >= LETTER_C) && (letter <= LETTER_H))
    01316   {
    01317     *min_northing = Latitude_Band_Table[letter-2].min_northing;
    01318     *northing_offset = Latitude_Band_Table[letter-2].northing_offset;
    01319   }
    01320   else if ((letter >= LETTER_J) && (letter <= LETTER_N))
    01321   {
    01322     *min_northing = Latitude_Band_Table[letter-3].min_northing;
    01323     *northing_offset = Latitude_Band_Table[letter-3].northing_offset;
    01324   }
    01325   else if ((letter >= LETTER_P) && (letter <= LETTER_X))
    01326   {
    01327     *min_northing = Latitude_Band_Table[letter-4].min_northing;
    01328     *northing_offset = Latitude_Band_Table[letter-4].northing_offset;
    01329   }
    01330   else
    01331     throw CoordinateConversionException( ErrorMessages::mgrsString );
    01332 }
    01333
    01334
    01335 void MGRS::getLatitudeRange( long letter, double* north, double* south )
    01336 {
    01337 /*
    01338  * The function getLatitudeRange receives a latitude band letter
    01339  * and uses the Latitude_Band_Table to determine the latitude band
    01340  * boundaries for that latitude band letter.
    01341  *
    01342  *   letter   : Latitude band letter                        (input)
    01343  *   north    : Northern latitude boundary for that letter  (output)
    01344  *   north    : Southern latitude boundary for that letter  (output)
    01345  */
    01346
    01347   if ((letter >= LETTER_C) && (letter <= LETTER_H))
    01348   {
    01349     *north = Latitude_Band_Table[letter-2].north * PI_OVER_180;
    01350     *south = Latitude_Band_Table[letter-2].south * PI_OVER_180;
    01351   }
    01352   else if ((letter >= LETTER_J) && (letter <= LETTER_N))
    01353   {
    01354     *north = Latitude_Band_Table[letter-3].north * PI_OVER_180;
    01355     *south = Latitude_Band_Table[letter-3].south * PI_OVER_180;
    01356   }
    01357   else if ((letter >= LETTER_P) && (letter <= LETTER_X))
    01358   {
    01359     *north = Latitude_Band_Table[letter-4].north * PI_OVER_180;
    01360     *south = Latitude_Band_Table[letter-4].south * PI_OVER_180;
    01361   }
    01362   else
    01363     throw CoordinateConversionException( ErrorMessages::mgrsString );
    01364 }
    01365
    01366
    01367 void MGRS::getLatitudeLetter( double latitude, int* letter )
    01368 {
    01369 /*
    01370  * The function getLatitudeLetter receives a latitude value
    01371  * and uses the Latitude_Band_Table to determine the latitude band
    01372  * letter for that latitude.
    01373  *
    01374  *   latitude   : Latitude              (input)
    01375  *   letter     : Latitude band letter  (output)
    01376  */
    01377
    01378   long band = 0;
    01379
    01380   if (latitude >= _72 && latitude < _84_5)
    01381     *letter = LETTER_X;
    01382   else if (latitude > -_80_5 && latitude < _72)
    01383   {
    01384     band = (long)(((latitude + _80) / _8) + 1.0e-12);
    01385     if(band < 0)
    01386       band = 0;
    01387     *letter = Latitude_Band_Table[band].letter;
    01388   }
    01389   else
    01390     throw CoordinateConversionException( ErrorMessages::latitude );
    01391 }
    01392
    01393
    01394
    01395
    01396
    01397
    01398 // CLASSIFICATION: UNCLASSIFIED