- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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

Go to the documentation of this file.

    00001 // CLASSIFICATION: UNCLASSIFIED
    00002
    00003 /***************************************************************************/
    00004 /* RSC IDENTIFIER: GEOREF
    00005  *
    00006  * ABSTRACT
    00007  *
    00008  *    This component provides conversions from Geodetic coordinates (latitude
    00009  *    and longitude in radians) to a GEOREF coordinate string.
    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  *          GEOREF_NO_ERROR          : No errors occurred in function
    00019  *          GEOREF_LAT_ERROR         : Latitude outside of valid range
    00020  *                                      (-90 to 90 degrees)
    00021  *          GEOREF_LON_ERROR         : Longitude outside of valid range
    00022  *                                      (-180 to 360 degrees)
    00023  *          GEOREF_STR_ERROR         : A GEOREF string error: string too long,
    00024  *                                      string too short, or string length
    00025  *                                      not even.
    00026  *          GEOREF_STR_LAT_ERROR     : The latitude part of the GEOREF string
    00027  *                                     (second or fourth character) is invalid.
    00028  *          GEOREF_STR_LON_ERROR     : The longitude part of the GEOREF string
    00029  *                                     (first or third character) is invalid.
    00030  *          GEOREF_STR_LAT_MIN_ERROR : The latitude minute part of the GEOREF
    00031  *                                      string is greater than 60.
    00032  *          GEOREF_STR_LON_MIN_ERROR : The longitude minute part of the GEOREF
    00033  *                                      string is greater than 60.
    00034  *          GEOREF_PRECISION_ERROR   : The precision must be between 0 and 5
    00035  *                                      inclusive.
    00036  *
    00037  *
    00038  * REUSE NOTES
    00039  *
    00040  *    GEOREF is intended for reuse by any application that performs a
    00041  *    conversion between Geodetic and GEOREF coordinates.
    00042  *
    00043  * REFERENCES
    00044  *
    00045  *    Further information on GEOREF can be found in the Reuse Manual.
    00046  *
    00047  *    GEOREF originated from :  U.S. Army Topographic Engineering Center
    00048  *                              Geospatial Information Division
    00049  *                              7701 Telegraph Road
    00050  *                              Alexandria, VA  22310-3864
    00051  *
    00052  * LICENSES
    00053  *
    00054  *    None apply to this component.
    00055  *
    00056  * RESTRICTIONS
    00057  *
    00058  *    GEOREF has no restrictions.
    00059  *
    00060  * ENVIRONMENT
    00061  *
    00062  *    GEOREF 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  *    02-20-97          Original Code
    00072  *    03-02-07          Original C++ Code
    00073  */
    00074
    00075
    00076 /***************************************************************************/
    00077 /*
    00078  *                               INCLUDES
    00079  */
    00080
    00081 #include <ctype.h>
    00082 #include <math.h>
    00083 #include <stdio.h>
    00084 #include <stdlib.h>
    00085 #include <string.h>
    00086 #include "GEOREF.h"
    00087 #include "GEOREFCoordinates.h"
    00088 #include "MapProjectionCoordinates.h"
    00089 #include "GeodeticCoordinates.h"
    00090 #include "CoordinateConversionException.h"
    00091 #include "ErrorMessages.h"
    00092
    00093 /*
    00094  *  ctype.h    - Standard C character handling library
    00095  *  math.h     - Standard C math library
    00096  *  stdio.h    - Standard C input/output library
    00097  *  stdlib.h   - Standard C general utility library
    00098  *  string.h   - Standard C string handling library
    00099  *  GEOREF.h   - for prototype error checking
    00100  *  GEOREFCoordinates.h   - defines GEOREF coordinates
    00101  *  MapProjectionCoordinates.h   - defines map projection coordinates
    00102  *  GeodeticCoordinates.h   - defines geodetic coordinates
    00103  *  CoordinateConversionException.h - Exception handler
    00104  *  ErrorMessages.h  - Contains exception messages
    00105  */
    00106
    00107
    00108 using namespace MSP::CCS;
    00109
    00110
    00111 /***************************************************************************/
    00112 /*                               DEFINES
    00113  *
    00114  */
    00115
    00116 const int TRUE = 1;
    00117 const int FALSE = 0;
    00118 const double LATITUDE_LOW = -90.0;           /* Minimum latitude                      */
    00119 const double LATITUDE_HIGH = 90.0;           /* Maximum latitude                      */
    00120 const double LONGITUDE_LOW = -180.0;         /* Minimum longitude                     */
    00121 const double LONGITUDE_HIGH = 360.0;         /* Maximum longitude                     */
    00122 const double MIN_PER_DEG = 60.0;             /* Number of minutes per degree          */
    00123 const int GEOREF_MINIMUM = 4;                /* Minimum number of chars for GEOREF    */
    00124 const int GEOREF_MAXIMUM = 14;               /* Maximum number of chars for GEOREF    */
    00125 const int GEOREF_LETTERS = 4;                /* Number of letters in GEOREF string    */
    00126 const int MAX_PRECISION = 5;                 /* Maximum precision of minutes part     */
    00127 const int LETTER_I = 8;                      /* Index for letter I                    */
    00128 const int LETTER_M = 12;                     /* Index for letter M                    */
    00129 const int LETTER_O = 14;                     /* Index for letter O                    */
    00130 const int LETTER_Q = 16;                     /* Index for letter Q                    */
    00131 const int LETTER_Z = 25;                     /* Index for letter Z                    */
    00132 const int LETTER_A_OFFSET = 65;              /* Letter A offset in character set      */
    00133 const int ZERO_OFFSET = 48;                  /* Number zero offset in character set   */
    00134 const double PI = 3.14159265358979323e0;     /* PI                                    */
    00135 const double DEGREE_TO_RADIAN = (PI / 180.0);
    00136 const double RADIAN_TO_DEGREE = (180.0 / PI);
    00137 const double QUAD = 15.0;                    /* Degrees per grid square               */
    00138 const double ROUND_ERROR = 0.0000005;        /* Rounding factor                       */
    00139
    00140
    00141 /************************************************************************/
    00142 /*                              LOCAL FUNCTIONS
    00143  *
    00144  */
    00145
    00146 void extractDegrees( char *GEOREFString, double *longitude, double *latitude )
    00147 {
    00148 /*
    00149  *  This function extracts the latitude and longitude degree parts of the
    00150  *  GEOREF string.  The latitude and longitude degree parts are the first four
    00151  *  characters.
    00152  *
    00153  *    GEOREFString  : GEOREF string             (input)
    00154  *    longitude     : Longitude in degrees      (output)
    00155  *    latitude      : Latitude in degrees       (output)
    00156  */
    00157   long i;                             /* counter in for loops            */
    00158   long temp_char;                     /* temporary character             */
    00159   long letter_number[GEOREF_LETTERS]; /* number corresponding to letter  */
    00160
    00161   for (i=0;i<GEOREF_LETTERS;i++)
    00162   {
    00163     temp_char = toupper(GEOREFString[i]);
    00164     temp_char = temp_char - LETTER_A_OFFSET;
    00165     if ((!isalpha(GEOREFString[i]))
    00166         || (temp_char == LETTER_I)
    00167         || (temp_char == LETTER_O))
    00168     {
    00169       if ((i == 0) || (i == 2))
    00170         throw CoordinateConversionException( ErrorMessages::longitude );
    00171       else
    00172         throw CoordinateConversionException( ErrorMessages::latitude );
    00173     }
    00174     letter_number[i] = temp_char;
    00175   }
    00176   for (i=0;i<4;i++)
    00177   {
    00178     if (letter_number[i] > LETTER_O)
    00179       letter_number[i] -= 2;
    00180     else if (letter_number[i] > LETTER_I)
    00181       letter_number[i] -= 1;
    00182   }
    00183   if ((letter_number[0] > 23) || (letter_number[2] > 14))
    00184     throw CoordinateConversionException( ErrorMessages::georefString );
    00185   if ((letter_number[1] > 11) || (letter_number[3] > 14))
    00186     throw CoordinateConversionException( ErrorMessages::georefString );
    00187
    00188   *latitude = (double)(letter_number[1]) * QUAD + (double)(letter_number[3]);
    00189   *longitude = (double)(letter_number[0]) * QUAD + (double)(letter_number[2]);
    00190 }
    00191
    00192
    00193 void extractMinutes( char *GEOREFString, long start, long length, long errorType, double *minutes )
    00194 {
    00195 /*
    00196  *  This function extracts the minutes from the GEOREF string.  The minutes
    00197  *  part begins at position start and has length length.  The ERROR_TYPE is
    00198  *  to allow this function to work with both latitude and longitude minutes.
    00199  *
    00200  *    GEOREFString : GEOREF string                                        (input)
    00201  *    start        : Start position in the GEOREF string                  (input)
    00202  *    length       : length of minutes in the GEOREF string               (input)
    00203  *    errorType    : has a value of either GEOREF_STR_LAT_MIN_ERROR  (input)
    00204  *                    or GEOREF_STR_LON_MIN_ERROR
    00205  *    minutes      : minute part                                          (output)
    00206  */
    00207   long i;                    /* counter in for loop  */
    00208   char temp_str[(GEOREF_MAXIMUM-GEOREF_LETTERS)/2 + 1];
    00209
    00210   for (i=0;i<length;i++)
    00211   {
    00212     if (isdigit(GEOREFString[start+i]))
    00213       temp_str[i] = GEOREFString[start+i];
    00214     else
    00215     {
    00216       if( errorType == GEOREF_STR_LAT_MIN_ERROR )
    00217         throw CoordinateConversionException( ErrorMessages::latitude_min );
    00218       else
    00219         throw CoordinateConversionException( ErrorMessages::longitude_min );
    00220     }
    00221   }
    00222   temp_str[length] = 0;
    00223   *minutes = (double)atof(temp_str);  /* need atof, atoi can't handle 59999 */
    00224   while (length > 2)
    00225   {
    00226     *minutes = *minutes / 10;
    00227     length = length - 1;
    00228   }
    00229   if (*minutes > (double)MIN_PER_DEG)
    00230     throw CoordinateConversionException( ErrorMessages::georefString );
    00231 }
    00232
    00233
    00234 long roundGEOREF( double value )
    00235 {
    00236 /* Round value to nearest integer, using standard engineering rule */
    00237
    00238   double ivalue;
    00239   long ival;
    00240   double fraction = modf (value, &ivalue);
    00241
    00242   ival = (long)(ivalue);
    00243   if ((fraction > 0.5) || ((fraction == 0.5) && (ival%2 == 1)))
    00244     ival++;
    00245
    00246   return ival;
    00247 }
    00248
    00249
    00250 void convertMinutesToString( double minutes, long precision, char *str )
    00251 {
    00252 /*
    00253  *  This function converts minutes to a string of length precision.
    00254  *
    00255  *    minutes       : Minutes to be converted                  (input)
    00256  *    precision     : Length of resulting string               (input)
    00257  *    str           : String to hold converted minutes         (output)
    00258  */
    00259
    00260   double divisor;
    00261   long min;
    00262   divisor = pow (10.0, (5.0 - precision));
    00263   if (minutes == 60.0)
    00264     minutes = 59.999;
    00265   minutes = minutes * 1000;
    00266   min = roundGEOREF (minutes/divisor);
    00267   sprintf (str, "%*.*ld", precision, precision, min);
    00268   if (precision == 1)
    00269     strcat (str, "0");
    00270 }
    00271
    00272
    00273 /************************************************************************/
    00274 /*                              FUNCTIONS
    00275  *
    00276  */
    00277
    00278 GEOREF::GEOREF() :
    00279   CoordinateSystem( 0, 0 )
    00280 {
    00281 }
    00282
    00283
    00284 GEOREF::GEOREF( const GEOREF &g )
    00285 {
    00286   semiMajorAxis = g.semiMajorAxis;
    00287   flattening = g.flattening;
    00288 }
    00289
    00290
    00291 GEOREF::~GEOREF()
    00292 {
    00293 }
    00294
    00295
    00296 GEOREF& GEOREF::operator=( const GEOREF &g )
    00297 {
    00298   if( this != &g )
    00299   {
    00300     semiMajorAxis = g.semiMajorAxis;
    00301     flattening = g.flattening;
    00302   }
    00303
    00304   return *this;
    00305 }
    00306
    00307
    00308 MSP::CCS::GEOREFCoordinates* GEOREF::convertFromGeodetic( MSP::CCS::GeodeticCoordinates* geodeticCoordinates, long precision )
    00309 {
    00310 /*
    00311  *  The function convertFromGeodetic converts Geodetic (latitude and longitude in radians)
    00312  *  coordinates to a GEOREF coordinate string.  Precision specifies the
    00313  *  number of digits in the GEOREF string for latitude and longitude:
    00314  *                                  0 for nearest degree
    00315  *                                  1 for nearest ten minutes
    00316  *                                  2 for nearest minute
    00317  *                                  3 for nearest tenth of a minute
    00318  *                                  4 for nearest hundredth of a minute
    00319  *                                  5 for nearest thousandth of a minute
    00320  *
    00321  *    longitude    : Longitude in radians.                  (input)
    00322  *    latitude     : Latitude in radians.                   (input)
    00323  *    precision    : Precision specified by the user.       (input)
    00324  *    GEOREFString : GEOREF coordinate string.              (output)
    00325  *
    00326  */
    00327
    00328   double long_min;                        /* GEOREF longitude minute part   */
    00329   double lat_min;                         /* GEOREF latitude minute part    */
    00330   double origin_long;                     /* Origin longitude (-180 degrees)*/
    00331   double origin_lat;                      /* Origin latitude (-90 degrees)  */
    00332   long letter_number[GEOREF_LETTERS + 1]; /* GEOREF letters                 */
    00333   char long_min_str[MAX_PRECISION + 1];   /* Longitude minute string        */
    00334   char lat_min_str[MAX_PRECISION + 1];    /* Latitude minute string         */
    00335   long i;                                 /* counter in for loop            */
    00336   char GEOREFString[21];
    00337
    00338   double latitude = geodeticCoordinates->latitude() * RADIAN_TO_DEGREE;
    00339   double longitude = geodeticCoordinates->longitude() * RADIAN_TO_DEGREE;
    00340
    00341   if ((latitude < (double)LATITUDE_LOW)
    00342       || (latitude > (double)LATITUDE_HIGH))
    00343     throw CoordinateConversionException( ErrorMessages::latitude );
    00344   if ((longitude < (double)LONGITUDE_LOW)
    00345       || (longitude > (double)LONGITUDE_HIGH))
    00346     throw CoordinateConversionException( ErrorMessages::longitude );
    00347   if ((precision < 0) || (precision > MAX_PRECISION))
    00348     throw CoordinateConversionException( ErrorMessages::precision );
    00349
    00350   if (longitude > 180)
    00351       longitude -= 360;
    00352
    00353   origin_long = (double)LONGITUDE_LOW;
    00354   origin_lat = (double)LATITUDE_LOW;
    00355   letter_number[0] = (long)((longitude-origin_long) / QUAD + ROUND_ERROR);
    00356   longitude = longitude - ((double)letter_number[0] * QUAD + origin_long);
    00357   letter_number[2] = (long)(longitude + ROUND_ERROR);
    00358   long_min = (longitude - (double)letter_number[2]) * (double)MIN_PER_DEG;
    00359   letter_number[1] = (long)((latitude - origin_lat) / QUAD + ROUND_ERROR);
    00360   latitude = latitude - ((double)letter_number[1] * QUAD + origin_lat);
    00361   letter_number[3] = (long)(latitude + ROUND_ERROR);
    00362   lat_min = (latitude - (double)letter_number[3]) * (double)MIN_PER_DEG;
    00363   for (i = 0;i < 4; i++)
    00364   {
    00365     if (letter_number[i] >= LETTER_I)
    00366       letter_number[i] += 1;
    00367     if (letter_number[i] >= LETTER_O)
    00368       letter_number[i] += 1;
    00369   }
    00370
    00371   if (letter_number[0] == 26)
    00372   { /* longitude of 180 degrees */
    00373     letter_number[0] = LETTER_Z;
    00374     letter_number[2] = LETTER_Q;
    00375     long_min = 59.999;
    00376   }
    00377   if (letter_number[1] == 13)
    00378   { /* latitude of 90 degrees */
    00379     letter_number[1] = LETTER_M;
    00380     letter_number[3] = LETTER_Q;
    00381     lat_min = 59.999;
    00382   }
    00383
    00384   for (i=0;i<4;i++)
    00385     GEOREFString[i] = (char)(letter_number[i] + LETTER_A_OFFSET);
    00386   GEOREFString[4] = 0;
    00387   convertMinutesToString(long_min,precision,long_min_str);
    00388   convertMinutesToString(lat_min,precision,lat_min_str);
    00389   strcat(GEOREFString,long_min_str);
    00390   strcat(GEOREFString,lat_min_str);
    00391
    00392   return new GEOREFCoordinates( CoordinateType::georef, GEOREFString );
    00393 }
    00394
    00395
    00396 MSP::CCS::GeodeticCoordinates* GEOREF::convertToGeodetic( MSP::CCS::GEOREFCoordinates* georefCoordinates )
    00397 {
    00398 /*
    00399  *  The function convertToGeodetic converts a GEOREF coordinate string to Geodetic (latitude
    00400  *  and longitude in radians) coordinates.
    00401  *
    00402  *    GEOREFString : GEOREF coordinate string.     (input)
    00403  *    longitude    : Longitude in radians.         (output)
    00404  *    latitude     : Latitude in radians.          (output)
    00405  *
    00406  */
    00407
    00408   long start;                /* Position in the GEOREF string                */
    00409   long minutes_length;       /* length of minutes in the GEOREF string       */
    00410   long georef_length;        /* length of GEOREF string                      */
    00411   double origin_long;        /* Origin longitude                             */
    00412   double origin_lat;         /* Origin latitude                              */
    00413   double long_minutes;       /* Longitude minute part of GEOREF              */
    00414   double lat_minutes;        /* Latitude minute part of GEOREF               */
    00415   double longitude, latitude;
    00416
    00417   origin_long = (double)LONGITUDE_LOW;
    00418   origin_lat = (double)LATITUDE_LOW;
    00419
    00420   char* GEOREFString = georefCoordinates->GEOREFString();
    00421
    00422   georef_length = strlen(GEOREFString);
    00423   if ((georef_length < GEOREF_MINIMUM) || (georef_length > GEOREF_MAXIMUM)
    00424       || ((georef_length % 2) != 0))
    00425     throw CoordinateConversionException( ErrorMessages::georefString );
    00426
    00427   extractDegrees( GEOREFString, &longitude, &latitude );
    00428   start = GEOREF_LETTERS;
    00429   minutes_length = (georef_length - start) / 2;
    00430
    00431   extractMinutes(GEOREFString, start, minutes_length,
    00432                                 GEOREF_STR_LON_MIN_ERROR, &long_minutes);
    00433
    00434   extractMinutes(GEOREFString, (start+minutes_length),
    00435                                 minutes_length, GEOREF_STR_LAT_MIN_ERROR, &lat_minutes);
    00436
    00437   latitude = latitude + origin_lat + lat_minutes / (double)MIN_PER_DEG;
    00438   longitude = longitude + origin_long + long_minutes / (double)MIN_PER_DEG;
    00439   latitude = latitude * DEGREE_TO_RADIAN;
    00440   longitude = longitude * DEGREE_TO_RADIAN;
    00441
    00442   return new GeodeticCoordinates( CoordinateType::geodetic, longitude, latitude );
    00443 }
    00444
    00445
    00446
    00447 // CLASSIFICATION: UNCLASSIFIED