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
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 #include <stdio.h>
00097 #include <math.h>
00098 #include "PolarStereographic.h"
00099 #include "PolarStereographicStandardParallelParameters.h"
00100 #include "PolarStereographicScaleFactorParameters.h"
00101 #include "MapProjectionCoordinates.h"
00102 #include "GeodeticCoordinates.h"
00103 #include "CoordinateConversionException.h"
00104 #include "ErrorMessages.h"
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 using namespace MSP::CCS;
00117
00118
00119
00120
00121
00122
00123
00124 const double PI = 3.14159265358979323e0;
00125 const double PI_OVER_2 = (PI / 2.0);
00126 const double PI_OVER_4 = (PI / 4.0);
00127 const double TWO_PI = (2.0 * PI);
00128
00129 #define MIN_SCALE_FACTOR 0.1
00130 #define MAX_SCALE_FACTOR 3.0
00131
00132
00133
00134
00135
00136
00137
00138 PolarStereographic::PolarStereographic( double ellipsoidSemiMajorAxis, double ellipsoidFlattening, double centralMeridian, double standardParallel, double falseEasting, double falseNorthing ) :
00139 CoordinateSystem(),
00140 coordinateType( CoordinateType::polarStereographicStandardParallel ),
00141 es( 0.08181919084262188000 ),
00142 es_OVER_2( .040909595421311 ),
00143 Southern_Hemisphere( 0 ),
00144 Polar_tc( 1.0 ),
00145 Polar_k90( 1.0033565552493 ),
00146 Polar_a_mc( 6378137.0 ),
00147 two_Polar_a( 12756274.0 ),
00148 Polar_Central_Meridian( 0.0 ),
00149 Polar_Standard_Parallel( ((PI * 90) / 180) ),
00150 Polar_False_Easting( 0.0 ),
00151 Polar_False_Northing( 0.0 ),
00152 Polar_Scale_Factor( 1.0 ),
00153 Polar_Delta_Easting( 12713601.0 ),
00154 Polar_Delta_Northing( 12713601.0 )
00155 {
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 double es2;
00171 double slat, sinolat, cosolat;
00172 double essin;
00173 double one_PLUS_es, one_MINUS_es;
00174 double one_PLUS_es_sinolat, one_MINUS_es_sinolat;
00175 double pow_es;
00176 double inv_f = 1 / ellipsoidFlattening;
00177 char errorStatus[500] = "";
00178
00179 if (ellipsoidSemiMajorAxis <= 0.0)
00180 {
00181 strcat( errorStatus, ErrorMessages::semiMajorAxis );
00182 }
00183 if ((inv_f < 250) || (inv_f > 350))
00184 {
00185 strcat( errorStatus, ErrorMessages::ellipsoidFlattening );
00186 }
00187 if ((standardParallel < -PI_OVER_2) || (standardParallel > PI_OVER_2))
00188 {
00189 strcat( errorStatus, ErrorMessages::originLatitude );
00190 }
00191 if ((centralMeridian < -PI) || (centralMeridian > TWO_PI))
00192 {
00193 strcat( errorStatus, ErrorMessages::centralMeridian );
00194 }
00195
00196 if( strlen( errorStatus ) > 0)
00197 throw CoordinateConversionException( errorStatus );
00198
00199 semiMajorAxis = ellipsoidSemiMajorAxis;
00200 flattening = ellipsoidFlattening;
00201
00202 two_Polar_a = 2.0 * semiMajorAxis;
00203
00204 if (centralMeridian > PI)
00205 centralMeridian -= TWO_PI;
00206 if (standardParallel < 0)
00207 {
00208 Southern_Hemisphere = 1;
00209 Polar_Standard_Parallel = -standardParallel;
00210 Polar_Central_Meridian = -centralMeridian;
00211 }
00212 else
00213 {
00214 Southern_Hemisphere = 0;
00215 Polar_Standard_Parallel = standardParallel;
00216 Polar_Central_Meridian = centralMeridian;
00217 }
00218 Polar_False_Easting = falseEasting;
00219 Polar_False_Northing = falseNorthing;
00220
00221 es2 = 2 * flattening - flattening * flattening;
00222 es = sqrt(es2);
00223 es_OVER_2 = es / 2.0;
00224
00225 if (fabs(fabs(Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10)
00226 {
00227 sinolat = sin(Polar_Standard_Parallel);
00228 essin = es * sinolat;
00229 pow_es = polarPow(essin);
00230 cosolat = cos(Polar_Standard_Parallel);
00231 double mc = cosolat / sqrt(1.0 - essin * essin);
00232 Polar_a_mc = semiMajorAxis * mc;
00233 Polar_tc = tan(PI_OVER_4 - Polar_Standard_Parallel / 2.0) / pow_es;
00234 }
00235
00236 one_PLUS_es = 1.0 + es;
00237 one_MINUS_es = 1.0 - es;
00238 Polar_k90 = sqrt(pow(one_PLUS_es, one_PLUS_es) * pow(one_MINUS_es, one_MINUS_es));
00239
00240 slat = sin(fabs(standardParallel));
00241 one_PLUS_es_sinolat = 1.0 + es * slat;
00242 one_MINUS_es_sinolat = 1.0 - es * slat;
00243 Polar_Scale_Factor = ((1 + slat) / 2) * (Polar_k90 / sqrt(pow(one_PLUS_es_sinolat, one_PLUS_es) * pow(one_MINUS_es_sinolat, one_MINUS_es)));
00244
00245
00246 GeodeticCoordinates tempGeodeticCoordinates = GeodeticCoordinates( CoordinateType::geodetic, centralMeridian, 0 );
00247
00248 MapProjectionCoordinates* tempCoordinates = convertFromGeodetic( &tempGeodeticCoordinates );
00249 Polar_Delta_Northing = tempCoordinates->northing();
00250 delete tempCoordinates;
00251
00252 if(Polar_False_Northing)
00253 Polar_Delta_Northing -= Polar_False_Northing;
00254 if (Polar_Delta_Northing < 0)
00255 Polar_Delta_Northing = -Polar_Delta_Northing;
00256 Polar_Delta_Northing *= 1.01;
00257
00258 Polar_Delta_Easting = Polar_Delta_Northing;
00259 }
00260
00261
00262 PolarStereographic::PolarStereographic( double ellipsoidSemiMajorAxis, double ellipsoidFlattening, double centralMeridian, double scaleFactor, char hemisphere, double falseEasting, double falseNorthing ) :
00263 CoordinateSystem(),
00264 coordinateType( CoordinateType::polarStereographicScaleFactor ),
00265 es( 0.08181919084262188000 ),
00266 es_OVER_2( .040909595421311 ),
00267 Southern_Hemisphere( 0 ),
00268 Polar_tc( 1.0 ),
00269 Polar_k90( 1.0033565552493 ),
00270 Polar_a_mc( 6378137.0 ),
00271 two_Polar_a( 12756274.0 ),
00272 Polar_Central_Meridian( 0.0 ),
00273 Polar_Standard_Parallel( ((PI * 90) / 180) ),
00274 Polar_False_Easting( 0.0 ),
00275 Polar_False_Northing( 0.0 ),
00276 Polar_Scale_Factor( 1.0 ),
00277 Polar_Delta_Easting( 12713601.0 ),
00278 Polar_Delta_Northing( 12713601.0 )
00279 {
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 double es2;
00295 double sinolat, cosolat;
00296 double essin;
00297 double pow_es;
00298 double mc;
00299 double one_PLUS_es, one_MINUS_es;
00300 double one_PLUS_es_sk, one_MINUS_es_sk;
00301 double sk, sk_PLUS_1;
00302 double tolerance = 1.0e-15;
00303 int count = 30;
00304 double inv_f = 1 / ellipsoidFlattening;
00305 char errorStatus[500] = "";
00306
00307 if (ellipsoidSemiMajorAxis <= 0.0)
00308 {
00309 strcat( errorStatus, ErrorMessages::semiMajorAxis );
00310 }
00311 if ((inv_f < 250) || (inv_f > 350))
00312 {
00313 strcat( errorStatus, ErrorMessages::ellipsoidFlattening );
00314 }
00315 if ((scaleFactor < MIN_SCALE_FACTOR) || (scaleFactor > MAX_SCALE_FACTOR))
00316 {
00317 strcat( errorStatus, ErrorMessages::scaleFactor );
00318 }
00319 if ((centralMeridian < -PI) || (centralMeridian > TWO_PI))
00320 {
00321 strcat( errorStatus, ErrorMessages::centralMeridian );
00322 }
00323 if ((hemisphere != 'N') && (hemisphere != 'S'))
00324 strcat( errorStatus, ErrorMessages::hemisphere );
00325
00326 if( strlen( errorStatus ) > 0)
00327 throw CoordinateConversionException( errorStatus );
00328
00329 semiMajorAxis = ellipsoidSemiMajorAxis;
00330 flattening = ellipsoidFlattening;
00331 Polar_Scale_Factor = scaleFactor;
00332 Polar_False_Easting = falseEasting;
00333 Polar_False_Northing = falseNorthing;
00334
00335 two_Polar_a = 2.0 * semiMajorAxis;
00336 es2 = 2 * flattening - flattening * flattening;
00337 es = sqrt(es2);
00338 es_OVER_2 = es / 2.0;
00339
00340 one_PLUS_es = 1.0 + es;
00341 one_MINUS_es = 1.0 - es;
00342 Polar_k90 = sqrt(pow(one_PLUS_es, one_PLUS_es) * pow(one_MINUS_es, one_MINUS_es));
00343
00344 sk = 0;
00345 sk_PLUS_1 = -1 + 2 * Polar_Scale_Factor;
00346 while (fabs(sk_PLUS_1 - sk) > tolerance && count)
00347 {
00348 sk = sk_PLUS_1;
00349 one_PLUS_es_sk = 1.0 + es * sk;
00350 one_MINUS_es_sk = 1.0 - es * sk;
00351 sk_PLUS_1 = ((2 * Polar_Scale_Factor * sqrt(pow(one_PLUS_es_sk, one_PLUS_es) * pow(one_MINUS_es_sk, one_MINUS_es))) / Polar_k90) - 1;
00352 count --;
00353 }
00354
00355 if(!count)
00356 throw CoordinateConversionException( ErrorMessages::originLatitude );
00357
00358 double standardParallel = 0.0;
00359 if(sk_PLUS_1 >= -1.0 && sk_PLUS_1 <= 1.0)
00360 standardParallel = asin(sk_PLUS_1);
00361 else
00362 throw CoordinateConversionException( ErrorMessages::originLatitude );
00363
00364 if (hemisphere == 'S')
00365 standardParallel *= -1.0;
00366
00367 if (centralMeridian > PI)
00368 centralMeridian -= TWO_PI;
00369 if (standardParallel < 0)
00370 {
00371 Southern_Hemisphere = 1;
00372 Polar_Standard_Parallel = -standardParallel;
00373 Polar_Central_Meridian = -centralMeridian;
00374 }
00375 else
00376 {
00377 Southern_Hemisphere = 0;
00378 Polar_Standard_Parallel = standardParallel;
00379 Polar_Central_Meridian = centralMeridian;
00380 }
00381
00382 sinolat = sin(Polar_Standard_Parallel);
00383
00384 if (fabs(fabs(Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10)
00385 {
00386 essin = es * sinolat;
00387 pow_es = polarPow(essin);
00388 cosolat = cos(Polar_Standard_Parallel);
00389 mc = cosolat / sqrt(1.0 - essin * essin);
00390 Polar_a_mc = semiMajorAxis * mc;
00391 Polar_tc = tan(PI_OVER_4 - Polar_Standard_Parallel / 2.0) / pow_es;
00392 }
00393
00394
00395 GeodeticCoordinates tempGeodeticCoordinates = GeodeticCoordinates( CoordinateType::geodetic, centralMeridian, 0 ) ;
00396 MapProjectionCoordinates* tempCoordinates = convertFromGeodetic( &tempGeodeticCoordinates );
00397 Polar_Delta_Northing = tempCoordinates->northing();
00398 delete tempCoordinates;
00399
00400 if(Polar_False_Northing)
00401 Polar_Delta_Northing -= Polar_False_Northing;
00402 if (Polar_Delta_Northing < 0)
00403 Polar_Delta_Northing = -Polar_Delta_Northing;
00404 Polar_Delta_Northing *= 1.01;
00405
00406 Polar_Delta_Easting = Polar_Delta_Northing;
00407 }
00408
00409
00410 PolarStereographic::PolarStereographic( const PolarStereographic &ps )
00411 {
00412 coordinateType = ps.coordinateType;
00413 semiMajorAxis = ps.semiMajorAxis;
00414 flattening = ps.flattening;
00415 es = ps.es;
00416 es_OVER_2 = ps.es_OVER_2;
00417 Southern_Hemisphere = ps.Southern_Hemisphere;
00418 Polar_tc = ps.Polar_tc;
00419 Polar_k90 = ps.Polar_k90;
00420 Polar_a_mc = ps.Polar_a_mc;
00421 two_Polar_a = ps.two_Polar_a;
00422 Polar_Central_Meridian = ps.Polar_Central_Meridian;
00423 Polar_Standard_Parallel = ps.Polar_Standard_Parallel;
00424 Polar_False_Easting = ps.Polar_False_Easting;
00425 Polar_False_Northing = ps.Polar_False_Northing;
00426 Polar_Scale_Factor = ps.Polar_Scale_Factor;
00427 Polar_Delta_Easting = ps.Polar_Delta_Easting;
00428 Polar_Delta_Northing = ps.Polar_Delta_Northing;
00429 }
00430
00431
00432 PolarStereographic::~PolarStereographic()
00433 {
00434 }
00435
00436
00437 PolarStereographic& PolarStereographic::operator=( const PolarStereographic &ps )
00438 {
00439 if( this != &ps )
00440 {
00441 coordinateType = ps.coordinateType;
00442 semiMajorAxis = ps.semiMajorAxis;
00443 flattening = ps.flattening;
00444 es = ps.es;
00445 es_OVER_2 = ps.es_OVER_2;
00446 Southern_Hemisphere = ps.Southern_Hemisphere;
00447 Polar_tc = ps.Polar_tc;
00448 Polar_k90 = ps.Polar_k90;
00449 Polar_a_mc = ps.Polar_a_mc;
00450 two_Polar_a = ps.two_Polar_a;
00451 Polar_Central_Meridian = ps.Polar_Central_Meridian;
00452 Polar_Standard_Parallel = ps.Polar_Standard_Parallel;
00453 Polar_False_Easting = ps.Polar_False_Easting;
00454 Polar_False_Northing = ps.Polar_False_Northing;
00455 Polar_Scale_Factor = ps.Polar_Scale_Factor;
00456 Polar_Delta_Easting = ps.Polar_Delta_Easting;
00457 Polar_Delta_Northing = ps.Polar_Delta_Northing;
00458 }
00459
00460 return *this;
00461 }
00462
00463
00464 PolarStereographicStandardParallelParameters* PolarStereographic::getStandardParallelParameters() const
00465 {
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 return new PolarStereographicStandardParallelParameters( CoordinateType::polarStereographicStandardParallel, Polar_Central_Meridian, Polar_Standard_Parallel, Polar_False_Easting, Polar_False_Northing );
00479 }
00480
00481
00482 PolarStereographicScaleFactorParameters* PolarStereographic::getScaleFactorParameters() const
00483 {
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 if(Southern_Hemisphere == 0)
00497 return new PolarStereographicScaleFactorParameters( CoordinateType::polarStereographicScaleFactor, Polar_Central_Meridian, Polar_Scale_Factor, 'N', Polar_False_Easting, Polar_False_Northing );
00498 else
00499 return new PolarStereographicScaleFactorParameters( CoordinateType::polarStereographicScaleFactor, Polar_Central_Meridian, Polar_Scale_Factor, 'S', Polar_False_Easting, Polar_False_Northing );
00500 }
00501
00502
00503 MSP::CCS::MapProjectionCoordinates* PolarStereographic::convertFromGeodetic( MSP::CCS::GeodeticCoordinates* geodeticCoordinates )
00504 {
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 double dlam;
00519 double slat;
00520 double essin;
00521 double t;
00522 double rho;
00523 double pow_es;
00524 double easting, northing;
00525 char errorStatus[50] = "";
00526
00527 double longitude = geodeticCoordinates->longitude();
00528 double latitude = geodeticCoordinates->latitude();
00529
00530 if ((latitude < -PI_OVER_2) || (latitude > PI_OVER_2))
00531 {
00532 strcat( errorStatus, ErrorMessages::latitude );
00533 }
00534 else if ((latitude < 0) && (Southern_Hemisphere == 0))
00535 {
00536 strcat( errorStatus, ErrorMessages::latitude );
00537 }
00538 else if ((latitude > 0) && (Southern_Hemisphere == 1))
00539 {
00540 strcat( errorStatus, ErrorMessages::latitude );
00541 }
00542 if ((longitude < -PI) || (longitude > TWO_PI))
00543 {
00544 strcat( errorStatus, ErrorMessages::longitude );
00545 }
00546
00547 if( strlen( errorStatus ) > 0)
00548 throw CoordinateConversionException( errorStatus );
00549
00550 if (fabs(fabs(latitude) - PI_OVER_2) < 1.0e-10)
00551 {
00552 easting = Polar_False_Easting;
00553 northing = Polar_False_Northing;
00554 }
00555 else
00556 {
00557 if (Southern_Hemisphere != 0)
00558 {
00559 longitude *= -1.0;
00560 latitude *= -1.0;
00561 }
00562 dlam = longitude - Polar_Central_Meridian;
00563 if (dlam > PI)
00564 {
00565 dlam -= TWO_PI;
00566 }
00567 if (dlam < -PI)
00568 {
00569 dlam += TWO_PI;
00570 }
00571 slat = sin(latitude);
00572 essin = es * slat;
00573 pow_es = polarPow(essin);
00574 t = tan(PI_OVER_4 - latitude / 2.0) / pow_es;
00575
00576 if (fabs(fabs(Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10)
00577 rho = Polar_a_mc * t / Polar_tc;
00578 else
00579 rho = two_Polar_a * t / Polar_k90;
00580
00581
00582 if (Southern_Hemisphere != 0)
00583 {
00584 easting = -(rho * sin(dlam) - Polar_False_Easting);
00585 northing = rho * cos(dlam) + Polar_False_Northing;
00586 }
00587 else
00588 {
00589 easting = rho * sin(dlam) + Polar_False_Easting;
00590 northing = -rho * cos(dlam) + Polar_False_Northing;
00591 }
00592 }
00593
00594 return new MapProjectionCoordinates( coordinateType, easting, northing );
00595 }
00596
00597
00598 MSP::CCS::GeodeticCoordinates* PolarStereographic::convertToGeodetic( MSP::CCS::MapProjectionCoordinates* mapProjectionCoordinates )
00599 {
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 double dy = 0, dx = 0;
00615 double rho = 0;
00616 double t;
00617 double PHI, sin_PHI;
00618 double tempPHI = 0.0;
00619 double essin;
00620 double pow_es;
00621 double delta_radius;
00622 double longitude, latitude;
00623 char errorStatus[50] = "";
00624
00625 double easting = mapProjectionCoordinates->easting();
00626 double northing = mapProjectionCoordinates->northing();
00627
00628 double min_easting = Polar_False_Easting - Polar_Delta_Easting;
00629 double max_easting = Polar_False_Easting + Polar_Delta_Easting;
00630 double min_northing = Polar_False_Northing - Polar_Delta_Northing;
00631 double max_northing = Polar_False_Northing + Polar_Delta_Northing;
00632
00633 if (easting > max_easting || easting < min_easting)
00634 {
00635 strcat( errorStatus, ErrorMessages::easting );
00636 }
00637 if (northing > max_northing || northing < min_northing)
00638 {
00639 strcat( errorStatus, ErrorMessages::northing );
00640 }
00641
00642 if( strlen( errorStatus ) > 0)
00643 throw CoordinateConversionException( errorStatus );
00644
00645 dy = northing - Polar_False_Northing;
00646 dx = easting - Polar_False_Easting;
00647
00648
00649 rho = sqrt(dx * dx + dy * dy);
00650
00651 delta_radius = sqrt(Polar_Delta_Easting * Polar_Delta_Easting + Polar_Delta_Northing * Polar_Delta_Northing);
00652
00653 if(rho > delta_radius)
00654 {
00655 throw CoordinateConversionException( ErrorMessages::radius );
00656 }
00657
00658 if ((dy == 0.0) && (dx == 0.0))
00659 {
00660 latitude = PI_OVER_2;
00661 longitude = Polar_Central_Meridian;
00662
00663 }
00664 else
00665 {
00666 if (Southern_Hemisphere != 0)
00667 {
00668 dy *= -1.0;
00669 dx *= -1.0;
00670 }
00671
00672 if (fabs(fabs(Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10)
00673 t = rho * Polar_tc / (Polar_a_mc);
00674 else
00675 t = rho * Polar_k90 / (two_Polar_a);
00676 PHI = PI_OVER_2 - 2.0 * atan(t);
00677 while (fabs(PHI - tempPHI) > 1.0e-10)
00678 {
00679 tempPHI = PHI;
00680 sin_PHI = sin(PHI);
00681 essin = es * sin_PHI;
00682 pow_es = polarPow(essin);
00683 PHI = PI_OVER_2 - 2.0 * atan(t * pow_es);
00684 }
00685 latitude = PHI;
00686 longitude = Polar_Central_Meridian + atan2(dx, -dy);
00687
00688 if (longitude > PI)
00689 longitude -= TWO_PI;
00690 else if (longitude < -PI)
00691 longitude += TWO_PI;
00692
00693
00694 if (latitude > PI_OVER_2)
00695 latitude = PI_OVER_2;
00696 else if (latitude < -PI_OVER_2)
00697 latitude = -PI_OVER_2;
00698
00699 if (longitude > PI)
00700 longitude = PI;
00701 else if (longitude < -PI)
00702 longitude = -PI;
00703
00704 }
00705 if (Southern_Hemisphere != 0)
00706 {
00707 latitude *= -1.0;
00708 longitude *= -1.0;
00709 }
00710
00711 return new GeodeticCoordinates( CoordinateType::geodetic, longitude, latitude );
00712 }
00713
00714
00715 double PolarStereographic::polarPow( double esSin )
00716 {
00717 return pow((1.0 - esSin) / (1.0 + esSin), es_OVER_2);
00718 }
00719
00720
00721