00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
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
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 using namespace MSP::CCS;
00114
00115
00116
00117
00118
00119
00120
00121 #define EPSILON 1.75e-7
00122
00123 const int LETTER_A = 0;
00124 const int LETTER_B = 1;
00125 const int LETTER_C = 2;
00126 const int LETTER_D = 3;
00127 const int LETTER_E = 4;
00128 const int LETTER_F = 5;
00129 const int LETTER_G = 6;
00130 const int LETTER_H = 7;
00131 const int LETTER_I = 8;
00132 const int LETTER_J = 9;
00133 const int LETTER_K = 10;
00134 const int LETTER_L = 11;
00135 const int LETTER_M = 12;
00136 const int LETTER_N = 13;
00137 const int LETTER_O = 14;
00138 const int LETTER_P = 15;
00139 const int LETTER_Q = 16;
00140 const int LETTER_R = 17;
00141 const int LETTER_S = 18;
00142 const int LETTER_T = 19;
00143 const int LETTER_U = 20;
00144 const int LETTER_V = 21;
00145 const int LETTER_W = 22;
00146 const int LETTER_X = 23;
00147 const int LETTER_Y = 24;
00148 const int LETTER_Z = 25;
00149 const double ONEHT = 100000.e0;
00150 const double TWOMIL = 2000000.e0;
00151 const int TRUE = 1;
00152 const int FALSE = 0;
00153 const double PI = 3.14159265358979323e0;
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;
00162 const double MIN_MGRS_NON_POLAR_LAT = -80.0 * ( PI / 180.0 );
00163 const double MAX_MGRS_NON_POLAR_LAT = 84.0 * ( PI / 180.0 );
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
00179
00180
00181
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;
00191 double min_northing;
00192 double north;
00193 double south;
00194 double 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;
00223 long ltr2_low_value;
00224 long ltr2_high_value;
00225 long ltr3_high_value;
00226 double false_easting;
00227 double false_northing;
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
00239
00240
00241
00242 long roundMGRS( double value )
00243 {
00244
00245
00246
00247
00248
00249
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
00266
00267
00268
00269
00270
00271
00272
00273
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);
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
00309
00310
00311
00312
00313
00314
00315
00316
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++;
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
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
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
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
00405
00406
00407
00408 MGRS::MGRS( double ellipsoidSemiMajorAxis, double ellipsoidFlattening, char* ellipsoidCode ) :
00409 CoordinateSystem(),
00410 ups( 0 ),
00411 utm( 0 )
00412 {
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 double inv_f = 1 / ellipsoidFlattening;
00424 char errorStatus[500] = "";
00425
00426 if (ellipsoidSemiMajorAxis <= 0.0)
00427 {
00428 strcat( errorStatus, ErrorMessages::semiMajorAxis );
00429 }
00430 if ((inv_f < 250) || (inv_f > 350))
00431 {
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
00491
00492
00493
00494
00495
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
00506
00507
00508
00509
00510
00511
00512
00513
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 {
00525 strcat( errorStatus, ErrorMessages::latitude );
00526 }
00527 if ((longitude < -PI) || (longitude > (2*PI)))
00528 {
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
00538
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
00562
00563
00564
00565
00566
00567
00568
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
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
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
00640
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
00665
00666
00667
00668
00669
00670
00671
00672
00673
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
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
00711
00712
00713
00714
00715
00716
00717
00718
00719
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
00744
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
00771
00772
00773
00774
00775
00776
00777
00778
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
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828 double pattern_offset;
00829 double grid_northing;
00830 long ltr2_low_value;
00831 long ltr2_high_value;
00832 int letters[MGRS_LETTERS];
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
00847
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 {
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
00873 if (letters[0] == LETTER_V)
00874 {
00875 if ((zone == 31) && (easting >= _500000))
00876 override = 32;
00877 }
00878 else if (letters[0] == LETTER_X)
00879 {
00880 if ((zone == 32) && (easting < _500000))
00881 override = 31;
00882 else if (((zone == 32) && (easting >= _500000)) ||
00883 ((zone == 34) && (easting < _500000)))
00884 override = 33;
00885 else if (((zone == 34) && (easting >= _500000)) ||
00886 ((zone == 36) && (easting < _500000)))
00887 override = 35;
00888 else if ((zone == 36) && (easting >= _500000))
00889 override = 37;
00890 }
00891
00892 if (override)
00893 {
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, <r2_low_value, <r2_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
00952
00953
00954
00955
00956
00957
00958
00959
00960
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;
00970 double lower_lat_limit;
00971 double grid_easting;
00972 double grid_northing;
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, <r2_low_value, <r2_high_value, &pattern_offset);
00993
00994
00995
00996
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
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
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063 double false_easting;
01064 double false_northing;
01065 double grid_easting;
01066 double grid_northing;
01067 long ltr2_low_value;
01068 int letters[MGRS_LETTERS];
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
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161 long ltr2_high_value;
01162 long ltr3_high_value;
01163 long ltr2_low_value;
01164 double false_easting;
01165 double false_northing;
01166 double grid_easting;
01167 double grid_northing;
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
01196
01197
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
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255 long set_number;
01256 long aa_pattern;
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
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
01307
01308
01309
01310
01311
01312
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
01339
01340
01341
01342
01343
01344
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
01371
01372
01373
01374
01375
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