00001 #pragma ident "$Id: Position.cpp 2944 2011-10-27 08:04:41Z yanweignss $"
00002
00003
00004
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "Position.hpp"
00037 #include "WGS84Geoid.hpp"
00038 #include "icd_200_constants.hpp"
00039 #include "geometry.hpp"
00040 #include "MiscMath.hpp"
00041
00042 namespace gpstk
00043 {
00044
00045 using namespace std;
00046 using namespace StringUtils;
00047
00048
00049
00050 static const char *SystemNames[] = {
00051 "Unknown",
00052 "Geodetic",
00053 "Geocentric",
00054 "Cartesian",
00055 "Spherical"};
00056
00057
00058 string Position::getSystemName()
00059 throw()
00060 { return SystemNames[system]; }
00061
00062
00063
00064 const double Position::ONE_MM_TOLERANCE = 0.001;
00065
00066 const double Position::ONE_CM_TOLERANCE = 0.01;
00067
00068 const double Position::ONE_UM_TOLERANCE = 0.000001;
00069
00070
00071 double Position::POSITION_TOLERANCE = Position::ONE_MM_TOLERANCE;
00072
00073
00074
00075
00076
00077 Position& Position::setTolerance(const double tol)
00078 throw()
00079 {
00080 tolerance = tol;
00081 return *this;
00082 }
00083
00084
00085
00086
00087 Position::Position()
00088 throw()
00089 {
00090 WGS84Geoid WGS84;
00091 initialize(0.0,0.0,0.0,Unknown,&WGS84);
00092 }
00093
00094 Position::Position(const double& a,
00095 const double& b,
00096 const double& c,
00097 Position::CoordinateSystem s,
00098 GeoidModel *geoid)
00099 throw(GeometryException)
00100 {
00101 try {
00102 initialize(a,b,c,s,geoid);
00103 }
00104 catch(GeometryException& ge) {
00105 GPSTK_RETHROW(ge);
00106 }
00107 }
00108
00109 Position::Position(const double ABC[3],
00110 CoordinateSystem s,
00111 GeoidModel *geoid)
00112 throw(GeometryException)
00113 {
00114 double a=ABC[0];
00115 double b=ABC[1];
00116 double c=ABC[2];
00117 try {
00118 initialize(a,b,c,s,geoid);
00119 }
00120 catch(GeometryException& ge) {
00121 GPSTK_RETHROW(ge);
00122 }
00123 }
00124
00125 Position::Position(const Triple& ABC,
00126 CoordinateSystem s,
00127 GeoidModel *geoid)
00128 throw(GeometryException)
00129 {
00130 double a=ABC[0];
00131 double b=ABC[1];
00132 double c=ABC[2];
00133 try {
00134 initialize(a,b,c,s,geoid);
00135 }
00136 catch(GeometryException& ge) {
00137 GPSTK_RETHROW(ge);
00138 }
00139 }
00140
00141 Position::Position(const Xvt& xvt)
00142 throw()
00143 {
00144 double a=xvt.x[0];
00145 double b=xvt.x[1];
00146 double c=xvt.x[2];
00147 initialize(a,b,c,Cartesian);
00148 }
00149
00150
00151
00152 Position& Position::operator-=(const Position& right)
00153 throw()
00154 {
00155 Position r(right);
00156 CoordinateSystem savesys=system;
00157
00158
00159 transformTo(Cartesian);
00160 r.transformTo(Cartesian);
00161
00162 for(int i=0; i<3; i++)
00163 theArray[i] -= r.theArray[i];
00164
00165 transformTo(savesys);
00166 return *this;
00167 }
00168
00169 Position& Position::operator+=(const Position& right)
00170 throw()
00171 {
00172 Position r(right);
00173 CoordinateSystem savesys=system;
00174
00175
00176 transformTo(Cartesian);
00177 r.transformTo(Cartesian);
00178
00179 for(int i=0; i<3; i++)
00180 theArray[i] += r.theArray[i];
00181
00182 transformTo(savesys);
00183 return *this;
00184 }
00185
00186 Position operator-(const Position& left,
00187 const Position& right)
00188 throw()
00189 {
00190 Position l(left),r(right);
00191
00192 l.transformTo(Position::Cartesian);
00193 r.transformTo(Position::Cartesian);
00194
00195 l -= r;
00196
00197 return l;
00198 }
00199
00200 Position operator+(const Position& left,
00201 const Position& right)
00202 throw()
00203 {
00204 Position l(left),r(right);
00205
00206 l.transformTo(Position::Cartesian);
00207 r.transformTo(Position::Cartesian);
00208
00209 l += r;
00210
00211 return l;
00212 }
00213
00214
00215
00216
00217 bool Position::operator==(const Position &right) const
00218 throw()
00219 {
00220 if(AEarth != right.AEarth || eccSquared != right.eccSquared)
00221 return false;
00222 if(range(*this,right) < tolerance)
00223 return true;
00224 else
00225 return false;
00226 }
00227
00228
00229 bool Position::operator!=(const Position &right) const
00230 throw()
00231 {
00232 return !(operator==(right));
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 Position Position::transformTo(CoordinateSystem sys)
00242 throw()
00243 {
00244 if(sys == Unknown || sys == system) return *this;
00245
00246
00247 Position target(*this);
00248
00249
00250 switch(system) {
00251 case Unknown:
00252 return *this;
00253 case Geodetic:
00254
00255 switch(sys) {
00256 case Unknown: case Geodetic: return *this;
00257 case Geocentric:
00258 convertGeodeticToGeocentric(*this,target,AEarth,eccSquared);
00259 target.system = Geocentric;
00260 break;
00261 case Cartesian:
00262 convertGeodeticToCartesian(*this,target,AEarth,eccSquared);
00263 target.system = Cartesian;
00264 break;
00265 case Spherical:
00266 convertGeodeticToGeocentric(*this,target,AEarth,eccSquared);
00267 target.theArray[0] = 90 - target.theArray[0];
00268 target.system = Spherical;
00269 break;
00270 }
00271 break;
00272 case Geocentric:
00273
00274 switch(sys) {
00275 case Unknown: case Geocentric: return *this;
00276 case Geodetic:
00277 convertGeocentricToGeodetic(*this,target,AEarth,eccSquared);
00278 target.system = Geodetic;
00279 break;
00280 case Cartesian:
00281 convertGeocentricToCartesian(*this,target);
00282 target.system = Cartesian;
00283 break;
00284 case Spherical:
00285 target.theArray[0] = 90 - target.theArray[0];
00286 target.system = Spherical;
00287 break;
00288 }
00289 break;
00290 case Cartesian:
00291
00292 switch(sys) {
00293 case Unknown: case Cartesian: return *this;
00294 case Geodetic:
00295 convertCartesianToGeodetic(*this,target,AEarth,eccSquared);
00296 target.system = Geodetic;
00297 break;
00298 case Geocentric:
00299 convertCartesianToGeocentric(*this,target);
00300 target.system = Geocentric;
00301 break;
00302 case Spherical:
00303 convertCartesianToSpherical(*this,target);
00304 target.system = Spherical;
00305 break;
00306 }
00307 break;
00308 case Spherical:
00309
00310 switch(sys) {
00311 case Unknown: case Spherical: return *this;
00312 case Geodetic:
00313 theArray[0] = 90 - theArray[0];
00314 convertGeocentricToGeodetic(*this,target,AEarth,eccSquared);
00315 target.system = Geodetic;
00316 break;
00317 case Geocentric:
00318 target.theArray[0] = 90 - target.theArray[0];
00319 target.system = Geocentric;
00320 break;
00321 case Cartesian:
00322 convertSphericalToCartesian(*this,target);
00323 target.system = Cartesian;
00324 break;
00325 }
00326 break;
00327 }
00328
00329 *this = target;
00330 return *this;
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340 double Position::X() const
00341 throw()
00342 {
00343 if(system == Cartesian)
00344 return theArray[0];
00345 Position t(*this);
00346 t.transformTo(Cartesian);
00347 return t.theArray[0];
00348 }
00349
00350
00351 double Position::Y() const
00352 throw()
00353 {
00354 if(system == Cartesian)
00355 return theArray[1];
00356 Position t(*this);
00357 t.transformTo(Cartesian);
00358 return t.theArray[1];
00359 }
00360
00361
00362 double Position::Z() const
00363 throw()
00364 {
00365 if(system == Cartesian)
00366 return theArray[2];
00367 Position t(*this);
00368 t.transformTo(Cartesian);
00369 return t.theArray[2];
00370 }
00371
00372
00373 double Position::geodeticLatitude() const
00374 throw()
00375 {
00376 if(system == Geodetic)
00377 return theArray[0];
00378 Position t(*this);
00379 t.transformTo(Geodetic);
00380 return t.theArray[0];
00381 }
00382
00383
00384
00385 double Position::geocentricLatitude() const
00386 throw()
00387 {
00388 if(system == Geocentric)
00389 return theArray[0];
00390 Position t(*this);
00391 t.transformTo(Geocentric);
00392 return t.theArray[0];
00393 }
00394
00395
00396 double Position::theta() const
00397 throw()
00398 {
00399 if(system == Spherical)
00400 return theArray[0];
00401 Position t(*this);
00402 t.transformTo(Spherical);
00403 return t.theArray[0];
00404 }
00405
00406
00407 double Position::phi() const
00408 throw()
00409 {
00410 if(system == Spherical)
00411 return theArray[1];
00412 Position t(*this);
00413 t.transformTo(Spherical);
00414 return t.theArray[1];
00415 }
00416
00417
00418
00419 double Position::longitude() const
00420 throw()
00421 {
00422 if(system != Cartesian)
00423 return theArray[1];
00424 Position t(*this);
00425 t.transformTo(Spherical);
00426 return t.theArray[1];
00427 }
00428
00429
00430
00431 double Position::radius() const
00432 throw()
00433 {
00434 if(system == Spherical || system == Geocentric)
00435 return theArray[2];
00436 Position t(*this);
00437 t.transformTo(Spherical);
00438 return t.theArray[2];
00439 }
00440
00441
00442 double Position::height() const
00443 throw()
00444 {
00445 if(system == Geodetic)
00446 return theArray[2];
00447 Position t(*this);
00448 t.transformTo(Geodetic);
00449 return t.theArray[2];
00450 }
00451
00452
00453
00454
00455
00456
00457 void Position::setGeoidModel(const GeoidModel *geoid)
00458 throw(GeometryException)
00459 {
00460 if(!geoid)
00461 {
00462 GeometryException ge("Given GeoidModel pointer is NULL.");
00463 GPSTK_THROW(ge);
00464 }
00465 AEarth = geoid->a();
00466 eccSquared = geoid->eccSquared();
00467 }
00468
00469
00470
00471
00472
00473
00474
00475 Position& Position::setGeodetic(const double lat,
00476 const double lon,
00477 const double ht,
00478 const GeoidModel *geoid)
00479 throw(GeometryException)
00480 {
00481 if(lat > 90 || lat < -90)
00482 {
00483 GeometryException ge("Invalid latitude in setGeodetic: "
00484 + StringUtils::asString(lat));
00485 GPSTK_THROW(ge);
00486 }
00487 theArray[0] = lat;
00488
00489 theArray[1] = lon;
00490 if(theArray[1] < 0)
00491 theArray[1] += 360*(1+(unsigned long)(theArray[1]/360));
00492 else if(theArray[1] >= 360)
00493 theArray[1] -= 360*(unsigned long)(theArray[1]/360);
00494
00495 theArray[2] = ht;
00496
00497 if(geoid) {
00498 AEarth = geoid->a();
00499 eccSquared = geoid->eccSquared();
00500 }
00501 system = Geodetic;
00502
00503 return *this;
00504 }
00505
00506
00507
00508
00509
00510
00511
00512 Position& Position::setGeocentric(const double lat,
00513 const double lon,
00514 const double rad)
00515 throw(GeometryException)
00516 {
00517 if(lat > 90 || lat < -90)
00518 {
00519 GeometryException ge("Invalid latitude in setGeocentric: "
00520 + StringUtils::asString(lat));
00521 GPSTK_THROW(ge);
00522 }
00523 if(rad < 0)
00524 {
00525 GeometryException ge("Invalid radius in setGeocentric: "
00526 + StringUtils::asString(rad));
00527 GPSTK_THROW(ge);
00528 }
00529 theArray[0] = lat;
00530 theArray[1] = lon;
00531 theArray[2] = rad;
00532
00533 if(theArray[1] < 0)
00534 theArray[1] += 360*(1+(unsigned long)(theArray[1]/360));
00535 else if(theArray[1] >= 360)
00536 theArray[1] -= 360*(unsigned long)(theArray[1]/360);
00537 system = Geocentric;
00538
00539 return *this;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548 Position& Position::setSpherical(const double theta,
00549 const double phi,
00550 const double rad)
00551 throw(GeometryException)
00552 {
00553 if(theta < 0 || theta > 180)
00554 {
00555 GeometryException ge("Invalid theta in setSpherical: "
00556 + StringUtils::asString(theta));
00557 GPSTK_THROW(ge);
00558 }
00559 if(rad < 0)
00560 {
00561 GeometryException ge("Invalid radius in setSpherical: "
00562 + StringUtils::asString(rad));
00563 GPSTK_THROW(ge);
00564 }
00565
00566 theArray[0] = theta;
00567 theArray[1] = phi;
00568 theArray[2] = rad;
00569
00570 if(theArray[1] < 0)
00571 theArray[1] += 360*(1+(unsigned long)(theArray[1]/360));
00572 else if(theArray[1] >= 360)
00573 theArray[1] -= 360*(unsigned long)(theArray[1]/360);
00574 system = Spherical;
00575
00576 return *this;
00577 }
00578
00579
00580
00581
00582
00583
00584 Position& Position::setECEF(const double X,
00585 const double Y,
00586 const double Z)
00587 throw()
00588 {
00589 theArray[0] = X;
00590 theArray[1] = Y;
00591 theArray[2] = Z;
00592 system = Cartesian;
00593 return *this;
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 Position& Position::setToString(const std::string& str,
00643 const std::string& fmt)
00644 throw(GeometryException,
00645 DayTime::FormatException,
00646 StringUtils::StringException)
00647 {
00648 try {
00649
00650
00651 Position toReturn;
00652
00653
00654 bool hX=false, hY=false, hZ=false;
00655 bool hglat=false, hlon=false, hht=false;
00656 bool hclat=false, hrad=false;
00657 bool htheta=false, hphi=false;
00658
00659 double x,y,z,glat,lon,ht,clat,rad,theta,phi;
00660
00661 string f = fmt;
00662 string s = str;
00663 stripLeading(s);
00664 stripTrailing(s);
00665
00666
00667
00668 while ( (s.size() > 0) && (f.size() > 0) )
00669 {
00670
00671
00672
00673 while ( (s.length() != 0) && (f.length() != 0) && (f[0] != '%') )
00674 {
00675
00676 s.erase(0,1);
00677 f.erase(0,1);
00678 stripLeading(s);
00679 stripLeading(f);
00680 }
00681
00682
00683 if ( (s.length() == 0) || (f.length() == 0) )
00684 break;
00685
00686
00687 f.erase(0,1);
00688
00689
00690
00691 string::size_type fieldLength = string::npos;
00692
00693 if (!isalpha(f[0]))
00694 {
00695 fieldLength = asInt(f);
00696
00697
00698
00699 while ((!f.empty()) && (!isalpha(f[0])))
00700 f.erase(0,1);
00701 if (f.empty())
00702 break;
00703 }
00704
00705
00706 char delimiter = 0;
00707 if (f.size() > 1)
00708 {
00709 if (f[1] != '%')
00710 {
00711 delimiter = f[1];
00712
00713 if (fieldLength == string::npos)
00714 fieldLength = s.find(delimiter,0);
00715 }
00716
00717
00718
00719 else if (fieldLength == string::npos)
00720 {
00721 fieldLength = 1;
00722 }
00723 }
00724
00725
00726
00727 string toBeRemoved = s.substr(0, fieldLength);
00728
00729
00730 switch (f[0])
00731 {
00732
00733
00734
00735
00736
00737
00738 case 'X':
00739 x = asDouble(toBeRemoved) * 1000;
00740 hX = true;
00741 break;
00742 case 'x':
00743 x = asDouble(toBeRemoved);
00744 hX = true;
00745 break;
00746 case 'Y':
00747 y = asDouble(toBeRemoved) * 1000;
00748 hY = true;
00749 break;
00750 case 'y':
00751 y = asDouble(toBeRemoved);
00752 hY = true;
00753 break;
00754 case 'Z':
00755 z = asDouble(toBeRemoved) * 1000;
00756 hZ = true;
00757 break;
00758 case 'z':
00759 z = asDouble(toBeRemoved);
00760 hZ = true;
00761 break;
00762
00763
00764 case 'A':
00765 glat = asDouble(toBeRemoved);
00766 if(glat > 90. || glat < -90.) {
00767 DayTime::FormatException f(
00768 "Invalid geodetic latitude for setTostring: "
00769 + toBeRemoved);
00770 GPSTK_THROW(f);
00771 }
00772 hglat = true;
00773 break;
00774 case 'a':
00775 clat = asDouble(toBeRemoved);
00776 if(clat > 90. || clat < -90.) {
00777 DayTime::FormatException f(
00778 "Invalid geocentric latitude for setTostring: "
00779 + toBeRemoved);
00780 GPSTK_THROW(f);
00781 }
00782 hclat = true;
00783 break;
00784
00785
00786
00787
00788 case 'L':
00789 case 'l':
00790 lon = asDouble(toBeRemoved);
00791 if(lon < 0)
00792 lon += 360*(1+(unsigned long)(lon/360));
00793 else if(lon >= 360)
00794 lon -= 360*(unsigned long)(lon/360);
00795 hlon = true;
00796 break;
00797 case 'w':
00798 case 'W':
00799 lon = 360.0 - asDouble(toBeRemoved);
00800 if(lon < 0)
00801 lon += 360*(1+(unsigned long)(lon/360));
00802 else if(lon >= 360)
00803 lon -= 360*(unsigned long)(lon/360);
00804 hlon = true;
00805 break;
00806
00807
00808 case 't':
00809 theta = asDouble(toBeRemoved);
00810 if(theta > 180. || theta < 0.) {
00811 DayTime::FormatException f("Invalid theta for setTostring: "
00812 + toBeRemoved);
00813 GPSTK_THROW(f);
00814 }
00815 htheta = true;
00816 break;
00817 case 'T':
00818 theta = asDouble(toBeRemoved) * RAD_TO_DEG;
00819 if(theta > 90. || theta < -90.) {
00820 DayTime::FormatException f("Invalid theta for setTostring: "
00821 + toBeRemoved);
00822 GPSTK_THROW(f);
00823 }
00824 htheta = true;
00825 break;
00826
00827
00828 case 'p':
00829 phi = asDouble(toBeRemoved);
00830 if(phi < 0)
00831 phi += 360*(1+(unsigned long)(phi/360));
00832 else if(phi >= 360)
00833 phi -= 360*(unsigned long)(phi/360);
00834 hphi = true;
00835 break;
00836 case 'P':
00837 phi = asDouble(toBeRemoved) * RAD_TO_DEG;
00838 if(phi < 0)
00839 phi += 360*(1+(unsigned long)(phi/360));
00840 else if(phi >= 360)
00841 phi -= 360*(unsigned long)(phi/360);
00842 hphi = true;
00843 break;
00844
00845
00846
00847
00848 case 'r':
00849 rad = asDouble(toBeRemoved);
00850 if(rad < 0.0) {
00851 DayTime::FormatException f("Invalid radius for setTostring: "
00852 + toBeRemoved);
00853 GPSTK_THROW(f);
00854 }
00855 hrad = true;
00856 break;
00857 case 'R':
00858 rad = asDouble(toBeRemoved) * 1000;
00859 if(rad < 0.0) {
00860 DayTime::FormatException f("Invalid radius for setTostring: "
00861 + toBeRemoved);
00862 GPSTK_THROW(f);
00863 }
00864 hrad = true;
00865 break;
00866 case 'h':
00867 ht = asDouble(toBeRemoved);
00868 hht = true;
00869 break;
00870 case 'H':
00871 ht = asDouble(toBeRemoved) * 1000;
00872 hht = true;
00873 break;
00874 default:
00875 break;
00876 }
00877
00878 stripLeading(s,toBeRemoved,1);
00879
00880
00881 f.erase(0,1);
00882
00883
00884 stripLeading(f);
00885 stripLeading(s);
00886
00887 }
00888
00889 if ( s.length() != 0 )
00890 {
00891
00892 DayTime::FormatException fe(
00893 "Processing error - parts of strings left unread - " + s);
00894 GPSTK_THROW(fe);
00895 }
00896
00897 if (f.length() != 0)
00898 {
00899
00900 DayTime::FormatException fe(
00901 "Processing error - parts of strings left unread - " + f);
00902 GPSTK_THROW(fe);
00903 }
00904
00905
00906 if ( !(hX && hY && hZ) && !(hglat && hlon && hht) &&
00907 !(hclat && hlon && hrad) && !(htheta && hphi && hrad)) {
00908 DayTime::FormatException fe("Incomplete specification for setToString");
00909 GPSTK_THROW(fe);
00910 }
00911
00912
00913 if(hX && hY && hZ)
00914 toReturn.setECEF(x,y,z);
00915 else if(hglat && hlon && hht)
00916 toReturn.setGeodetic(glat,lon,ht);
00917 else if(hclat && hlon && hrad)
00918 toReturn.setGeocentric(clat,lon,rad);
00919 else if(htheta && hphi && hrad)
00920 toReturn.setSpherical(theta,phi,rad);
00921
00922 *this = toReturn;
00923 return *this;
00924 }
00925 catch(gpstk::Exception& exc)
00926 {
00927 GeometryException ge(exc);
00928 ge.addText("Failed to convert string to Position");
00929 GPSTK_THROW(ge);
00930 }
00931 catch(std::exception& exc)
00932 {
00933 GeometryException ge(exc.what());
00934 ge.addText("Failed to convert string to Position");
00935 GPSTK_THROW(ge);
00936 }
00937 }
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968 std::string Position::printf(const char *fmt) const
00969 throw(StringUtils::StringException)
00970 {
00971 string rv = fmt;
00972 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?x"),
00973 string("xf"), X());
00974 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?y"),
00975 string("yf"), Y());
00976 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?z"),
00977 string("zf"), Z());
00978 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?X"),
00979 string("Xf"), X()/1000);
00980 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?Y"),
00981 string("Yf"), Y()/1000);
00982 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?Z"),
00983 string("Zf"), Z()/1000);
00984
00985 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?A"),
00986 string("Af"), geodeticLatitude());
00987 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?a"),
00988 string("af"), geocentricLatitude());
00989 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?L"),
00990 string("Lf"), longitude());
00991 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?l"),
00992 string("lf"), longitude());
00993 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?w"),
00994 string("wf"), 360-longitude());
00995 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?W"),
00996 string("Wf"), 360-longitude());
00997
00998 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?t"),
00999 string("tf"), theta());
01000 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?T"),
01001 string("Tf"), theta()*DEG_TO_RAD);
01002 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?p"),
01003 string("pf"), phi());
01004 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?P"),
01005 string("Pf"), phi()*DEG_TO_RAD);
01006 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?r"),
01007 string("rf"), radius());
01008 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?R"),
01009 string("Rf"), radius()/1000);
01010 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?h"),
01011 string("hf"), height());
01012 rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?H"),
01013 string("Hf"), height()/1000);
01014 return rv;
01015 }
01016
01017
01018 string Position::asString() const
01019 throw(StringUtils::StringException)
01020 {
01021 ostringstream o;
01022 o << *this;
01023 return o.str();
01024 }
01025
01026
01027
01028
01029
01030
01031
01032 void Position::convertSphericalToCartesian(const Triple& tpr,
01033 Triple& xyz)
01034 throw()
01035 {
01036 double st=::sin(tpr[0]*DEG_TO_RAD);
01037 xyz[0] = tpr[2]*st*::cos(tpr[1]*DEG_TO_RAD);
01038 xyz[1] = tpr[2]*st*::sin(tpr[1]*DEG_TO_RAD);
01039 xyz[2] = tpr[2]*::cos(tpr[0]*DEG_TO_RAD);
01040 }
01041
01042
01043
01044
01045
01046 void Position::convertCartesianToSpherical(const Triple& xyz,
01047 Triple& tpr)
01048 throw()
01049 {
01050 tpr[2] = RSS(xyz[0],xyz[1],xyz[2]);
01051 if(tpr[2] <= Position::POSITION_TOLERANCE/5) {
01052 tpr[0] = 90;
01053 tpr[1] = 0;
01054 return;
01055 }
01056 tpr[0] = ::acos(xyz[2]/tpr[2]);
01057 tpr[0] *= RAD_TO_DEG;
01058 if(RSS(xyz[0],xyz[1]) < Position::POSITION_TOLERANCE/5) {
01059 tpr[1] = 0;
01060 return;
01061 }
01062 tpr[1] = ::atan2(xyz[1],xyz[0]);
01063 tpr[1] *= RAD_TO_DEG;
01064 if(tpr[1] < 0) tpr[1] += 360;
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 void Position::convertCartesianToGeodetic(const Triple& xyz,
01076 Triple& llh,
01077 const double A,
01078 const double eccSq)
01079 throw()
01080 {
01081 double p,slat,N,htold,latold;
01082 p = SQRT(xyz[0]*xyz[0]+xyz[1]*xyz[1]);
01083 if(p < Position::POSITION_TOLERANCE/5) {
01084 llh[0] = (xyz[2] > 0 ? 90.0: -90.0);
01085 llh[1] = 0;
01086 llh[2] = ::fabs(xyz[2]) - A*SQRT(1.0-eccSq);
01087 return;
01088 }
01089 llh[0] = ::atan2(xyz[2], p*(1.0-eccSq));
01090 llh[2] = 0;
01091 for(int i=0; i<5; i++) {
01092 slat = ::sin(llh[0]);
01093 N = A / SQRT(1.0 - eccSq*slat*slat);
01094 htold = llh[2];
01095 llh[2] = p/::cos(llh[0]) - N;
01096 latold = llh[0];
01097 llh[0] = ::atan2(xyz[2], p*(1.0-eccSq*(N/(N+llh[2]))));
01098 if(::fabs(llh[0]-latold) < 1.0e-9 && fabs(llh[2]-htold) < 1.0e-9 * A) break;
01099 }
01100 llh[1] = ::atan2(xyz[1],xyz[0]);
01101 if(llh[1] < 0.0) llh[1] += TWO_PI;
01102 llh[0] *= RAD_TO_DEG;
01103 llh[1] *= RAD_TO_DEG;
01104 }
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 void Position::convertGeodeticToCartesian(const Triple& llh,
01115 Triple& xyz,
01116 const double A,
01117 const double eccSq)
01118 throw()
01119 {
01120 double slat = ::sin(llh[0]*DEG_TO_RAD);
01121 double clat = ::cos(llh[0]*DEG_TO_RAD);
01122 double N = A/SQRT(1.0-eccSq*slat*slat);
01123 xyz[0] = (N+llh[2])*clat*::cos(llh[1]*DEG_TO_RAD);
01124 xyz[1] = (N+llh[2])*clat*::sin(llh[1]*DEG_TO_RAD);
01125 xyz[2] = (N*(1.0-eccSq)+llh[2])*slat;
01126 }
01127
01128
01129
01130
01131
01132 void Position::convertCartesianToGeocentric(const Triple& xyz,
01133 Triple& llr)
01134 throw()
01135 {
01136 convertCartesianToSpherical(xyz, llr);
01137 llr[0] = 90 - llr[0];
01138 }
01139
01140
01141
01142
01143 void Position::convertGeocentricToCartesian(const Triple& llr,
01144 Triple& xyz)
01145 throw()
01146 {
01147 Triple llh(llr);
01148 llh[0] = 90 - llh[0];
01149 convertSphericalToCartesian(llh, xyz);
01150 }
01151
01152
01153
01154
01155
01156
01157
01158 void Position::convertGeocentricToGeodetic(const Triple& llr,
01159 Triple& llh,
01160 const double A,
01161 const double eccSq)
01162 throw()
01163 {
01164 double cl,p,sl,slat,N,htold,latold;
01165 llh[1] = llr[1];
01166 cl = ::sin((90-llr[0])*DEG_TO_RAD);
01167 sl = ::cos((90-llr[0])*DEG_TO_RAD);
01168 if(llr[2] <= Position::POSITION_TOLERANCE/5) {
01169
01170
01171 llh[0] = llh[1] = 0;
01172 llh[2] = -A;
01173 return;
01174 }
01175 else if(cl < 1.e-10) {
01176
01177 if(llr[0] < 0) llh[0] = -90;
01178 else llh[0] = 90;
01179 llh[1] = 0;
01180 llh[2] = llr[2] - A*SQRT(1-eccSq);
01181 return;
01182 }
01183 llh[0] = ::atan2(sl, cl*(1.0-eccSq));
01184 p = cl*llr[2];
01185 llh[2] = 0;
01186 for(int i=0; i<5; i++) {
01187 slat = ::sin(llh[0]);
01188 N = A / SQRT(1.0 - eccSq*slat*slat);
01189 htold = llh[2];
01190 llh[2] = p/::cos(llh[0]) - N;
01191 latold = llh[0];
01192 llh[0] = ::atan2(sl, cl*(1.0-eccSq*(N/(N+llh[2]))));
01193 if(fabs(llh[0]-latold) < 1.0e-9 && ::fabs(llh[2]-htold) < 1.0e-9 * A) break;
01194 }
01195 llh[0] *= RAD_TO_DEG;
01196 }
01197
01198
01199
01200
01201
01202
01203
01204 void Position::convertGeodeticToGeocentric(const Triple& llh,
01205 Triple& llr,
01206 const double A,
01207 const double eccSq)
01208 throw()
01209 {
01210 double slat = ::sin(llh[0]*DEG_TO_RAD);
01211 double N = A/SQRT(1.0-eccSq*slat*slat);
01212
01213 llr[1] = llh[1];
01214
01215 llr[2] = SQRT((N+llh[2])*(N+llh[2]) + N*eccSq*(N*eccSq-2*(N+llh[2]))*slat*slat);
01216 if(llr[2] <= Position::POSITION_TOLERANCE/5) {
01217
01218
01219 llr[0] = llr[1] = llr[2] = 0;
01220 return;
01221 }
01222 if(1-::fabs(slat) < 1.e-10) {
01223 if(slat < 0) llr[0] = -90;
01224 else llr[0] = 90;
01225 llr[1] = 0.0;
01226 return;
01227 }
01228
01229 llr[0] = ::acos((N*(1-eccSq)+llh[2])*slat/llr[2]);
01230 llr[0] *= RAD_TO_DEG;
01231 llr[0] = 90 - llr[0];
01232 }
01233
01234
01235
01236
01237
01238
01239
01240 ostream& operator<<(ostream& s, const Position& p)
01241 {
01242 if(p.system == Position::Cartesian)
01243 s << p.printf("%.4x m %.4y m %.4z m");
01244 else if(p.system == Position::Geodetic)
01245 s << p.printf("%.8A degN %.8L degE %.4h m");
01246 else if(p.system == Position::Geocentric)
01247 s << p.printf("%.8a degN %.8L degE %.4r m");
01248 else if(p.system == Position::Spherical)
01249 s << p.printf("%.8t deg %.8p deg %.4r m");
01250 else
01251 s << " Unknown system! : " << p[0] << " " << p[1] << " " << p[2];
01252
01253 return s;
01254 }
01255
01256
01257
01258
01259
01260
01261 double range(const Position& A,
01262 const Position& B)
01263 throw(GeometryException)
01264 {
01265 if(A.AEarth != B.AEarth || A.eccSquared != B.eccSquared)
01266 {
01267 GeometryException ge("Unequal geoids");
01268 GPSTK_THROW(ge);
01269 }
01270
01271 Position L(A),R(B);
01272 L.transformTo(Position::Cartesian);
01273 R.transformTo(Position::Cartesian);
01274 double dif = RSS(L.X()-R.X(),L.Y()-R.Y(),L.Z()-R.Z());
01275 return dif;
01276 }
01277
01278
01279
01280
01281 double Position::radiusEarth(const double geolat,
01282 const double A,
01283 const double eccSq)
01284 throw()
01285 {
01286 double slat=::sin(DEG_TO_RAD*geolat);
01287 double e=(1.0-eccSq);
01288 double f=(1.0+(e*e-1.0)*slat*slat)/(1.0-eccSq*slat*slat);
01289 return (A * SQRT(f));
01290 }
01291
01292
01293
01294
01295
01296
01297 double Position::elevation(const Position& Target) const
01298 throw(GeometryException)
01299 {
01300 Position R(*this),S(Target);
01301 R.transformTo(Cartesian);
01302 S.transformTo(Cartesian);
01303
01304 double elevation;
01305 try {
01306 elevation = R.elvAngle(S);
01307 }
01308 catch(GeometryException& ge)
01309 {
01310 GPSTK_RETHROW(ge);
01311 }
01312 return elevation;
01313 }
01314
01315
01316
01317
01318
01319
01320
01321 double Position::elevationGeodetic(const Position& Target) const
01322 throw(GeometryException)
01323 {
01324 Position R(*this),S(Target);
01325 double latGeodetic = R.getGeodeticLatitude()*DEG_TO_RAD;
01326 double longGeodetic = R.getLongitude()*DEG_TO_RAD;
01327 double localUp;
01328 double cosUp;
01329 R.transformTo(Cartesian);
01330 S.transformTo(Cartesian);
01331 Triple z;
01332
01333 z = S.theArray - R.theArray;
01334
01335 if (z.mag()<=1e-4)
01336 {
01337 GeometryException ge("Positions are within .1 millimeter");
01338 GPSTK_THROW(ge);
01339 }
01340
01341
01342 Triple kVector(::cos(latGeodetic)*::cos(longGeodetic), ::cos(latGeodetic)*::sin(longGeodetic), ::sin(latGeodetic));
01343
01344 localUp = z.dot(kVector);
01345
01346 cosUp = localUp/z.mag();
01347
01348 return 90.0 - ((::acos(cosUp))*RAD_TO_DEG);
01349 }
01350
01351
01352
01353
01354
01355
01356 double Position::azimuth(const Position& Target) const
01357 throw(GeometryException)
01358 {
01359 Position R(*this),S(Target);
01360 R.transformTo(Cartesian);
01361 S.transformTo(Cartesian);
01362
01363 double az;
01364 try
01365 {
01366 az = R.azAngle(S);
01367
01368 }
01369 catch(GeometryException& ge)
01370 {
01371 GPSTK_RETHROW(ge);
01372 }
01373
01374 return az;
01375 }
01376
01377
01378
01379
01380
01381
01382
01383 double Position::azimuthGeodetic(const Position& Target) const
01384 throw(GeometryException)
01385 {
01386 Position R(*this),S(Target);
01387 double latGeodetic = R.getGeodeticLatitude()*DEG_TO_RAD;
01388 double longGeodetic = R.getLongitude()*DEG_TO_RAD;
01389 double localN, localE;
01390 R.transformTo(Cartesian);
01391 S.transformTo(Cartesian);
01392 Triple z;
01393
01394 z = S.theArray - R.theArray;
01395
01396 if (z.mag()<=1e-4)
01397 {
01398 GeometryException ge("Positions are within .1 millimeter");
01399 GPSTK_THROW(ge);
01400 }
01401
01402
01403 Triple iVector(-::sin(latGeodetic)*::cos(longGeodetic), -::sin(latGeodetic)*::sin(longGeodetic), ::cos(latGeodetic));
01404
01405 Triple jVector(-::sin(longGeodetic), ::cos(longGeodetic), 0);
01406
01407
01408 localN = (z.dot(iVector))/z.mag();
01409 localE = (z.dot(jVector))/z.mag();
01410
01411
01412 double test = fabs(localN) + fabs(localE);
01413
01414
01415 if (test < 1.0e-16) return 0.0;
01416
01417 double alpha = ((::atan2(localE, localN)) * RAD_TO_DEG);
01418 if (alpha < 0.0)
01419 {
01420 return alpha + 360.0;
01421 }
01422 else
01423 {
01424 return alpha;
01425 }
01426 }
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443 Position Position::getIonosphericPiercePoint(const double elev,
01444 const double azim,
01445 const double ionoht) const
01446 throw()
01447 {
01448 Position Rx(*this);
01449
01450
01451 Rx.transformTo(Geocentric);
01452
01453
01454 Position IPP(Rx);
01455 double el = elev * DEG_TO_RAD;
01456
01457 double p = PI/2.0 - el - ::asin(AEarth*::cos(el)/(AEarth+ionoht));
01458 double lat = Rx.theArray[0] * DEG_TO_RAD;
01459 double az = azim * DEG_TO_RAD;
01460 IPP.theArray[0] = std::asin(std::sin(lat)*std::cos(p) + std::cos(lat)*std::sin(p)*std::cos(az));
01461 IPP.theArray[1] = Rx.theArray[1]*DEG_TO_RAD
01462 + ::asin(::sin(p)*::sin(az)/::cos(IPP.theArray[0]));
01463
01464 IPP.theArray[0] *= RAD_TO_DEG;
01465 IPP.theArray[1] *= RAD_TO_DEG;
01466 IPP.theArray[2] = AEarth + ionoht;
01467
01468
01469 IPP.transformTo(system);
01470
01471 return IPP;
01472 }
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483 void Position::initialize(const double a,
01484 const double b,
01485 const double c,
01486 Position::CoordinateSystem s,
01487 GeoidModel *geoid)
01488 throw(GeometryException)
01489 {
01490 double bb(b);
01491 if(s == Geodetic || s==Geocentric)
01492 {
01493 if(a > 90 || a < -90)
01494 {
01495 GeometryException ge("Invalid latitude in constructor: "
01496 + StringUtils::asString(a));
01497 GPSTK_THROW(ge);
01498 }
01499 if(bb < 0)
01500 bb += 360*(1+(unsigned long)(bb/360));
01501 else if(bb >= 360)
01502 bb -= 360*(unsigned long)(bb/360);
01503 }
01504 if(s==Geocentric || s==Spherical)
01505 {
01506 if(c < 0)
01507 {
01508 GeometryException ge("Invalid radius in constructor: "
01509 + StringUtils::asString(c));
01510 GPSTK_THROW(ge);
01511 }
01512 }
01513 if(s==Spherical)
01514 {
01515 if(a < 0 || a > 180)
01516 {
01517 GeometryException ge("Invalid theta in constructor: "
01518 + StringUtils::asString(a));
01519 GPSTK_THROW(ge);
01520 }
01521 if(bb < 0)
01522 bb += 360*(1+(unsigned long)(bb/360));
01523 else if(bb >= 360)
01524 bb -= 360*(unsigned long)(bb/360);
01525 }
01526
01527 theArray[0] = a;
01528 theArray[1] = bb;
01529 theArray[2] = c;
01530
01531 if(geoid) {
01532 AEarth = geoid->a();
01533 eccSquared = geoid->eccSquared();
01534 }
01535 else {
01536 WGS84Geoid WGS84;
01537 AEarth = WGS84.a();
01538 eccSquared = WGS84.eccSquared();
01539 }
01540 system = s;
01541 tolerance = POSITION_TOLERANCE;
01542 }
01543
01544 }